本文作者:刘振东,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」公众号,获取更多技术干货