资讯详情

从数据存储分析RocketMQ的高性能设计

前言

??RocketMQ高性能设计主要体现在数据存储、动态存储、动态伸缩和信息传输设计。动态扩展主要体现在队列扩展和集群扩展的能力上,新闻交付主要体现在其长轮查询设计(和nacos配置中心的长轮询问非常相似。你可以去那篇文章,主要是为了避免push模式对服务端的压力和pull浪费网络资源模式等缺陷)。本文主要关注数据存储。RocketMQ高性能的数据存储设计主要体现在四个方面:

1.前两个与硬盘上新闻数据的存储设计有关:顺序写盘和消费队列设计 2.后两个主要涉及系统中新闻数据的传输过程:新闻跳读和数据零复制设计

下面逐一分析:

顺序写盘

??要了解RocketMQ对于硬盘上数据的存储设计,首先要简单了解硬盘的结构,这里主要指机械硬盘。硬盘用于存储数据,数据实际上存储在硬盘中的磁盘上。当然,硬盘中不仅有一个磁盘,还有许多层磁盘堆叠在一起。磁头从磁盘上读取数据,有些磁盘可以存储在两个磁盘上,所以每个磁盘都有自己对应的磁头。切面大概是这样的: 机械硬盘

??数据实际上存储在磁盘上的一圈磁道中(磁性物质,通过改变磁极记录0和1)。整个硬盘的读写过程可能是:

1.传动轴将磁头定位到相应的磁道 2.电机旋转磁盘,将磁道上相应的读写区域(扇区)送到磁头下 3.通过磁头读写磁片上的数据。

??因此,要实现阅读和写作的第三步,我们必须经历前两步:搜索和旋转磁盘(主要消耗搜索,磁盘旋转非常快,家用机器一般可以达到7200转)。一般来说,磁头只会在磁盘上找到在磁盘上找到足够的空闲位置来存储当前的数据,完成后,再次写操作,导致一些看似合乎逻辑的数据,磁盘上的实际存储位置完全是全国性的,可以想象,在这种情况下,新闻数据读写过程,需要不断经历搜索,旋转磁盘的过程,一定要花很多时间。如何避免这样的时间消耗,这就是顺序写作的意义。

??顺序写盘是指一段数据写入磁盘的结束位置和下一段数据开始写入的位置是相邻的,所以磁头写完一个数据后,不需要再经历一个新的定位过程,只需要再写一个数据。同样,由于数据顺序,所有数据最终都会写在同一个磁道或几个相邻的磁道上,因此在读取数据时,磁头不需要移动或只在很小的范围内移动。大大节省了寻道时间,提高了数据的整体读写效率(实验证明,随机读写数据的速度只有几十几百KB每秒,顺序读写速度可以达到几十百MB,相差千倍,甚至超过了一般网卡的数据传输速度)。

??了解顺序写作的优势,那么RocketMQ如何实现顺序写盘?当RocketMQ成功部署运行后(至少发送一条信息){USER_HOME}中(可通过broker.conf修改),有/,有/store/commitlog文件夹,文件夹中可以看到一个名为0的文件(20位,命名规则稍后说),大小只有1G(默认),是的,RocketMQ刚运行,不管你的消息有多小,他都会直接在硬盘上创建一个1G空间的大小,之后所有的消息,不管Topic是什么?如果你不做任何分类,你会把它按顺序存储在这个文件中。如果你满了,创建一个1G这些文件是RocketMQ的CommitLog文件。因为直接创建1G因此,磁盘上的文件也是相应的,一次占G连续空间,RocketMQ就是这样提前占地,保证数据顺序记录在磁盘上。

消费队列设计

??顺序写盘使RocketMQ它节省了很多寻道时间,但很明显,这会导致另一个问题。数据是按顺序紧凑地写入磁盘的,但因为一切Topic消息消费者想要消费指定Topic当新闻数据出现时,是不是要一个一个?G检索大文件吗?这无疑会导致消费者信息性能差,吞吐量低。RocketMQ还有一个消费队列设计(先说这些队列文件也是按顺序写的,后面的介绍很容易看出来,就不提了,主要介绍队列设计)。

??还是和上面一起发现CommitLog在commitlog在相同的路径下,有一条路径consumequeue文件夹,进入后,可以看到自定义topic命名的文件夹,每个文件夹都有多个数字命名的文件夹,对应于多个消费队列,一个topic在某个broker默认情况下会有4个消费队列(顺序消息除外)。以后再说原因),同样,这些数字文件夹是一串0命名的文件,5.72M大小。

??简单地说,这些消费队列文件的存储过程就是当新闻写入时CommitLog文件之后,RocketMQ对应会异步topic的ConsumeQueue记录在消费队列文件中。但要说明,ConsumeQueue从消息队列文件CommitLog获取和存储的数据不是真实的新闻数据,主要有三个部分:CommitLog物理偏移量、消息大小消息哈希(用于过滤功能),因此消费队列中的每个消息对应的存储空间固定且非常小,每个消息固定20B,每个ConsumeQueue消费队列文件固定存储30万个数据,因此每个文件也固定6万个B(5.72M)。

??主要说偏移量,也涉及到前面提到的这些文件的命名规则数据存储的起始地址和CommitLog文件起始地址的差值,CommitLog文件的起始地址定义为0,以便在提取详细的信息数据时,可以通过偏移量直接定位数据CommitLog文件的偏移量总计,第二个文件的起始位置定义是前一个文件的延续,所以第二个CommitLog文件的起始位置定义为1G的数值1024X1024X1024=1073741824,这是这些文件的命名规则。文件的起始偏移量为0,向前补充20位,通过偏移量直接快速找到相应的文件,获取具体的消息内容。

??因此,消费实际上是通过topic定位读取ConsumeQueue消费队列文件等较小的文件,然后通过获取信息读取较大的文件CommitLog通过偏移量直接定位文件。

综上,RocketMQ硬盘上新闻数据存储设计的整体结构如下:

跳跃读取消息

??上面提到了硬盘上数据的存储,但是从硬盘上读取数据到发送给消息消费者的过程还有很多步骤,RocketMQ下面继续优化后续步骤。

??首先,在计算机系统中,cpu,内存、硬盘对数据的读写速度完全不同,并且存在指数级差异,因此为了在速度上折中,cpu内存、内存和硬盘之间会有缓冲空间,主要关注内存和硬盘之间的缓冲空间,直接访问硬盘的概率可以降低。

??RocketMQ在消费broker在获取信息时,需要先从硬盘中读取信息数据,然后尽量使用内存与硬盘之间的缓冲机制,减少直接访问硬盘的次数,RocketMQ检查缓冲中是否有需要读取的数据,然后根据数据是否存在采取不同的操作流程:

1.如果所需数据没有命中缓冲,RocketMQ从硬盘中读取相应的数据(按页面读取,页面大小通常为4k),然而,他不仅读取相应的数据,还读取当前数据(连续几页)后的一定数量的数据,一起读取缓冲空间中的数据,称为跳跃读取。 2.如果缓冲中有相应的数据,说明以前的缓冲是有效的,所以在RocketMQ在从缓冲中取回相应数据的同时,将继续从硬盘预读数据,以扩大缓存范围。

??从以上操作流程可以看出,如果数据是按顺序读取的,那么RocketMQ在消费新闻时,预读数据将继续从内存缓冲空间中读取,从而节省直接读取硬盘的时间。

数据零拷贝

??为了限制不同程序之间的访问能力,防止其他程序的内存数据或外围设备的数据,并发送到网络,操作系统对执行权限进行了分级,即核心状态和用户状态。内核状态可以访问内存中的任何地址,包括外围设备,如硬盘、网卡等,权限级别最高;与内核状态相比,用户状态只有较低的执行权限,只能访问有限的内存,许多操作不允许,如不允许访问有限的内存。

??以RocketMQ例如,作为一个应用程序,它具有较低的执行权限,通常只能在用户状态下运行,但为了读写存储在硬盘上的信息数据,并向消费者发送信息,RocketMQ我们确实需要做一些内核态的事情,比如硬盘读写、网络读写等。此时,我们需要切换用户态到内核态。但是,两种状态的相互切换是要耗时的(保存当前状态的执行情况,寄存器状态,栈指针修改等),比如JDK早期,synchronized系统会直接调用,用户态和内核态之间存在切换消耗问题。synchronized也叫重量级锁(1).6后优化)。

??一般情况下,应用程序从磁盘读取数据并通过网络传输,首先要调用到系统read方法,此时系统将从用户状态切换到核心状态,然后从磁盘读取数据到核心缓冲区,然后从核心缓冲区复制到用户缓冲区,同时切换到用户状态,应用程序通过用户缓冲区获取数据,可以呼叫到系统write该方法,系统将再次进入核心态,将数据从用户缓冲区复制到socket缓冲区最终通过网卡传输数据。当然,它最终会切换回用户状态并返回write结果。如图所示:

??而RocketMQ采用零拷贝的方式,这里提到的零拷贝,并非完全不拷贝,而是省略了一些拷贝的过程,零拷贝也分为多种,如mmap write,sendfile,sendfile DMA,RocketMQ选用了mmap write的方式,mmap也是读取数据的方法,但mmap和read的区别是,系统调用mmap当调用过程的虚拟地址空间创建新映射时,该映射将直接将内核缓冲区的数据映射到用户空间,从而节省从内核缓冲区复制到用户缓冲区的步骤。然而,系统仍然需要切换到用户状态并呼叫write但数据直接从内核缓冲区复制到socket缓冲区的其他步骤相似,如图所示: ??sendfile和sendfile DMA简单说一下,sendfile省去了中切到用户态一步,等于减少了两次状态切换,sendfile+DMA涉及到另一个概念,DMA拷贝和CPU拷贝,简单来说DMA拷贝允许不同速度的硬件装置沟通,而不需要依赖于CPU ,CPU拷贝则要占用CPU,当然越少越好。而内存缓冲区到socket缓冲区的拷贝过程正好是CPU拷贝(内核缓冲区到用户缓冲区再到socket缓冲区也是CPU拷贝),sendfile+DMA在这步,只拷贝了描述符、数据长度等少量数据,网卡在从socket缓冲区获取相关信息后,会直接通过DMA拷贝从内核缓冲区获取数据,减少了CPU占用。但是我们已经知道,上边所说的有关零拷贝过程中的很多步骤,其实都是操作系统进行操作的,对系统有一定的要求,mmap+write的方式显然更具有通用性。

标签: 磁片电容e221

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台