Kafka 和 RocketMQ 底层存储简单比较
所属分类 kafka
浏览量 1336
顺序读写
页缓存 数据写入页缓存 脏页
操作系统在合适的时候将脏页写入磁盘中
小的写入操作合并成大的写入,再刷盘
读取 页缓存命中则直接返回
页缓存 miss 则产生缺页中断,从磁盘加载数据至页缓存中,然后返回数据
预读 局部性原理 把相邻的磁盘块读入页缓存中
顺序写盘的速度比随机写内存要快
数据丢失 断电 未刷盘的脏页数据丢失
可以调用 fsync 强制刷盘 ,但性能损耗大
一般建议通过多副本机制来保证消息的可靠,而不是同步刷盘。
采用文件追加的方式来写入消息
mmap-文件内存映射 ,避免拷贝
避免内核空间页缓存到用户空间的拷贝
文件映射
将程序虚拟页面直接映射到页缓存上,不需要从内核态往用户态拷贝数据
不用调用read或write方法对文件进行读写,可通过映射地址加偏移量的方式直接操作
sendfile-零拷贝
一般发送文件的流程
磁盘 页缓存(内核空间) 缓冲区(用户空间) socketbuffer(内核空间) 网卡
DMA Direct Memory Access ,独立直接读写系统内存,不需要 CPU 介入,显卡、网卡之类都会用DMA
Linux2.1 sendfile
页缓存(内核空间) socketbuffer(内核空间) 网卡
Linux2.4 sendfile
sendfile + 分散-收集(Scatter-gather)DMA
Java里的 sendfile
FileChannal.transferTo()
RocketMQ
CommitLog
所有的消息顺序追加写入 CommitLog ,并建立消息对应的 CosumerQueue ,
消费者通过 CosumerQueue 得到消息的真实物理地址再去 CommitLog 获取消息。
可将 CosumerQueue 理解为消息的索引
CommitLog 和 CosumerQueue 都使用 mmap
发消息的时候默认将数据拷贝到堆内存中,然后再发送
this.fileChannel = new RandomAccessFile(this.file,"rw").getChannel();
this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE,0,fileSize);
顺序写盘,整体来看是顺序读盘,使用 mmap,不是真正的零拷贝
文件预先分配和文件预热即每页写入一个0字节,然后再调用mlock 和 madvise(MADV_WILLNEED)
CommitLog 大小默认1G
后台线程 AllocateMappedFileService
mlock
将进程使用的部分或者全部的地址空间锁定在物理内存中,防止其被交换到swap空间
madvise
给操作系统建议,说明文件在不久的将来要访问,可以提前读几页
Kafka
一个分区一个文件夹
日志文件没有用 mmap,索引文件用了 mmap
发消息 用 零拷贝 FileChannel.transferTo
sendfile vs mmap+write
sendfile少了一次页缓存到 SocketBuffer 的拷贝
vm.swappiness 建议 设置为1
RocketMQ VS Kafka
都是顺序写入,不过 RocketMQ 把消息都存一个文件中,而 Kafka 是一个分区一个文件
每个分区一个文件在迁移或者数据复制更加灵活
但是分区多了 会变成 随机读写
发送消息 RocketMQ mmap + write ,通过预热来减少大文件 mmap 因为缺页中断产生的性能问题
Kafka sendfile,发送效率更高,少了一次页缓存到 SocketBuffer 的拷贝
RocketMQ Kafka 简单比较
rocketmq知识点
kafka核心知识点
上一篇
下一篇
Redis内部存储结构
kafka-topics.sh 无法获取topic列表及topic信息
kafka之broker-list bootstrap-server 和 zookeeper
kafka发送端核心参数说明
kafka消息发送机制
Kafka中的分区分配