RocketMQ零拷贝原理

这篇具有很好参考价值的文章主要介绍了RocketMQ零拷贝原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 PageCache

●由内存中的物理page组成,其内容对应磁盘上的block。

●page cache的大小是动态变化的。

●backing store:cache缓存的存储设备。

●一个page通常包含多个block,而block不一定是连续的。

1.1读Cache

●当内核发起一个读请求时,先会检查请求的数据是否缓存到了page cache中。

如果有,那么直接从内存中读取,不需要访问磁盘,此即cache hit(缓存命中)

如果没有,就必须从磁盘中读取数据,然后内核将读取的数据再缓存到cache中,如此后续的读请求就可以命中缓存了。

●page可以只缓存一个文件的部分内容,而不需要把整个文件都缓存进来。

1.2写Cache

●当内核发起一个写请求时,也是直接往cache中写入,后备存储中的内容不会直接更新。

●内核会将被写入的page标记为dirty,并将其加入到dirty list中。

●内核会周期性地将dirty list中的page写回到磁盘上,从而使磁盘上的数据和内存中缓存的数据一致。

1.3 cache回收

●Page cache的另一个重要工作是释放page,从而释放内存空间。

●cache回收的任务是选择合适的page释放

如果page是dirty的,需要将page写回到磁盘中再释放。

2 cache和buffer的区别

(1) Cache:缓存区,是高速缓存,是位于CPU和主内存之间的容量较小但速度很快的存储器,因为CPU的速度远远高于主内存的速度,CPU从内存中读取数据需等待很长的时间,而Cache

保存着CPU刚用过的数据或循环使用的部分数据,这时从Cache中读取数据会更快,减少了CPU等待的时间,提高了系统的性能。

Cache并不是缓存文件的,而是缓存块的(块是I/O读写最小的单元);Cache一般会用在I/O请求上,如果多个进程要访问某个文件,可以把此文件读入Cache中,这样下一个进程获取CPU控制权并访问此文件直接从Cache读取,提高系统性能。

(2)Buffer:缓冲区,用于存储速度不同步的设备或优先级不同的设备之间传输数据;通过buffer可以减少进程间通信需要等待的时间,当存储速度快的设备与存储速度慢的设备进行通信时,存储慢的数据先把数据存放到buffer,达到一定程度存储快的设备再读取buffer的数据,在此期间存储快的设备CPU可以干其他的事情。

Buffer:一般是用在写入磁盘的,例如:某个进程要求多个字段被读入,当所有要求的字段被读入之前已经读入的字段会先放到buffer中。

3 HeapByteBuffer和DirectByteBuffer

HeapByteBuffer,是在jvm堆上面一个buffer,底层的本质是一个数组,用类封装维护了很多的索引(limit/position/capacity等)。

DirectByteBuffer,底层的数据是维护在操作系统的内存中,而不是jvm里,DirectByteBuffer里维护了一个引用address指向数据,进而操作数据。

HeapByteBuffer优点:内容维护在jvm里,把内容写进buffer里速度快;更容易回收。

DirectByteBuffer优点:跟外设(I0设备)打交道时会快很多,因为外设读取jvm堆里的数据时,

不是直接读取的,而是把jvm里的数据读到一个内存块里,再在这个块里读取的,如果使用

DirectByteBuffer,则可以省去这一步,实现zero copy (零拷贝)

外设之所以要把jvm堆里的数据copy出来再操作,不是因为操作系统不能直接操作jvm内存,而是因为jvm在进行gc (垃圾回收)时,会对数据进行移动,一旦出现这种问题,外设就会出现数据错乱的情况。

RocketMQ零拷贝原理,中间件,java-rocketmq,rocketmq,spring

所有的通过allocate方法创建的buffer都是HeapByteBuffer。

RocketMQ零拷贝原理,中间件,java-rocketmq,rocketmq,spring

堆外内存实现零拷贝

(1)前者分配在JVM堆上(ByteBuffer allocate()),后者分配在操作系统物理内存上

(ByteBuffer allocateDirect(),JVM使用C库中的malloc()方法分配堆外内存);

(2)DirectByteBuffer可以减少JVM GC压力,当然,堆中依然保存对象引用,fullgc发生时也会回收直接内存,也可以通过system.gc主动通知JVM回收,或者通过cleaner.clean主动清理。

Cleaner.create()方法需要传入一个DirectByteBuffer对象和一个Deallocator (一个堆外内存回收线程)。GC发生时发现堆中的DirectByteBuffer对象没有强引用了,则调用Deallocator的run()方法回收直接内存,并释放堆中DirectByteBuffer的对象引用;

(3)底层I/O操作需要连续的内存UVM堆内存容易发生GC和对象移动),所以在执行write操作时需要将HeapByteBuffer数据拷贝到一个临时的(操作系统用户态)内存空间中,会多一次额外拷贝。而DirectByteBuffer则可以省去这个拷贝动作,这是Java层面的“零拷贝”技术,在netty中广泛使用;

(4)MappedByteBuffer底层使用了操作系统的mmap机制,FileChannel#map(方法就会返回MappedByteBuffer。DirectByteBuffer虽然实现了 MappedByteBuffer,不过DirectByteBuffer默认并没有直接使用mmap机制。

4缓冲IO和直接IO

4.1缓存IO

缓存I/O又被称作标准I/O,大多数文件系统的默认I/O操作都是缓存I/O。在Linux的缓存I/O机制中,数据先从磁盘复制到内核空间的缓冲区,然后从内核空间缓冲区复制到应用程序的地址空间。

读操作:操作系统检查内核的缓冲区有没有需要的数据,如果已经缓存了,那么就直接从缓存中返回;否则从磁盘中读取,然后缓存在操作系统的缓存中。

写操作:将数据从用户空间复制到内核空间的缓存中。这时对用户程序来说写操作就已经完成,至于什么时候再写到磁盘中由操作系统决定,除非显示地调用了sync同步命令。

缓存I/O的优点:

(1)在一定程度上分离了内核空间和用户空间,保护系统本身的运行安全;

(2)可以减少读盘的次数,从而提高性能。

缓存I/O的缺点:

(1)在缓存I/O机制中,DMA方式可以将数据直接从磁盘读到页缓存中,或者将数据从页缓存直接写回到磁盘上,而不能直接在应用程序地址空间和磁盘之间进行数据传输。数据在传输过程中就需要在应用程序地址空间(用户空间)和缓存(内核空间)之间进行多次数据拷贝操作,这些数据拷贝操作所带来的CPU以及内存开销是非常大的。

4.2直接IO

直接IO就是应用程序直接访问磁盘数据,而不经过内核缓冲区,这样做的目的是减少一次从内核缓冲区到用户程序缓存的数据复制。比如说数据库管理系统这类应用,它们更倾向于选择它们自己的缓存机制,因为数据库管理系统往往比操作系统更了解数据库中存放的数据,数据库管理系统可以提供一种更加有效的缓存机制来提高数据库中数据的存取性能。

直接IO的缺点:如果访问的数据不在应用程序缓存中,那么每次数据都会直接从磁盘加载,这种直接加载会非常缓慢。通常直接IO与异步IO结合使用,会得到此较好的性能。

5内存映射文件(Mmap)

在LINUX中我们可以使用mmap用来在进程虚拟内存地址空间中分配地址空间,创建和物理内存的映射关系。

RocketMQ零拷贝原理,中间件,java-rocketmq,rocketmq,spring

 

映射关系可以分为两种

(1)文件映射磁盘文件映射进程的虚拟地址空间,使用文件内容初始化物理内存。

(2)匿名映射初始化全为0的内存空间。

而对于映射关系是否共享又分为

(1)私有映射(MAP. PRIVATE)多进程间数据共享,修改不反应到磁盘实际文件,是一个copy-on-write (写时复制)的映射方式。

(2)共享映射(MAP. SHARED)多进程间数据共享,修改反应到磁盘实际文件中。

因此总结起来有4种组合

(1)私有文件映射多个进程使用同样的物理内存页进行初始化,但是各个进程对内存文件的修改不会共享,也不会反应到物理文件中

(2)私有匿名映射mmap会创建一个新的映射,各个进程不共享,这种使用主要用于分配内存(malloc分配大内存会调用mmap)。例如开辟新进程时,会为每个进程分配虚拟的地址空间,这些虚拟地址映射的物理内存空间各个进程间读的时候共享,写的时候会copy-on-write。

(3)共享文件映射多个进程通过虚拟内存技术共享同样的物理内存空间,对内存文件的修改会反应到实际物理文件中,他也是进程间通信(IPC)的一种机制。

(4)共享匿名映射这种机制在进行fork的时候不会采用写时复制,父子进程完全共享同样的物理内存页,这也就实现了父子进程通信(IPC)。

mmap只是在虚拟内存分配了地址空间,只有在第一次访问虚拟内存的时候才分配物理内存。

在mmap之后,并没有在将文件内容加载到物理页上,只上在虚拟内存中分配了地址空间。当进程在访问这段地址时,通过查找页表,发现虚拟内存对应的页没有在物理内存中缓存,则产生"缺页",由内核的缺页异常处理程序处理,将文件对应内容,以页为单位(4096)加载到物理内存,注意是只加载缺页,但也会受操作系统一些调度策略影响,加载的比所需的多。

6直接内存读取并发送文件的过程

RocketMQ零拷贝原理,中间件,java-rocketmq,rocketmq,spring

 

7 Mmap读取并发送文件的过程

RocketMQ零拷贝原理,中间件,java-rocketmq,rocketmq,spring

 

8 Sendfile零拷贝读取并发送文件的过程

RocketMQ零拷贝原理,中间件,java-rocketmq,rocketmq,spring

 

零拷贝(zero copy)小结

(1)虽然叫零拷贝,实际上sendfile有2次数据拷贝的。第1次是从磁盘拷贝到内核缓冲区,第二次是从内核缓冲区拷贝到网卡(协议引擎)。如果网卡支持SG-DMA (The Scatter-Gather Direct Memory Access)技术,就无需从PageCache拷贝至Socket缓冲区;

(2)之所以叫零拷贝,是从内存角度来看的,数据在内存中没有发生过拷贝,只是在内存和I/O设备之间传输。很多时候我们认为sendfile才是零拷贝,mmap严格来说不算;

(3)Linux中的API为sendfile、mmap,Java中的API为FileChanel.transferTo().FileChannel.map()等;

(4)Netty、Kafka(sendfile)、Rocketmq (mmap)、Nginx等高性能中间件中,都有大量利用操作系统零拷贝特性。文章来源地址https://www.toymoban.com/news/detail-672824.html

到了这里,关于RocketMQ零拷贝原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 消息中间件-RocketMQ

            RocketMQ是阿里巴巴开源的消息分布中间件,在阿里内部使用非常更广泛,已经经过了“双11”这种万亿级的应用场景考验。 1.安装         下载地址:http://rocketmq.apache.org/release_notes/release-notes-4.4.0/         下载完成后解压缩安装包到指定目录。 2.配置    

    2024年02月09日
    浏览(44)
  • 中间件:RocketMQ安装部署

    下载 配置 broker.conf 的brokerIP1 为公网ip 启动命令: 查看集群状态 benchmark目录下

    2024年02月12日
    浏览(38)
  • 消息中间件系列 - RocketMQ

    本内容仅用于个人学习笔记,如有侵扰,联系删除 【尚硅谷】RocketMQ教程丨深度掌握MQ消息中间件_哔哩哔哩_bilibili 1 、MQ简介 MQ , Message Queue ,是一种提供 消息队列服务 的中间件,也称为消息中间件,是一套提供了消息生产、存储、消费全过程API的软件系统。消息即数据。

    2024年02月16日
    浏览(72)
  • 消息队列中间件 MetaQ/RocketMQ

    推荐电子书:云原生架构白皮书 2022版-藏经阁-阿里云开发者社区 (aliyun.com) 简介—— 消息队列中间件 MetaQ/RocketMQ 中间件 MetaQ 是一种基于队列模型的消息中间件,MetaQ 据说最早是受 Kafka 的影响开发的,第一版的名字 \\\"metamorphosis\\\",是奥地利作家卡夫卡的名作——《变形记》。

    2024年02月14日
    浏览(56)
  • 中间件上云部署 rocketmq

    Apache RocketMQ是一个分布式消息传递和流媒体平台,具有低延迟、高性能和可靠性、万亿级别的容量和灵活的可伸缩性。 发布/订阅消息传递模型 定期消息传递 按时间或偏移量进行消息回溯 日志中心流 大数据集成 在同一队列中可靠的FIFO和严格的有序消息传递 有效的拉伸消费

    2024年02月16日
    浏览(45)
  • 消息中间件之RocketMQ源码分析(十)

    启动命令 nohup ./bin/mqnamesrv -c ./conf/namesrv.conf dev/null 21 通过脚本配置启动基本参数,比如配置文件路径、JVM参数,调用NamesrvStartup.main()方法,解析命令行的参数,将处理好的参数转化为Java实例,传递给NamesrvController实例 加载命令行传递的配置参数,调用controller.initialize()方法初

    2024年02月20日
    浏览(56)
  • Kafka、RabbitMQ、RocketMQ中间件的对比

    消息中间件现在有不少,网上很多文章都对其做过对比,在这我对其做进一步总结与整理。     RocketMQ 淘宝内部的交易系统使用了淘宝自主研发的Notify消息中间件,使用Mysql作为消息存储媒介,可完全水平扩容,为了进一步降低成本,我们认为存储部分可以进一步优化,201

    2024年02月05日
    浏览(38)
  • 分布式消息中间件RocketMQ的应用

    所有代码同步至GitCode:https://gitcode.net/ruozhuliufeng/test-rocketmq.git 普通消息 消息发送分类 ​ Producer对于消息的发送方式也有多种选择,不同的方式会产生不同的系统效果。 同步发送消息 ​ 同步发送消息是指,Producer发出一条消息后,会在收到MQ返回的ACK之后才发下一条消息。

    2024年02月05日
    浏览(86)
  • 【消息中间件】RocketMQ消息重复消费场景及解决办法

    消息重复消费是各个MQ都会发生的常见问题之一,在一些比较敏感的场景下,重复消费会造成比较严重的后果,比如重复扣款等。 当系统的调用链路比较长的时候,比如系统A调用系统B,系统B再把消息发送到RocketMQ中,在系统A调用系统B的时候,如果系统B处理成功,但是迟迟

    2024年02月05日
    浏览(47)
  • 【消息中间件】详解三大MQ:RabbitMQ、RocketMQ、Kafka

    作者简介 前言 博主之前写过一个完整的MQ系列,包含RabbitMQ、RocketMQ、Kafka,从安装使用到底层机制、原理。专栏地址: https://blog.csdn.net/joker_zjn/category_12142400.html?spm=1001.2014.3001.5482 本文是该系列的清单综述,会拉通来聊一下三大MQ的特点和各种适合的场景。 目录 1.概述 1.1.M

    2024年02月09日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包