searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Rocketmq消息存储过程

2023-04-28 03:44:54
10
0

rocketmq为了极致的消息写入性能,设计了commitLog日志文件,消息完成编码后将会被顺序写入到磁盘,并且为了保证高可用,会将消息复制到其他副本。所以消息的存储过程一共分为两部分,第一部分为master的本地磁盘写入,当然这一步会伴随同步或异步的刷盘机制;第二部分就是高可用,即主从复制,下面也主要分析这两部分的核心流程;

Disk

消息顺序写入commitLog,同时采用异步的方式进行写磁盘以及主从复制,如果是可靠性最严格的模式,需要等待该条消息落盘后以及完成主从复制之后才返回客户端;

主体的流程如下:

 

默认的模式下,消息的读写都需要涉及到pageCache的写入,swap等操作,在极高并发的情况下,pageCache会面临较大的压力,导致page busy,延时出现毛刺,经典的解决方案就是读写分离(在pulsar中的方案就是硬盘级别的读写分离);rocketmq的实现方式在内存级别,采用堆外缓冲池的模式,预先在堆外分配默认5个大小为1G的writeBuffer,每次写入消息的时候,写入到writeBuffer即可返回;writeBuffer会被一个线程定期commit到fileChannel中,即pageCache,为了追求极高的吞吐,提交到pageCache也是批量的方式,可以指定最小commit的page数,同时根据时间间隔强制commit一次(后面的异步flush线程也是同样的批量优化机制)。commit完成之后就会更新该mappedFile的commitPosition,该位置会被当成valid的可以被构建读索引的offset。

完成写入后,会唤醒flush线程,flush线程会将当前wrotePosition跟flushPosition之间的数据(也会有上述的批量优化机制)刷盘,并更新flushPosition指针;整个数据落盘完成。

Slave

master会启动一个accetpor线程,等待slave的连接,slave启动的时候就会跟master建立主从复制的连接,并且开始同步ackOffset,master必须保证从ack的位置开始新的复制,所以连接建立之后必须等待收到slave的ack,更新本地状态之后才会开始数据传输;

正常情况下主从复制下的模式,slave成功复制并写入本地commitlog的offset应跟master下一次复制batch的起始offset一致,否则复制失败,主从连接将会被关闭;

如果slave节点收到master发送的数据但是写入本地失败(由于写入本地commitlog为同步操作,所以ackOffset要么等于上一次的值,要么等于这次完全写入成功的offset,不存在中间状态),本地维护的最大offset没有更新,下一次起始offset更大的batch发送过来会由于起始offset大于当前commitlog的最大offset而发生错误,slave主动关闭主从复制的连接,master的读线程收到关闭连接的FIN包会全部退出复制的读写线程,主从复制停止,直到slave故障恢复;

当slave恢复后,跟master建立新连接,master重新恢复主从复制channel,master从内存中的slaveAckOffset(上一次slave返回的ackOffset,为安全位置)继续开始复制,slave中的未完成复制的部分会被重新覆盖,保证不丢失数据;

slave在复制某batch过程中宕机同理;

这样的机制保证了slave不会出现日志空洞,保证了主从复制的一致性,当然如果是异步复制,只能保证最终一致性;

在master中会维护slaveAckOffset这样一个变量,这标记着一个消息写入安全的位置,也就是说这个位置之前的消息是被安全复制的,只不回丢失,也不回更改的,后面消息异步构建索引(这里的索引分为cq的构建以及index文件的构建,在rocketmq内部都统一封装为dispatch任务在消息安全写入到commitLog之后异步线程完成)也是以该水位为终点,超过该位置的消息是不安全的,如果在客户端进行消费之后master宕机了发生了主从切换之后它再被恢复成slave,由于该条被消费的消息没有复制到当前的新master,因此旧master复制commitLog时该消息会被截断丢弃,造成消息生产消费的不一致;

总结

rocketmq通过顺序写入消息方式提供极致的性能,并且考虑不同场景的需求在数据的可靠性与性能之间提供了多种配置;在数据的一致性上同时支持写入强一致性以及最终一致性,这也是分布式系统在CAP上做出的经典权衡。

0条评论
0 / 1000
l****n
2文章数
0粉丝数
l****n
2 文章 | 0 粉丝