豆瓣
扫码直接下载
我是本书作者。因为在Github收到读者询问是否有书籍相关讨论群,所以试着用了一下豆瓣的讨论功能。如果你有对书籍或者代码的疑问,你可以在这里发表话题,我会定期检查和回复,谢谢。
作者您好,我看到第二章,matchIndex 的作用是什么,我没搞清楚,还请指教
2.6.2 章节
matchIndex是Raft算法里的一个概念:两个节点在哪个index是匹配的。知道这个matchIndex之后leader可以决定发送哪些日志,比如说从matchIndex + 1开始的日志。另外,matchIndex在选举之后会被重置,新的leader需要探测其他follower和自己之间的matchIndex。
作者好.kvstore get 操作 是不是从日志的最后往前搜索?我看源码 是从内存的map直接get真实应该从commitindex 往前搜索, 直到找到对应的key, 且取过半follower返回的数据中, 最新的term的数据?作者能否把这个逻辑实现到 源码里啊?`public void get(CommandRequest commandRequest) { String key = commandRequest.getCommand().getKey(); logger.debug("get {}", key); byte[] value = this.map.get(key); // TODO view from node state machine commandRequest.reply(new GetCommandResponse(value));}
从后往前搜索日志的话,效率会非常慢,基本做不了复杂的系统。Raft算法中有一个applyIndex,只要按照设计应用日志的话,现在服务的状态就是Raft状态机的状态。
谢谢作者的解答.有个疑问, Raft状态机的状态是保存在内存吗?如果是的话, 对内存的压力是不是很大?
另外请教作者一个问题:收到投票请求时, 还要比较最新日志的term是为了防止 网络分区, 导致小分区的节点term很大, 但是日志不是最新的问题吗?if (rpc.getTerm() > role.getTerm()) { boolean voteForCandidate = !context.log().isNewerThan(rpc.getLastLogIndex(), rpc.getLastLogTerm());
第三个问题:成员变更规则第八条, 发起选举时, 不判断自己是否在成员列表里.是为什么? 如果判断, 会有什么问题呢?
PreVote属于优化部分,在develop分支有实现。
Raft的状态机是基于日志的,而日志基本上都需要持久化,所以理论上状态机不基于内存。书里面为了调试方便设计了一个基于内存的日志实现,但是不代表Raft的状态及基于内存。
你好, 每次系统启动时, 为了获得最新的服务状态, 需要服务去重放日志, 以获得最新的状态吗?
理论上是的。不过Raft有日志快照,所以实际上Raft不一定是从第一条日志开始重放的。你可以参考数据库的快照和WAL。
抱歉,不是很确定你的这个问题是问Raft为什么要比较term,还是为什么还要用日志中的term比较。我只能模糊地回答一下。Raft算法中每次选举都会产生一个新的term,这和Paxos算法是一样的。Raft所有操作都会基于这个term。Raft实现在收到请求之后基本都会先比较一下term,如果对方term比较小,直接返回错误。其次Raft是基于日志比较的算法,日志里的term可能和系统现在的term不一致,比如说发起选举的时候,所以日志比较必须用日志而不是系统自身的term。
简单的回答的话,Raft算法的要求。比如一个极端情况,两个节点组成的集群。把leader节点移除时,leader在没有把新集群配置传给另外一个节点时宕机了,剩下的一个节点因为收不到选票永远没办法成为leader。此时让旧leader重启,重新成为leader,让移除继续。这种情况下旧leader并不在集群列表中,所以结论是发起选举时不用判断。
作者你好,源码中在 AbstractHandler 中保存了 lastAppendEntriesRpc ,这样实现感觉会有问题?源码中每次调用 write 就会保存 lastAppendEntriesRpc,然后在 channelRead 的时候去判断这个对象是否存在。但是每次调用 write 的时候是保存在 ToRemoteHandler 这个对象中,而 channelRead 的时候是在 FromRemoteHandler 这个对象中,所以在 channelRead 获取的时候就会获取不到这个 lastAppendEntriesRpc。
> 去分布式一致性算法开发实战的论坛
作者您好,我看到第二章,matchIndex 的作用是什么,我没搞清楚,还请指教
2.6.2 章节
matchIndex是Raft算法里的一个概念:两个节点在哪个index是匹配的。知道这个matchIndex之后leader可以决定发送哪些日志,比如说从matchIndex + 1开始的日志。另外,matchIndex在选举之后会被重置,新的leader需要探测其他follower和自己之间的matchIndex。
作者好.
kvstore get 操作 是不是从日志的最后往前搜索?
我看源码 是从内存的map直接get
真实应该从commitindex 往前搜索, 直到找到对应的key, 且取过半follower返回的数据中, 最新的term的数据?
作者能否把这个逻辑实现到 源码里啊?
`
public void get(CommandRequest commandRequest) {
String key = commandRequest.getCommand().getKey();
logger.debug("get {}", key);
byte[] value = this.map.get(key);
// TODO view from node state machine
commandRequest.reply(new GetCommandResponse(value));
}
从后往前搜索日志的话,效率会非常慢,基本做不了复杂的系统。Raft算法中有一个applyIndex,只要按照设计应用日志的话,现在服务的状态就是Raft状态机的状态。
谢谢作者的解答.
有个疑问, Raft状态机的状态是保存在内存吗?
如果是的话, 对内存的压力是不是很大?
另外请教作者一个问题:
收到投票请求时, 还要比较最新日志的term是为了防止 网络分区, 导致小分区的节点term很大, 但是日志不是最新的问题吗?
if (rpc.getTerm() > role.getTerm()) {
boolean voteForCandidate = !context.log().isNewerThan(rpc.getLastLogIndex(), rpc.getLastLogTerm());
第三个问题:
成员变更规则
第八条, 发起选举时, 不判断自己是否在成员列表里.
是为什么? 如果判断, 会有什么问题呢?
PreVote属于优化部分,在develop分支有实现。
Raft的状态机是基于日志的,而日志基本上都需要持久化,所以理论上状态机不基于内存。书里面为了调试方便设计了一个基于内存的日志实现,但是不代表Raft的状态及基于内存。
你好, 每次系统启动时, 为了获得最新的服务状态, 需要服务去重放日志, 以获得最新的状态吗?
理论上是的。不过Raft有日志快照,所以实际上Raft不一定是从第一条日志开始重放的。你可以参考数据库的快照和WAL。
抱歉,不是很确定你的这个问题是问Raft为什么要比较term,还是为什么还要用日志中的term比较。我只能模糊地回答一下。
Raft算法中每次选举都会产生一个新的term,这和Paxos算法是一样的。Raft所有操作都会基于这个term。Raft实现在收到请求之后基本都会先比较一下term,如果对方term比较小,直接返回错误。
其次Raft是基于日志比较的算法,日志里的term可能和系统现在的term不一致,比如说发起选举的时候,所以日志比较必须用日志而不是系统自身的term。
简单的回答的话,Raft算法的要求。
比如一个极端情况,两个节点组成的集群。把leader节点移除时,leader在没有把新集群配置传给另外一个节点时宕机了,剩下的一个节点因为收不到选票永远没办法成为leader。此时让旧leader重启,重新成为leader,让移除继续。这种情况下旧leader并不在集群列表中,所以结论是发起选举时不用判断。
作者你好,源码中在 AbstractHandler 中保存了 lastAppendEntriesRpc ,这样实现感觉会有问题?
源码中每次调用 write 就会保存 lastAppendEntriesRpc,然后在 channelRead 的时候去判断这个对象是否存在。但是每次调用 write 的时候是保存在 ToRemoteHandler 这个对象中,而 channelRead 的时候是在 FromRemoteHandler 这个对象中,所以在 channelRead 获取的时候就会获取不到这个 lastAppendEntriesRpc。
> 我来回应