本文作者:刘振东,Apache RocketMQ PMC Member
RocketMQ基础介绍
RocketMQ的诞生是为了处理微服务解耦的问题。微服务解耦指将传统的巨大服务拆分为散布式的微服务。
拆分之后,发生了一个新的问题:服务之间需求进行通讯才干对外构成完好的服务。通讯方法分为两种:其一为RPC方法,也称为同步通讯;其二为异步通讯方法,比方RocketMQ。
RocketMQ的广泛运用证明异步通讯方法存在极大优势。最明显的特色即异步解耦,所谓解耦指一个服务不需求知道别的一个服务的存在。比方开发A服务,即使其他服务需求A服务的数据,A服务也并不需求知道它们的存在,不需求依赖其他服务的发布,其他服务的新增也不会对A服务造成影响,然后完结了团队的解耦,指一个微服务由一个特定的团队去完结,而其他团队并不需求知道该团队的存在,只需求依据事前约定的数据格式,通过RocketMQ完结异步通讯。这种安排方法大大促进了出产力的开展,天然也促进RocketMQ得到广泛应用。
在异步解耦进程中,有的组件出产音讯,有的组件消费音讯。RocketMQ的API model是其异步解耦进程的抽象概念。API model 的两端是RocketMQ范畴最典型的两个概念:其一为producer,指音讯的出产方或许数据出产方;其二为consumer,指音讯的消费方。
除此之外,topic也是API model的一个重要概念。由于异步解耦的需求,一条数据从producer发出到终究被consumer消费的进程并不是直接连接,中心有一个抽象层,这个抽象概念称为topic,相当于一个逻辑地址。topic就像一个仓库,当一条数据被发送到一个topic时,它会担任将音讯暂存,其他组件需求运用时能够拿取。
RocketMQ是一个散布式的音讯中心件,因而topic实质上是一个逻辑概念,真正的物理概念是散布在每一个broker上的行列,即message queue。一个topic能够具有许多message queue,能够散布在许多broker上,然后具有了无限扩展的才能,这是topic的一个根本特性。
此外,topic接纳音讯还有一个十分重要的特性,即音讯不可变。音讯的不可变特性使其能够被重复地读取。通过引入consumer group 的概念,能够看到不同组的消费者读取音讯的行为相互之间不会造成影响。Topic里的数据不会由于有consumer去读取而消失,可完结一处发送多处消费的才能。比方在一个安排内,订单团队发了一条音讯到订单topic,该安排内的其他一切团队都能够直接进行读取,且一个团队的读取并不会影响其他团队的读取,完结了读取的相互独立。
MQ的一个重要特性是异步解耦,在互联网的超大流量场景下,异步解耦之后往往会跟随着削峰填谷问题。为了完结削峰填谷,需求耐久化的才能。MQ是一个存储引擎,它能够暂存发送者的数据。假如消费者暂时无法处理,数据能够先堆积在MQ ,等到有满足的才能消费时再读取数据。
耐久化也更好地支撑了异步解耦的特性,即使consumer 悉数不在线也并不影响producer的发送。耐久化是MQ的一项重要才能。在耐久化才能里,为了合作顺序的特性,MQ的引擎是一个顺序存储的引擎。
RocketMQ规划时稍微有所不同,它将一切音讯集中式地存储,再依据不同的topic、不同的行列别离树立索引。这种规划是RocketMQ针对微服务场景特别优化的,它具有能够很好地支撑同步刷盘的才能,在海量Topic的场景下写入延迟依然能够保持平稳,这也是RocketMQ可与其他音讯引擎竞赛的重要特性。
流场景最初应用于用户行为剖析。用户行为剖析指依据用户的行为日志去猜测用户的喜爱。比方引荐体系的查找引荐广告等事务便是流场景最典型的场景。
流场景的第一步为将各个体系里发生的用户行为,包括日志、数据库记载等,集中导入到某些剖析引擎。进程中数据来源多,数据的剖析引擎也许多,包括离线引擎、实时引擎等。
为了降低复杂度,咱们引入了类似MQ的东西,使得数据源和数据运用者不直接交互,而是先将数据发送到MQ里,整个体系的连接复杂度会从O(N2)变为O(N),复杂度大大降低。
从用户行为或许流处理的视点剖析MQ扮演的人物以及它终究所期望的IT架构,能够发现其与微服务解耦的架构十分类似,两者之间的一切概念比方consumer、producer、topic、message queue、分片等,都能够一一对应。因而,假如只考虑RocketMQ的功用,它本身就能支撑流处理场景。
现在有许多公司在运用RocketMQ进行流处理,但RocketMQ在处理流处理问题时仍然存在可优化的空间。
Stream场景特征剖析
流处理的场景具有三个特色:
(1)单条音讯size很小:微服务解耦中,一条音讯一般便是一条订单,包括的数据十分多,买家、卖家等各种信息糅杂在一同发给下流,一条音讯一般会达到至少1KB乃至几KB。但在流场景里,数据类似于用户的行为日志,比方某个用户登录、某个用户下线、某个用户阅读某个页面等描绘。用户行为的表达很可能只占几个字节到100个字节。
(2)音讯数量许多:用户的阅读行为数量远远大于操作行为数量,全体音讯数量急剧增多。一般在微服务解耦场景中,单机不会超过10万TPS。可是在流场景或许日志收集等场景傍边,单机百万TPS很常见。
(3)Catch Up读常态化:在流场景中,常常有使命的replay,即读取历史数据再核算历史成果,也称为cache up read。相对于微服务解耦场景,catch up read在流场景中会更常见。
总而言之,在整个流场景里,吞吐变得愈加重要。
存储增强三步曲——批、分、合
RocketMQ起先为微服务解耦规划时,是面向单条记载,因而吞吐并不高。RocketMQ 5.0针对吞吐引入了一个新特性batch。
在传统RocketMQ里,一条音讯一条记载,一条音讯一条索引。这种传统规划的长处是能够保证延迟愈加稳定,但也意味着吞吐不高。由于通讯链路层的RPC次数太多,对CPU的耗费太大。因而,RocketMQ 5.0针对该问题,推出了batch功用。
Batch的根本逻辑是:在客户端自动组装,将多条音讯依照topic和行列兼并,作为一个恳求发送到服务端;服务端收到音讯一般不解压,而是直接存储;消费端一次拿下一批,将多个byte的音讯拿到本地,再进行解压。假如每个 batch包括10条音讯,TPS能够很轻松地上升10倍。本来一条音讯要发一次长途恳求,而参加batch后10条音讯发一次长途恳求即可。
由于服务端不进行解压,所以对服务端的CPU添加十分小,将解压和兼并的功用下放到各个客户端,然后使服务端资源不容易构成瓶颈,TPS能够很轻松地得到提高。
流场景中另一个典型问题是扩容和数据重均衡。在微服务场景中,流量不大的情况下,扩容问题并不明显。可是在流场景中,单机流量本来就高,一旦扩容,扩容和数据重均衡问题就难以疏忽。在扩容进程中,假如原先是一个node,需求扩容变成两个node,则会发生重均衡的问题。
为了处理该问题,一般有两个办法:
(1)直接添加行列的数量,即“Add a Shard”。这种方法会发生一个问题,行列的数量发生改变导致整个数据的散布也发生改变。比方做word count单词个数核算,本来A单词位于行列0,行列数发生改变之后,A单词位于行列2,核算的成果会呈现问题。因而假如添加行列个数,流核算使命需求重新运行一遍来批改数据。另一问题为分片数,假如每动一次就添加分片数,则会导致分片数量膨胀而且很难减少,这也会发生问题。
(2)不添加行列,可是仿制行列。比方本来行列1在node 0上,添加一个node 1,将行列1从node 0转移到 node 1,进程中行列数量没有发生改变,数据散布也没发生改变,因而客户端、发送端、消费端等流接纳使命都不需求重跑。此方法对用户很友爱,但也会带来一个新的问题:仿制进程会导致额定带宽耗费。在流场景中需求扩容的本质原因是机器的流量过高,可是为了将流量引走还需求新增一个仿制使命,在还未完结引流之前就给体系带来额定的功能耗费,可能会导致扩容的进程直接发生网络风暴,体系溃散。别的,仿制分区时,由于流核算使命的每个分片数据量很大,仿制进程耗时会很长。
因而选用仿制方法来处理大数据存储引擎的扩容其实很困难,可用性与可靠性难以权衡。
RocketMQ针对该问题提出了logic queue处理方案。logic queue是暴露给客户的行列,一个物理queue散布在一个node上,用于实践存储数据的行列。一个logic queue由多个物理queue通过位点映射组合而成。
位点映射的原理如下:假定LogicQueue-1由Queue-1和Queue-2组成,Queue-1包括0到100,Queue-2包括101到200,可映射成一个总位点是0到 200的LogicQueue-1。
上述情况下,只需修正映射关系,将逻辑行列修正到新node上的行列里,即可完结扩容。
写入时,新进的数据写入新节点,即完结了写入端的负载均衡。而读取进程有所不同,最新的数据会从本机读取,老数据会选用长途读取。
在流核算的整个生命周期中,数据在不断发生、不断地消费。因而在大多数情况下,假如没有发生堆积,长途读取的数量很小,简直能够瞬间完结,写入和读取都在新节点上,以此完结扩容。这种扩容有两个明显优势:其一是不需求转移数据;其二是分片数量不必发生改变。这也意味着上下流的客户端都无需重启,也不必发生改变,数据使命都是完好而正确的。
严格意义上来看,RocketMQ是一个流存储引擎。但RocketMQ 5.0推出了RocketMQ Streams——一个轻量级的流核算。
在RocketMQ Streams中,source 端是数据源头,中心有算子,最终数据会进入Sink端。一般它们都是有状况的,比方核算word count,每一条数据进来,一个新的单词呈现,首先要拿取过去数据的count值,加1后生成新的count值,这个中心的数据为状况村塾,一般称为state store。
State store的特征包括:
(1)本地化locality:一个轻量级的流核算假如要遵循高效的核算功能,一般需求本地化。本地化指将state store的数据和核算节点放在一同,至少要缓存到核算节点里。从state store里边取数据,就相当于从本地取数据,提高功能。假如每次读取state store都是长途读取,可想而知功能会明显下降。
(2)耐久化persistency:一旦灾难发生后,其他核算节点要能完好地读到state store。例如本来在A核算节点核算数据,A核算节点出问题后要到B核算节点核算,在B核算节点也需求康复出state store。
(3)可转移exchangeable:state store需求能便利地从一个体系搬到别的一个体系。比方算完word count,一个BI体系或许一个网站体系想测验感知到该改变,则需求将数据从state store转移到体系里。
针对以上三个特性,RocketMQ推出了一种新的topic,称为compacted topic。compacted topic的存储方法和运用方法和与正常topic 一样,唯一差异在于其服务端会将key相同的record删掉,进行规整。
比方图中本来offset=3的节点是K1V4,会覆盖之前的offset=0的K1V1和offset=2的K1V3,使最终只剩下一个K1V4。此规划的长处在于重新康复时需求读取的数据量十分少。
State store是一个NoSQL型的table,比方word count便是一个KV 结构,key是单词,count是单词呈现的个数,可是word count 在不断改变,需求将表转变成一个流,表发生的一切改变构成的数、记载的列表就构成了一个流,该进程称为流转,行将一个表转成一个流。RocketMQ能够通过以上方法轻松地将一张动态表存下来。
Compacted topic相当于一张动态表,且为流的形式,因而compacted topic是一种流表二象性的状况。这种特别的topic能够充当state store的存储层——一个耐久化层。
State store本身是表,且key和value不断改变。为了完结容灾的特性,需求将该表耐久化,将该表的一切修正记载构成一个流,存到RocketMQ的一个compacted topic,state store即相当于被耐久化。假如一个核算节点A溃散,B核算节点接收使命时,能够将topic以一般API的方法读出,再在本地康复state store,以此完结流核算使命的disaster recovery,即完结了容灾特性,能够协助RocketMQ构建一个轻量级、没有任何外部依赖的流核算引擎。
Batch、logic queue、compacted topic三个存储的根本特性,别离用于处理增强吞吐的问题、弹性的问题以及state store的问题。将三个存储特性进行结合,再合作RocketMQ Streams,能够构成一个轻量级的流核算处理方案。只需求RocketMQ和RocketMQ Streams,即可完结一个通用的流核算存储引擎。
RocketMQ 5.0从原先的微服务解耦转变为流存储引擎,原先的异步解耦、削峰填补等特性依然能够在新场景中充分得以运用。
此外,RocketMQ 5.0针对流存储的场景完结了三个严重特性的增强:其一是batch,可提高功能,将吞吐才能提高10倍;其二是logic queue,能够完结秒级扩容,而且无需转移数据,也无需改变分片数量;其三是针对流核算场景中所用state store完结了compacted topic。
通过增强,RocketMQ向流存储引擎开展的进程更进了一步。
参加 Apache RocketMQ 社区
十年铸剑,Apache RocketMQ 的成长离不开全球接近 500 位开发者的积极参与奉献,相信在下个版别你便是 Apache RocketMQ 的奉献者,在社区不只能够结识社区大牛,提高技能水平,也能够提高个人影响力,促进自身成长。
社区 5.0 版别正在进行着如火如荼的开发,别的还有接近 30 个 SIG(兴趣小组)等你参加,欢迎立志打造世界级散布式体系的同学参加社区,添加社区开发者微信:rocketmq666 即可进群,参与奉献,打造下一代音讯、事件、流融合处理平台。
微信扫码添加小火箭进群
别的还能够参加钉钉群与 RocketMQ 爱好者一同广泛评论:
钉钉扫码加群
重视「Apache RocketMQ」公众号,获取更多技能干货