对于数据的写入 OS会先写入至Cache内 随后通过异步的方式由pdflush内核线程将Cache内的数据刷盘至物理磁盘上
对于数据的读取 如果一次读取文件时出现未命中PageCache的情况 OS从物理磁盘上访问读取文件的同时 会顺序对其他相邻块的数据文件进行预读取
消费队列的读性能几乎接近读内存的原因
在消息堆积的情况下也不会影响性能
- 存储的数据较少
- page cache机制预读取
- 顺序读取
消息存储的日志数据文件CommitLog的读取会严重影响性能
读取消息内容会产生较多的随机访问读取
如何提升随机读性能
在块存储采用SSD的话 选择合适的系统IO调度算法 比如Deadline算法 随机读的性能会有所提升
文件的读写操作
传统的IO方式
传统的IO方式 用户态空间的进程要读写磁盘文件 需要经过内核空间 用户进程访问内核空间的缓存 如果没有的话 则读取磁盘文件 用户进程写入文件 先写入内核空间的socket缓存 再通过网卡写入到磁盘 经过2次DMA拷贝+2次CPU拷贝 4次上下文切换
RocketMQ mmap+write
1、页缓存是对磁盘数据的缓存 2、用户先读取页缓存 如果没有数据则读取磁盘 根据局部性原理 将相邻磁盘块读入页缓存 3、用户将数据写入页缓存 异步线程将小的写入操作合并成大的写入 然后刷入磁盘 4、顺序写入磁盘 磁头几乎不用换道 5、异步刷盘 容易丢失数据 a、可以同步刷盘 但性能低 b、一般采用多副本机制保证消息的可靠 6、数据追加到日志文件的尾部 老的消息无法更改
mmap利用内存映射文件来避免拷贝
用户空间可以通过映射地址加偏移量的方式直接操作内核空间的页缓存 避免了内核态再拷贝到用户态
rocketmq采用mmap+write方式实现文件读写操作
产生2次DMA拷贝+1次CPU拷贝 4次上下文切换 通过内存映射减少了一次CPU拷贝 可以减少内存使用 适合大文件的传输
对比Kafafa sendfile
sendfile
1、用户进程通过sendfile()方法向操作系统发起调用上下文从用户态转向内核态 2、DMA控制器把数据从硬盘中拷贝到读缓冲区 3、CPU将读缓冲区中数据拷贝到socket缓冲区 DMA控制器把数据从socket缓冲区拷贝到网卡 上下文从内核态切换回用户态 sendfile调用返回 2次用户态和内核态的上下文切换 3次拷贝 sendfile方法IO数据对用户空间完全不可见 所以只能适用于完全不需要用户空间处理的情况 比如静态文件服务器
sendfile+DMA gather
1、用户进程通过sendfile()方法向操作系统发起调用 上下文从用户态转向内核态 2、DMA控制器利用scatter把数据从硬盘中拷贝到读缓冲区离散存储 3、CPU把读缓冲区中的文件描述符和数据长度发送到socket缓冲区 4、DMA控制器根据文件描述符和数据长度 使用scatter/gather把数据从内核缓冲区拷贝到网卡 5、sendfile()调用返回,上下文从内核态切换回用户态 DMA gather和sendfile一样数据对用户空间不可见 而且需要硬件支持 同时输入文件描述符只能是文件 但是过程中完全没有CPU拷贝过程 极大提升了性能 产生2次DMA拷贝 没有CPU拷贝 而且也只有2次上下文切换