Files
MIT6.824/lecture-06-raft1/6.4-raft-tong-bu-shi-xu.md
2022-01-25 02:41:31 +00:00

46 lines
4.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 6.4 Log 同步时序
这一部分我们从另一个角度来看Raft Log同步的一些交互这种角度将会在这门课中出现很多次那就是时序图。
接下来我将画一个时序图来描述Raft内部的消息是如何工作的。假设我们有一个客户端服务器1是当前Raft集群的Leader。同时我们还有服务器2服务器3。这张图的纵坐标是时间越往下时间越长。假设客户端将请求发送给服务器1这里的客户端请求就是一个简单的请求例如一个Put请求。
![](<../.gitbook/assets/image (19).png>)
之后服务器1的Raft层会发送一个添加日志AppendEntries的RPC到其他两个副本S2S3。现在服务器1会一直等待其他副本节点的响应一直等到过半节点的响应返回。这里的过半节点包括Leader自己。所以在一个只有3个副本节点的系统中Leader只需要等待一个其他副本节点。
![](<../.gitbook/assets/image (18).png>)
一旦过半的节点返回了响应这里的过半节点包括了Leader自己所以在一个只有3个副本的系统中Leader只需要等待一个其他副本节点返回对于AppendEntries的正确响应。
![](<../.gitbook/assets/image (17).png>)
当Leader收到了过半服务器的正确响应Leader会执行来自客户端的请求得到结果并将结果返回给客户端。
![](<../.gitbook/assets/image (16).png>)
与此同时服务器3可能也会将它的响应返回给Leader尽管这个响应是有用的但是这里不需要等待这个响应。这一点对于理解Raft论文中的图2是有用的。
![](<../.gitbook/assets/image (15).png>)
好了,大家明白了吗?这是系统在没有故障情况下,处理普通操作的流程。
> 学生提问S2和S3的状态怎么保持与S1同步
>
> Robert教授我的天我忘了一些重要的步骤。现在Leader知道过半服务器已经添加了Log可以执行客户端请求并返回给客户端。但是服务器2还不知道这一点服务器2只知道我从Leader那收到了这个请求但是我不知道这个请求是不是已经被Leader提交committed这取决于我的响应是否被Leader收到。服务器2只知道它的响应提交给了网络或许Leader没有收到这个响应也就不会决定commit这个请求。所以这里还有一个阶段。一旦Leader发现请求被commit之后它需要将这个消息通知给其他的副本。所以这里有一个额外的消息。
![](<../.gitbook/assets/image (20).png>)
这条消息的具体内容依赖于整个系统的状态。至少在Raft中没有明确的committed消息。相应的committed消息被夹带在下一个AppendEntries消息中由Leader下一次的AppendEntries对应的RPC发出。任何情况下当有了committed消息时这条消息会填在AppendEntries的RPC中。下一次Leader需要发送心跳或者是收到了一个新的客户端请求要将这个请求同步给其他副本时Leader会将新的更大的commit号随着AppendEntries消息发出当其他副本收到了这个消息就知道之前的commit号已经被Leader提交其他副本接下来也会执行相应的请求更新本地的状态。
![](<../.gitbook/assets/image (21).png>)
> 学生提问:这里的内部交互有点多吧?
>
> Robert教授是的这是一个内部需要一些交互的协议它不是特别的快。实际上客户端发出请求请求到达某个服务器这个服务器至少需要与一个其他副本交互在返回给客户端之前需要等待多条消息。所以一个客户端响应的背后有多条消息的交互。
>
> 学生提问也就是说commit信息是随着普通的AppendEntries消息发出的那其他副本的状态更新就不是很及时了。
>
> Robert教授是的作为实现者这取决于你在什么时候将新的commit号发出。如果客户端请求很稀疏那么Leader或许要发送一个心跳或者发送一条特殊的AppendEntries消息。如果客户端请求很频繁那就无所谓了。因为如果每秒有1000个请求那么下一条AppendEntries很快就会发出你可以在下一条消息中带上新的commit号而不用生成一条额外的消息。额外的消息代价还是有点高的反正你要发送别的消息可以把新的commit号带在别的消息里。
>
> 实际上我不认为其他副本非Leader执行客户端请求的时间很重要因为没有人在等这个步骤。至少在不出错的时候其他副本执行请求是个不太重要的步骤。例如说客户端就没有等待其他副本执行请求客户端只会等待Leader执行请求。所以其他副本在什么时候执行请求不会影响客户端感受的请求时延。