前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >RocketMQ存储--同步刷盘和异步刷盘【源码笔记】

RocketMQ存储--同步刷盘和异步刷盘【源码笔记】

作者头像
瓜农老梁
发布于 2019-08-23 08:33:30
发布于 2019-08-23 08:33:30
2.3K00
代码可运行
举报
文章被收录于专栏:瓜农老梁瓜农老梁
运行总次数:0
代码可运行
目录
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
一、问题思考
二、Broker启动刷盘有关调用链
1.调用链
2.线程类关系图
三、线程类工作流程
1.堆外内存线程类CommitRealTimeService工作流程
2.同步刷盘线程类GroupCommitService工作流程
3.异步刷盘线程类FlushRealTimeService工作流程
四、消息追加与线程类的交互
1.调用链
2.同步刷盘主要代码
3.异步刷盘主要代码
五、刷盘方式示意图
1.同步刷盘示意图
2.异步刷盘未开启堆外缓存示意图
3.异步刷盘开启堆外缓存示意图
六、文章总结
七、主要源码类清单
一、问题思考

1.同步刷盘是怎么工作的? 2.异步刷盘是怎么工作的? 3.上篇文章的疑问,写入堆外内存的消息如何落盘的?

二、Broker启动刷盘有关调用链
1.调用链
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//初始化链条
@1 BrokerStartup#main
start(createBrokerController(args));
@2 BrokerStartup#createBrokerController
final BrokerController controller = new BrokerController(...)
boolean initResult = controller.initialize();
@3 BrokerController#initialize
this.messageStore = new DefaultMessageStore(...);
@4 DefaultMessageStore#DefaultMessageStore()
this.commitLog = new CommitLog(this);
@5 CommitLog#CommitLog()
if (FlushDiskType.SYNC_FLUSH == defaultMessageStore.getMessageStoreConfig()
.getFlushDiskType()) {
this.flushCommitLogService = new GroupCommitService();
} else {
this.flushCommitLogService = new FlushRealTimeService();
}
this.commitLogService = new CommitRealTimeService();
//启动链条
@6 BrokerStartup#start
controller.start();
@7 BrokerController#start()
this.messageStore.start();
@8 DefaultMessageStore#start()
this.commitLog.start();
@9 CommitLog#start()
this.flushCommitLogService.start();
if (defaultMessageStore.getMessageStoreConfig()
.isTransientStorePoolEnable()) {
this.commitLogService.start();
}

小结:由调用链可以看出,初始化并启动了以下线程类

1.同步刷盘 GroupCommitService

2.异步刷盘 FlushRealTimeService

3.如果开启堆外内存并且为异步刷盘 CommitRealTimeService

2.线程类关系图
三、线程类工作流程

既然线程类在Broker启动时就启动了,他们在做啥呢?

1.堆外内存线程类CommitRealTimeService工作流程

小结: 1.CommitRealTimeService主要工作是将写入堆外内存(writeBuffer)的消息,写入到fileChannel中,fileChannel为commitLog文件通道

2.committedPosition用于记录将writeBuffer数据写入到fileChannel中的内存位点(相对偏移量offset) 3.committedWhere用于记录写入fileChannel中的物理偏移量(文件名称+相对偏移量offset)

2.同步刷盘线程类GroupCommitService工作流程
注1:

1.执行onWaitEnd时交换读写容器,该线程类提供两个容器来装GroupCommitRequest

2.requestsWrite和requestsRead,每次执行提交(刷盘)前都会进行容器交换

3.好处:读写请求容器分离,避免潜在的锁竞争

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private void swapRequests() {
List<GroupCommitRequest> tmp = this.requestsWrite;
this.requestsWrite = this.requestsRead;
this.requestsRead = tmp;
}
注2:

1.flushedPosition 标记已经刷盘内存的位点。即刷盘相对偏移量,刷盘到什么位置了,下次从此处刷盘即可

2.flushedWhere 标记已经刷盘的物理偏移量,根据此位置可精确查找到文件中消息的存储位置。flushedWhere = 当前刷盘文件名称(该日志文件的起始物理偏移量) + flushedPosition

注3:
流程图中标记红色部分,将刷盘结果通知给等待线程

小结:同步刷盘线程类GroupCommitService主要工作 将请求从读容器中取出并通过mappedByteBuffer.force()将数据落盘。

3.异步刷盘线程类FlushRealTimeService工作流程

小结:FlushRealTimeService主要工作 1.不开启堆外外内存刷盘方式为mappedByteBuffer.force() 2.开启堆外内存刷盘方式为fileChannel.force

疑问:同步刷盘线程类GroupCommitService每执行一次都会交换读写容器,那刷盘请求什么时候放到写容器(requestsWrite)呢?

四、消息追加与线程类的交互

分析完线程类后,把镜头切换到消息追加,看看消息进来后是如何跟线程类交互的?

1.调用链
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@1 CommitLog#putMessage
//同步刷盘或者异步刷盘
handleDiskFlush(result, putMessageResult, msg);
@2 CommitLog#handleDiskFlush
2.同步刷盘主要代码

同步刷盘时构造刷盘请求,将请求提交给线程类GroupCommitService,service.putRequest(request),并获取刷盘结果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (FlushDiskType.SYNC_FLUSH == this.defaultMessageStore.getMessageStoreConfig().getFlushDiskType()) {
final GroupCommitService service = (GroupCommitService) this.flushCommitLogService;
GroupCommitRequest request = new GroupCommitRequest(result.getWroteOffset() + result.getWroteBytes());
service.putRequest(request);
//等待MappedFile刷盘成功状态通过countDownLatch来控制
boolean flushOK = request.waitForFlush(this.defaultMessageStore.getMessageStoreConfig().getSyncFlushTimeout());
}
}
3.异步刷盘主要代码

未开启堆外内存唤醒FlushRealTimeServicee,开启堆外内存唤醒CommitRealTimeService。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (!this.defaultMessageStore.getMessageStoreConfig()
.isTransientStorePoolEnable()) {
flushCommitLogService.wakeup();
} else {
commitLogService.wakeup();
}
五、刷盘方式示意图
1.同步刷盘示意图
2.异步刷盘未开启堆外缓存示意图
3.异步刷盘开启堆外缓存示意图
六、文章总结

1.同异步刷盘通过Broker属性flushDiskType来设置,默认为ASYNC_FLUSH,同步刷盘配置为SYNC_FLUSH 2.同步刷盘是怎么工作的? 注:见GroupCommitService工作流程及与消息追加交互 3.异步刷盘是怎么工作的? 注:

见FlushRealTimeService和CommitRealTimeService工作流程及与消息追加交互

4.上篇文章的疑问,写入堆外内存的消息如何落盘的? 注:见异步刷盘开启堆外缓存示意图

七、主要源码类清单
  • CommitLog.java
  • CommitLog#putMessage
  • CommitLog#GroupCommitService
  • CommitLog#FlushRealTimeService
  • CommitLog#CommitRealTimeService
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-08-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 瓜农老梁 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
只有1个字节的文件实际占用多少磁盘空间
在一个目录中创建了一个空的文件以后,通过du命令看到的该文件夹的占用空间并没有发生变化。这符合我们之前的认识,因为空文件只占用inode。好,那让我们修改文件,添加一个字母
范蠡
2020/12/15
8130
只有1个字节的文件实际占用多少磁盘空间
深入了解linux系统—— 文件系统
很简单,我们被打开的文件在操作系统中被管理起来,而没有被打开的文件是存储在磁盘当中的。
星辰与你
2025/05/23
1660
深入了解linux系统—— 文件系统
新建一个空文件占用多少磁盘空间?
操作完成后,是否要消耗掉我们的一些磁盘空间?需要的话,大概能消耗多少?嗯,是的,这个问题简单的超乎你的想象,但是不知道你否能给你自己一个满意的答案。
开发内功修炼
2022/03/28
5760
新建一个空文件占用多少磁盘空间?
Linux Ext系列文件系统(看这一篇就够了!)
硬盘是典型的"块"设备, 操作系统读取硬盘数据的时候, 其实是不会一个个扇区地读取, 这样效率太低, 而是一次性连续读取多个扇区, 即一次性取⼀个”块”(block)。
用户11317877
2025/02/17
1250
Linux Ext系列文件系统(看这一篇就够了!)
文件系统专栏 | 之ext4文件系统结构
上次讲了VFS层,这次说说文件系统层,文件系统层将不同的文件系统实现了VFS的这些函数,通过指针注册到VFS里面。所以,用户的操作通过VFS转到各种文件系统,linux用到最多的是ext4文件系统,我们就说这个吧。EXT4是第四代扩展文件系统(英语:Fourth extended filesystem,缩写为 ext4)是Linux系统下的日志文件系统,是ext2和ext3文件系统的后继版本。 ext4文件系统布局 一个Ext4文件系统被分成一系列块组。为减少磁盘碎片产生的性能瓶颈,块分配器尽量保持每个文件
刘盼
2022/08/29
3.7K0
文件系统专栏 | 之ext4文件系统结构
read文件一个字节实际会发生多大的磁盘IO?
先讲一个作者大约5-6年前我在某当时很火的一个应用分发创业公司的面试小插曲,该公司安排了一个刚工作1年多的一个同学来面我,聊到我们项目中的配置文件里写的一个开关,这位同学就跳出来说,你这个读文件啦,每个用户请求来了还得多一次的磁盘IO,性能肯定差。借由这个故事其实我发现了一个问题,虽然我们中的大部分人都是计算机科班出身,代码也写的很遛。但是在一些看似司空见惯的问题上,我们中的绝大多数人并没有真正理解,或者理解的不够透彻。
桶哥
2021/01/04
1.1K0
read文件一个字节实际会发生多大的磁盘IO?
从磁盘存储维度观测ext4文件系统
inode是文件系统中每个文件的唯一标识,映射IO Block到磁盘扇区的对应关系。inode一般存储了文件的acess/modify/create的时间、访问权限、以及最重要的这个文件包含了哪些Blocks.这里需要注意的是ext4系统中当删除文件的时候,这个文件的inode是可以被回收然后被新文件重用。
用户4700054
2023/02/26
1.2K0
从磁盘存储维度观测ext4文件系统
【linux学习指南】Ext系列文件系统(二)引⼊⽂件系统“块“&&分区&&inode概念
其实硬盘是典型的“块”设备,操作系统读取硬盘数据的时候,其实是不会⼀个个扇区地读取,这样效率太低,⽽是⼀次性连续读取多个扇区,即⼀次性读取⼀个”块”(block)。
学习起来吧
2025/01/01
1610
【linux学习指南】Ext系列文件系统(二)引⼊⽂件系统“块“&&分区&&inode概念
从青铜到王者系列:深入浅出理解DeepSeek 3FS (2)从内核到用户态文件系统的设计之路
从青铜到王者系列:深入浅出理解DeepSeek 3FS (2)从内核到用户态文件系统的设计之路
早起的鸟儿有虫吃
2025/04/11
1820
从青铜到王者系列:深入浅出理解DeepSeek 3FS (2)从内核到用户态文件系统的设计之路
Ext2文件系统布局,文件数据块寻址,VFS虚拟文件系统
http://blog.csdn.net/jnu_simba/article/details/11759809
bear_fish
2018/09/20
7990
Ext2文件系统布局,文件数据块寻址,VFS虚拟文件系统
read 文件一个字节实际会发生多大的磁盘IO?
在日常开发中一些看似司空见惯的问题上,我觉得可能大多数人其实并没有真正理解,或者理解的不够透彻。不信我们来看以下一段简单的读取文件的代码:
开发内功修炼
2022/03/28
1.1K0
read 文件一个字节实际会发生多大的磁盘IO?
ext2文件系统详解[接<磁盘与文件系统(简单)>]
在大文件系统下, 单一inode表将会变得非常臃肿, 难以管理, 因此 ext2采用多个区块群组(group block), 每个区块群组均具有其 superblock, inode, block
buiu
2021/10/27
8540
Linux文件属性详解
文件存储在硬盘上,硬盘的最小存储单位叫做"扇区"(sector)。每个"扇区"的大小为512字节(byte), ,操作系统读取硬盘的时候,不会一个个扇区的读取,这样效率太慢。他是一次性读取多个扇区,即一次性读取一个"Block块"。一个Block有8个连续的扇区(sector)组成。 数据都存在Block块里面,但是我们怎么知道一个数据存放在哪些Block块里面呢?这个时候就必须需要一个索引,引导我们去找到哪些存放在BLOCK块里面的额数据。这存放索引的地方我们称为索引节点(Inode),索引节点里面包括了:文件的类型,属主,属组,权限,和时间戳一些信息,但是不包括文件名, 1.1.2 inode包含的内容
张琳兮
2018/09/10
3.4K0
Linux文件属性详解
理解格式化原理
在前文《磁盘开篇:扒开机械硬盘坚硬的外衣!》和《拆解固态硬盘结构》中,我们了解到了硬盘基本单位是扇区。在《磁盘分区也是隐含了技术技巧的》中我们也了解了磁盘分区是怎么回事,但刚分完区的硬盘也是不能直接被被操作系统使用的,必须还得要经过格式化。那么今天我们就简单聊一聊,Linux下的格式化到底都干了些啥。
开发内功修炼
2022/03/24
5330
理解格式化原理
Linux的文件系统及文件缓存知识点整理
硬盘分成相同大小的单元,我们称为块(Block)。一块的大小是扇区大小的整数倍,默认是4K。在格式化的时候,这个值是可以设定的。
luozhiyun
2020/06/08
4.3K0
Linux的文件系统及文件缓存知识点整理
[ Linux驱动炼成记 ] 15 - 存储器EMMC中Ext4文件系统 中 磁盘空间占用率100%
**产品现象 : ** 设备(Linux 系统) 运行一段时间后,其中某一个分区 /et/config 突然占用率为100%,而实际空间可能1%都不到。 这种问题百思不得其解。谷歌/百度 所遇到的解决方案都是嵌入式系统中磁盘空间占用率100% , 针这种情况,完全没用。
程序手艺人
2019/02/20
5.1K0
用户与磁盘
该文章介绍了Linux系统中用户和用户组管理的基本知识,包括用户账号、用户组、UID和GID的概念,以及使用命令行和图形界面管理用户和用户组的技巧。同时,还介绍了Linux系统中文件权限设置和文件所有者/所属用户/其他用户的区别,以及如何使用命令行工具进行文件权限管理的技巧。
惨绿少年
2017/12/27
1.1K0
磁盘文件系统二
但是,如果一个文件比较大,inode的块号不足以标识所有的数据块,就会使用间接块。文件系统会在硬盘上分配一个数据块,不存储文件数据,专门用来存储块号。该块被称为间接块。inode的长度是固定的。间接块占用的空间对于大文件来说是必要的。但是对于小文件不会带来额外的开销。当我们用到 i_block[12]的时候,就不能直接放数据块的位置了,要不然 i_block 很快就会用完了。这该怎么办呢?我们需要想个办法。我们可以让 i_block[12]指向间接块。也就是说,我们在 i_block[12]里面放间接块的位置,通过 i_block[12]找到间接块后,间接块里面放数据块的位置,通过间接块可以找到数据块。如果文件再大一些,i_block[13]会指向一个块,我们可以用二次间接块。二次间接块里面存放了间接块的位置,间接块里面存放了数据块的位置,数据块里面存放的是真正的数据。如果文件再大一些,i_block[14]会指向三次间接块。
没有故事的陈师傅
2021/06/24
1.1K0
磁盘文件系统二
漫谈Linux标准的文件系统(Ext2/Ext3/Ext4)
全称Linux extended file system, extfs,即Linux扩展文件系统,Ext2就代表第二代文件扩展系统,Ext3/Ext4以此类推,它们都是Ext2的升级版,只不过为了快速恢复文件系统,减少一致性检查的时间,增加了日志功能,所以Ext2被称为索引式文件系统,而Ext3/Ext4被称为日志式文件系统。
justmine
2019/02/15
2.1K0
浅谈ext4文件系统初始化
调试环境 $ modprobe -v ext4 $ dd if=/dev/zero of=/tmp/disk1 count=30 bs=1M $ losetup --show -f /tmp/disk1 /dev/loop0 $ mkfs.ext4 /dev/loop0 $ mount /tmp/disk1 /mnt/disk1 关于超级快基本知识 当使用者适应mkfs.ext4 /dev/sdb时候,系统按照ext4内部的布局规则写入写入先关数据。mount时候按照内置的布局规则读取这些信息
用户4700054
2022/08/17
1.7K0
浅谈ext4文件系统初始化
推荐阅读
相关推荐
只有1个字节的文件实际占用多少磁盘空间
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验