前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Raft只读操作实现要点

Raft只读操作实现要点

作者头像
老钱
发布2018-08-14 17:31:55
3.1K1
发布2018-08-14 17:31:55
举报
文章被收录于专栏:码洞码洞

Leader直连

所有的客户端最终都只会链接到Leader。客户端开始时随机挑选一个节点,如果这个节点不是Leader,就通过响应告诉客户端Leader的地址,然后客户端再去连Leader。

Follower转发

客户端可以链接任意节点,客户端的指令会被Follower转发到Leader来执行。

只读操作也必须经过majority确认

只读操作一般只需要读取当前节点的状态机就可以了。但是存在网络分区的情况会导致当前的节点数据严重落伍。被分区隔离开来的Leader和Follower全然不知整个集群已经经过了新一轮的选举,自己的数据已经严重落伍了。所以不论客户端连接的是Follower还是Leader,都不能直接读取状态机来处理只读操作。

Raft对只读操作的处理办法是

  1. 只读请求最终也必须依靠Leader来执行,如果是Follower接收请求的,那么必须转发
  2. 记录下当前日志的commitIndex => readIndex
  3. 执行读操作前要向集群广播一次心跳,并得到majority的反馈
  4. 等待状态机的applyIndex移动过readIndex
  5. 通过查询状态机来执行读操作并返回客户端最终结果。

在步骤1到步骤2之间,如果Leader刚刚当选,还必须等待no-op操作同步完成。

上面的步骤看起来很复杂,其中最重要的就是心跳广播,这是为了确认当前集群没有被网络分区。

只读操作没那么快

因为只读操作也要经过一次RPC,所以它并没有我们想想的那么快,它可能和写操作性能差不多。所以并不能通过扩展节点数量来得到整体集群读性能的提升,甚至不升反降。

折中的方案就是单独提供一个特殊的只读指令,在一致性要求不高的场合使用这个特殊指令。这样就可以通过扩展集群数量来提升读性能。但是在遇到网络分区时会导致数据陈旧的问题,要看业务场景是否可以容忍。

只读操作的进一步优化

标准的强一致只读操作是完全是在Leader端进行的。这里可以做一步改进让只读操作主要在Follower端进行。

  1. Follower接收到只读指令后,向leader索要当前的readIndex值。
  2. Follower端等待自身的状态机的applyIndex移动过readIndex。
  3. Follower端通过查询自身的状态机来执行读操作并返回客户端最终结果。

leader向follower返回readIndex也不是简单的直接返回,而是需要重复前面的标准步骤1~步骤3,来确认网络没有分区。这还是一次RPC操作,无法省略。但是毫无疑问,它分担了leader的压力,可以让leader有更多的资源来处理自身的读写操作。

只读操作的终极优化

前面提到的方法无法避免额外的RPC操作来确认网络没有被分区,所以性能没有非常明显的得到优化。 Raft的论文中提到了另一种可以大幅提升只读操作性能的优化方案,同时还告诫读者不到万不得已不要使用。

因为这个额外的RPC操作只是为了确认网络没有被分区,当前节点有无被孤立,新的leader是否有产生。而新leader的产生是需要经历一次完整的选举过程的,这个选举过程有一定的时间才能完成。所以这个分区的状态是可以被缓存一小段时间的。这段时间内不可能出现leader的变更。

leader收到majority的心跳响应后,在接下来的一小段时间里不必去广播心跳来确认分区情况,而可以直接查询当前节点的状态机返回客户端结果。

之所以作者不推荐折中方案是考虑到时钟漂移。比如一个定时任务在系统非常繁忙的时候是不能得到准时执行的,会产生偏差,偏差的时间取决于系统的繁忙程度、Full GC是否正在进行、虚拟机是否正在迁移等特殊情况。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码洞 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档