Raft 算法原理及其在 CMQ 中的应用(下)

《Raft 算法原理及其在 CMQ 中的应用(上)》

三 Raft在CMQ中的应用

早期我们在rabbitmq的基础上搭建了一套可扩展消息中间件CRMQ1.0,由于rabbitmq的GM同步算法在性能等方面存在瓶颈,所以自研了基于raft算法的内部版本CRMQ2.0和腾讯云CMQ,在保证强一致高可靠的前提下,性能和可用性都有显著提升。实现上采用了生产Confirm + 消费Ack机制保证消息不丢失,Confirm和Ack机制均通过raft来保证。生产的消息通过Raft转为Entry同步到大多数节点并提交,完成后各节点状态机应用该Entry,将消息内容写入磁盘,之后由Leader节点回复客户端Confirm,表示消息生产成功。消费时客户端从Leader节点拉取消息,消费完成后通过Ack命令通知服务端消息已消费可删除,Ack请求经Raft同步后,各节点应用该请求,之后消息被删除不会再投递。下面介绍详细过程:

生产流程:

1)生产者将生产消息的请求发往Leader的Raft模块。

2)Raft模块完成Entry的创建和同步。

3)大多数节点上持久化并返回成功后Entry标记为Committed。

4)所有节点的State Machine应用该日志,取出实际的生产请求,将消息内容写入磁盘,更新ApplyIndex。该步骤不需要刷盘。

5)Leader回复客户端Confirm,通知生产成功。

6)如果此后机器重启,通过raft日志恢复生产消息,保证了已Confirm的消息不丢失。

消费流程:

1)消费者从Leader节点拉取消息。

2)Leader收到后从磁盘加载未删除的消息投递给客户端。

3)客户端处理完成后Ack消息,通知服务器删除消息。

4)Ack请求经Raft同步后标记为Committed。

5)各节点状态机应用该日志,将消息对应的bit置位,将其设置为已删除并更新ApplyIndex。

6)通知客户端删除成功。

7)如果机器重启,通过Raft日志恢复Ack请求,保证了已删除的消息不会再投递。

快照管理:

快照管理与业务紧密相关,不同系统快照制作的成本差异很大,CMQ中快照的内容十分轻量,一次快照的耗时在毫秒级,平均5min创建一次,各节点独立完成。实现上内存中维护了一份动态的快照,制作快照时首先拷贝出动态快照的副本,之后处理流继续更新动态快照,用拷贝出的副本创建快照文件,不影响实际的处理流。快照具体内容包括:

1)term:快照对应Entry的term (参照算法)

2)index:快照对应Entry的 index (参照算法)

3)node_info:Entry时的集群配置信息。

4)topic info:每个队列一项。CMQ中同一队列生产的消息顺序写入,分片存储,因此只需记录最后一个分片的状态(分片文件名,文件偏移量)。

5)queue info:每个队列一项。CMQ中采用bitmap记录消息的删除情况,在内存中维护,在制作快照时dump到快照文件。

可靠性:业界统一的衡量标准为RPO(Recovery Point Objective),反映故障时数据恢复完整性的指标。由于只有提交的日志才会被应用到状态机,且raft日志在写入时会强制刷盘,所以故障重启后通过快照+raft日志即可恢复,不会丢失数据,RPO=0。不过,如2.7节所述,Leader故障时可能会产生重复数据,需要通过幂等性保证或去重机制来解决该问题。

可用性:业界统一的衡量标准为RTO(Recovery Time Objective),反映故障时业务恢复及时性的指标。follower故障对系统没有影响(RTO=0),leader故障时其他节点通过自发选出新leader,而且CMQ中前端具备自动重连功能,当连接断开后会自动寻找新leader,系统不可用时间大大降低。目前CMQ中配置的选举超时时间为2s~4s,在不考虑选举冲突的前提下,RTO上限为4s。

在CMQ中,Leader通过与Follower的心跳判断自己是否已网络分区,当检测到分区时(大多数节点上次心跳回复时间距现在超过2s),主动断开前端连接,前端发现后会自动寻找新Leader。这段时间内客户端请求会超时,在连上新Leader后,客户端重试之前超时的任务,后续请求恢复正常。

四 Raft算法性能优化

Raft算法的性能瓶颈主要有两方面:

1) 每次日志写入后都需要刷盘才能返回成功,而刷盘是一个比较耗时的操作。

2) 由于算法限制,所有的请求都由Leader处理,不能做到所有节点皆可提供服务。

针对以上两个问题,我们做了以下优化:

1)Batch Processing:在请求量较大时,并不是每一条日志写入都刷盘,还是累积一定量的日志后集中刷盘,从而减少刷盘次数。对应的,在同步到Follower时也采用批量同步的方式,Follower接收后将日志批量写盘。

2)Multi-Raft: 进程中同时运行多个raft实例,机器之间组建多raft 组,客户端请求路由到不同的group上,从而实现多主读写,提高并发性能。通过将leader分布在不同机器上,提高了系统的整体利用率。

3)Async-rpc: 在日志同步过程中采用同步rpc方式,在一端处理时另一端只能等待,性能较差。我们采用异步的方式使得leader端发送和Follower端处理并发进行。发送过程中leader端维持一个发送窗口,当待确认的rpc数达到上限停止发送,窗口值上限:

在与同属于高可靠(多副本同步刷盘)的Rabbitmq性能对比中,相同压测场景下CMQ速度可以达到RabbitMQ的四倍左右。

以下为TS60机器1KB消息大小时性能数据:

测试中CMQ采用单Raft组方式以保证测试公平性。监控显示CPU、内存和网卡均未达到瓶颈,系统瓶颈在磁盘IO,iostat显示w_await远大于svctm。主要原因在于刷盘耗时,造成写操作排队等待。

实际生产环境CMQ中我们将raft组和磁盘进行绑定,实现raft组之间磁盘的隔离,一方面保证了磁盘的顺序读写,另一方面充分利用机器的cpu 、内存、网卡等资源。

五 通用Raft库

CMQ中完整实现了Raft算法并解决了很多细节难点。考虑到分布式系统设计的复杂性,如果开发者只专注于业务相关部分,将可以显著降低开发难度,提高系统的质量,所以我们将CMQ中的raft部分以库的方式独立出来,使用者用它即可搭建一套强一致高可用分布式系统。目前该库已经完成基线版本开发并在部门落地使用,验证完成后会陆续开放给更多业务使用。

六 总结

消息中间件通常分为高可靠版本和高性能版本两种。CMQ是一款金融级的高可靠分布式消息中间件,通过raft保证了消息的可靠不丢失。同时在性能和可用性方面相比竞品都有显著提高。此外,我们自研的高性能版本的消息中间件ckafka也已在腾讯云上线,完美兼容kafka0.09~0.10版本客户端,关于CKafka的具体技术介绍请关注后续技术文章。

Raft算法强调了Leader的地位,选举和日志同步都是围绕Leader展开。由Leader负责处理所有请求保证了系统的强一致性;Leader选举和日志同步算法保证了数据的可靠不丢失;此外上述步骤只需要大多数正常互联即可,从而极大提高了系统的可用性,少量机器故障不受影响。不过,所有请求由Leader处理并没有充分利用从节点的资源,目前google的Spanner已支持从从节点读取,后续我们也会在这方面作更进一步的研究。Raft算法易于理解和工程化,相信未来会应用在越来越多的分布式系统中。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

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

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏杨建荣的学习笔记

Oracle跨平台迁移的简单总结(r10笔记第91天)

前段时间测试了一下GoldenGate,结合我之前的一些尝试,对于小机环境的迁移,思路是逐步清晰了起来。 需求的核心是跨平台迁移数据库,最好能够升级到新的版本,...

34113
来自专栏腾讯Bugly的专栏

Android 进程保活招式大全

目前市面上的应用,貌似除了微信和手Q都会比较担心被用户或者系统(厂商)杀死问题。本文对 Android 进程拉活进行一个总结。 Android 进程拉活包括两个...

5817
来自专栏大魏分享(微信公众号:david-share)

最流行的5大开源Web服务器

根据维基百科介绍,web服务器是“通过HTTP协议处理web请求的计算机系统”(a computer system that processes request...

4015
来自专栏互联网技术栈

消息队列探秘-Kafka全面解析

在项目启动之初来预测将来项目会碰到什么需求,是极其困难的。消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。这允许你独立...

961
来自专栏PingCAP的专栏

三篇文章了解 TiDB 技术内幕:谈调度

前两篇文章介绍了 TiKV、TiDB 的基本概念以及一些核心功能的实现原理,这两个组件一个负责 KV 存储,一个负责 SQL 引擎。本篇文章将介绍一下 PD(P...

2710
来自专栏Android 研究

反插件化:你的应用不是一个插件(转)

Android插件化技术是应用程序级别的一项创新型技术,它的初衷主要是用于热更新,减少APK安装包的大小,以及解决65535方法数量的限制。从技术层面来说,An...

3052
来自专栏架构师之路

100行代码,搞定http监控框架

集群信息管理,员工信息管理,告警策略管理,几篇前戏已经铺垫足够,今天,分享如何用100行代码搞定一个可扩展,通用的http监控框架。 一、常见的http监控玩法...

3896
来自专栏数据和云

故障恢复:从未知错误ORA-600 [3712]以猜测推理达成恢复

李真旭 Oracle ACE,云和恩墨技术专家 个人博客:www.killdb.com 在Oracle数据库的日常维护中,我们可能经常会遇到一些从未见过的错误,...

2886
来自专栏架构师之路

消息总线真的能保证幂等?

一、缘起 如《消息总线消息必达》所述,MQ消息必达,架构上有两个核心设计点: (1)消息落地 (2)消息超时、重传、确认 ? 再次回顾消息总线核心架构,它由发送...

4679
来自专栏阿杜的世界

RocketMQ学习-概览快速开始RocketMQ的架构

参考官网的文档Quick-Start,在我的Mac上部署rmq,并体验了发消息和收消息的功能。

931

扫码关注云+社区