raft read query
Processing read-only queries more efficiently
前言:
raft 的论文也看了很多遍, 其中轻描淡写的说了leased-base的读。 etcd的raft源码实现也看了几次, 有几个点特别不理解, 直到去看readme.md的时候,才注意到这个https://ramcloud.stanford.edu/~ongaro/thesis.pdf(哎, 不读文档害死人呀,以后看什么一定要先读文档), 这不是论文, 更像一本书, 涉及到了raft方方面面.
整体步骤
-
如果leader还没有提交entry, 他必须等待直到有entry提交. leader完整性规则保证了该leader拥有提交过的entry, 但是在当他被选择为leader的时候, 他并不知道那些那些是已经提交的entry, 所以他会在成为leader之后, 首先提交一个空entry作为自己item的开始, 一旦该空entry提及提交成功,该leader的commmited idx 至少和其他server上的commit idx一样大(也就是说:刚成为leader的时候, leader的commitidx 不一定是最大的)
-
leader 把最新的commit idx保存在本地变量readindex里
-
leader必须保证自己不被其他new leader替代(并且自己还没有意识到自己被替代)。 leader向其他server发送一轮hb,并且检验自己能不能被过半server回复, 一旦被集群过半server回复,该leader就能至少保证在他发送hb的那一刻,集群中没有其他leader, 因此,自己本地保存的readindex仍然是最大.
-
leader等state machine至少applied和readindex一样大, 这种情况下, 就能满足强一致。
-
最后,leader把用户查询赋给状态机, 并且给客户端回复。
alternative(一)
为了提高集群的吞吐量,分担leader的压力, 可以让follower承担读的请求。 但若没有一些措施,可能读到过期数据,比如L:分区follower可能一段时间内并没有接受到任何新的entry, 甚至该follower确实接受到了leader的hb, 但是该leader其实并不是当前集群的leader, 只是该leader自己还没意识到自己已经被取代而已。 为了保证安全的读, follower需要向leader(该leader将会执行上面的1-3 step)请求当前最新的readindex, 然后该follower在自己本机器执行以上的4-5 step。
alternative(二)
屏幕快照 2017-08-24 上午11.41.10.png一旦leader的hb被集群的大多数server确定, 该leader就能假设没有其他任何server在最小election timeout能成为leader, 这样leader就可以延长自己的lease(这个spanner的长leader有点相似)。因此leader在这段时间内就可以回复client的读请求而不需要和其他server交互。