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 条评论
登录 后参与评论

相关文章

来自专栏Hadoop数据仓库

HAWQ取代传统数仓实践(二)——搭建示例模型(MySQL、HAWQ)

一、业务场景         本系列实验将应用HAWQ数据库,为一个销售订单系统建立数据仓库。本篇说明示例的业务场景、数据仓库架构、实验环境、源和目标库的建立过...

2038
来自专栏匠心独运的博客

分布式定时任务Elastic-Job框架在SpringBoot工程中的应用实践(一)

摘要:如何构建具备作业分片和弹性扩缩容的定时任务系统是每个大型业务系统在设计时需要考虑的重要问题? 对于构建一般的业务系统来说,使用Quartz或者Sprin...

802
来自专栏SDNLAB

脱坑神器,让你一步了解ODL控制器集群

一、控制器集群基本知识 1.1 Consensus一致性 Consensus一致性是指多个服务器在状态达成一致,但是在一个分布式系统中,因为各种意外可能,有的...

3657
来自专栏腾讯技术工程官方号的专栏

PGXZ 腾讯分布式关系数据集群—架构解析

本文作者:数据平台部存储引擎组PGXZ项目负责人,2013年从华为加入腾讯,从事数据库和存储相关的工作。多年来一直致力于数据库引擎的研究和开发,从事过多款数据库...

24511
来自专栏Java技术分享

java系统高并发的解决方案

一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构、性能的要求...

5858
来自专栏Golang语言社区

机器人 Go 语言库:Gobot

Gobot 是为机器人和物理计算所设计的一组 Go 语言库,提供在同一时间合并多个不同设备的简单且强大的解决方案。 package main import (...

3015
来自专栏CSDN技术头条

Livy:基于Apache Spark的REST服务

Apache Spark提供的两种基于命令行的处理交互方式虽然足够灵活,但在企业应用中面临诸如部署、安全等问题。为此本文引入Livy这样一个基于Apache S...

2877
来自专栏hbbliyong

mstsc 远程序桌面登录的 c#开发

远程序桌面登录的.NET开发,可以使用MSTSCLib.dll和MsTscAxWrapper.dll两个转换过的动态库,而无需使用WINDOWS自带的OCX,因...

3706
来自专栏智能大石头

每天4亿行SQLite订单大数据测试(源码)

SQLite单表4亿订单,大数据测试 SQLite作为嵌入式数据库的翘楚,广受欢迎! 新生命团队自2010年以来,投入大量精力对SQLite进行学习研究,成功应...

2726
来自专栏Elasticsearch实验室

基于Elastic Stack搭建日志分析平台

(本次课程是通过小程序对外推广的,所以PPT是竖版的。电脑端浏览体验可能不太好,望大家见谅)

1683

扫码关注云+社区