title=

本文作者:黄理,快手在线消息系统负责人。

快手对于 RocketMQ 社区版本的优化一般为在其外层进行能力的构建,而不是对其内部进行大改动,因为内部大改不利于后期的版本升级。即使对内部 RocketMQ 进行了修改,我们也会尽量通过 PR 将新特性回馈到社区。

快手会定期对 RocketMQ 进行升级。2022年春节,我们大胆使用了尚未正式发布的 RocketMQ 4.9.3-SNAPSHOT 版本,平稳度过了快手一年中最重要的活动,这也证实了社区版本 RocketMQ 的兼容性和稳定性。

应用篇

 title=

RocketMQ 进入快手两年内,从 0 发展到每天数千亿消息级别。快手是 RocketMQ 社区版本的事务消息最早的大规模用户,目前每天有百亿以上的事务消息和定时消息,实现了跨 IDC的自动负载均衡以及容灾,实现了多级泳道(项目)互不干扰,多个项目可同时开发,以及可回落。

 title=

RocketMQ的落地方式一般为两种。

方式一:在开源软件的基础上进行修改,能够快速轻松地实现需要的功能,但后续升级存在很大不便。

方式二:对RocketMQ的 client 和 server 只进行少量修改。如果 server 存在能力缺失,会开发辅助的 server 或以 proxy 进行补充。我们在 client 之上包装了一层 MQ SDK,对用户屏蔽了具体实现。快手也是基于此方式对RocketMQ进行了落地。

 title=

MQ SDK如上图,分为三层:最上层为 API ,用户与该层打交道;中间为核心层,能够实现各种通用的能力;最底层负责与具体的 MQ 交互,当前只有 RocketMQ 的实现,但未来也许会有其他消息中间件的实现。

中间层实现了热变更的能力。用户配置不写在代码里,而是在平台进行指定,指定以后热生效,SDK 会直接加载新的配置并自动 reload 用户程序,无需重启。

 title=

RocketMQ 会分配 Logic topic,业务代码无需关心集群在哪,无需关心当前环境,也无需关心数据标记比如压测、泳道,只需使用我们提供的非常简单的 API ,复杂的过程全部在核心层进行封装,对业务用户屏蔽。

 title=

上图为跨机房负载均衡的实现流程。

所有Logic topic 都会映射到上图中间的两个机房,每个机房部署一个集群。RocketMQ 集群可以有多个 broker ,生产者和消费者对 broker 有故障感知和转移能力,能够通过 NameServer 发现哪个 broker 故障以避免与其进行连接。为了实现更好的控制,我们在集群之上又封装了一层负载均衡,并在 client 端实现。

每一个 Logic topic 都被分配到两个集群,生产者在生产时会同时连接到两个集群。两个集群分别位于不同 IDC,同一地区的两个IDC之间延时大约为1-2ms。消费者侧也是双连,一旦某机房或集群发生故障,流量会立刻自动转移到另一机房。

我们将生产端的自动负载均衡(自动failover)进行了抽象封装,做成了开源项目。Failover 组件与 RocketMQ 无关,在主调方做 RPC 或消息生产等调用时,会检查被调方的健康度。如果被调方不健康或响应很慢,则会调低其权重。

扫描上方二维码,了解更多关于该组件的功能。

 title=

RocketMQ 实现了简单的延迟消息,但是只能实现几个固定级别的延时,而实际的业务更希望发消息时可以任意指定延迟时间。因此我们通过外挂 Delay Server 的方式实现了任意精度的延迟消息。

Delay Server 会将用户要求延迟投递的消息进行保存,等到指定时间以后,再将消息送回原来的业务 topic 。

 title=

基于PULL的模式(RocketMQ的PUSH Consumer也是基于PULL),很难直接实现动态的多泳道隔离。因此很多公司会选择根据泳道的不同将消息投递到不同的 topic,这样虽然实现了功能,但是侵入性太强,并且也不好实现多级回落。

而在快手,我们将所有泳道的消费都放在同一个 topic 里,并且实现了多级泳道回落。比如项目 A 和项目 B 同时在开发,项目 A 生产的消息由项目 A 的消费者消费。项目 A 下面有子项目A.X和A.Y,那么A.X生产的消息由A.X的消费者消费,但是如果A.Y没有消费者,因此A.Y生产的消息会回落到由 A 的消费者进行消费。

 title=

快手的泳道隔离主要通过 RPC 转发实现。

如上图,黄色线代表项目 A 的数据流向,橙色线代表项目 B 的数据流向。SDK 会在将数据交给业务用户之前,先检查数据的泳道标记是否匹配,如果不匹配,则会通过 RPC 的方式转发至匹配的消费者。

这样我们等于是将 PULL 转为了 PUSH,在主调方进行选择,所以能够将所有项目放在同一个 topic 里,且能够实现隔离。

 title=

RocketMQ 是基于 queue 来进行客户端的 rebanance,如果消费者的数量大于queue,则会导致部分消费者无事可做;或有时 queue 分配不均匀,导致部分消费者负担大、部分消费者负担小。

我们通过RPC的方式实现了消费 Proxy,先从 RocketMQ 的 broker 消费数据,再通过 RPC 的方式  PUSH 到 consumer。

消费 proxy 的 RPC 与前文的 RPC 转发使用同一套机制,因此RocketMQ 不需要过多的 queue, 但可以有很多消费者。消费 proxy 为可选项,只需在平台指定消费方式,无需修改代码也无需重启,即可直接热生效。

 title=

此外,我们开发了拨测程序,生成了一个模拟的生产者和消费者。生产者会往线上所有集群的每一个 broker 发送消息,包括普通消息、定时消息和事务消息。消费者消费到消息后,会取出消息体内生产者的 IP 地址,然后通过 TCP 的方式 ACK 回生产者,告知生产者消息是否丢失、是否重复以及从生产到消费的延迟是多少。

另外,还可以针对生产者和消费者进行各种配置,比如消息体大小、生产速率、对账抽样比例、对账周期等。比如在配置中将速率调大,即可实现压测,生产者和消费者会进行打点,最终可在 Grafana 上进行查看和告警。

性能篇

对 RocketMQ 进行性能优化后,300字节小消息生产 TPS 提升54%,同时 CPU占用降低11%;600 queue消费性能提升200%,跨IDC 100KB大消息单线程生产 TPS 提升693%,跨IDC 100KB集群消费吞吐提升250%。

优化主要分为两批。

 title=

第一批优化集中在RocketMQ4.9.1版本,包括清除多余的日志、消除不必要的锁、消除主从复制中的数组拷贝、优化Broker的默认参数、优化锁内操作的性能并将部分操作抽取到锁外、优化消息属性编解码的性能以及优化消息Header解析的性能。扫描二维码可阅读本次优化相关的完整文章。

另外,RocketMQ 4.9.0版本的默认参数设置不合理,因此我们在4.9.1版本对其进行了优化,使得性能有了巨大提升。

 title=

上图为第二批优化的目标:

  • 降低 CPU 开销。RocketMQ 不消耗 CPU,但是在混合部署场景下,CPU 极有可能会成为问题,因此需要对 CPU 开销进行优化。 
  • 提升跨机房的生产、消费的吞吐。
  • 提升大消息的吞吐。
  • 提升queue特别多的场景下的消费性能。

第二批优化大部分集中在社区的ISSUE3585 里,扫描上方二维码可阅读完整文章。

 title=

上图为第二批优化CPU 方面的具体内容,字母编号与 ISSUE3585 相对应。此前RocketMQ 使用 Fastjson 做序列化,而有一个自定义的协议性能略微优于 Fastjson,我们对其进行了深入研究和优化,最终使得 RocketMQ 在编解码上性能也得到了很大提升。

 title=

RocketMQ 构建 Queue 的程序为单线程,因此我们使用mmap buffer 代替 FileChannel,性能得到了极大提高。

上图红框中为某方法优化前后对比。

 title=

此外,我们将 Pull 通知移动到另外的线程,使其不占用线程的资源。同时,将通知自动聚批,兼顾高吞吐和低延迟,只有 TPS 较高时才会自动打开,阈值可设置,避免 Pull 通知在 Broker 和消费者之间震荡频率过高,消耗 CPU。

 title=

大消息性能不佳也是一直以来很大的困扰,经过分析我们发现 RocketMQ remoting 的 TCP 参数设置有待优化。原先的buffer 设置为固定值,当机房延迟很大时,过小的 buffer 会导致 TCP 连接的吞吐受到严重影响。因此,我们将 buffer 修改为由操作系统自动管理,以保证吞吐。

上图列出了线上实测的数据表,可以看出消费的性能提升了数倍。

 title=

在极高的 TPS 场景下,如果消息体较大,则操作系统内存分配可能会成为 RocketMQ 的瓶颈,4.X 的内核下的表现远远优于 3 .X 。极端场景下,3.X内核通常需要将参数 min_free_kbytes 调至较大值。

 title=

我们于2021年12月社区开发者会议现场演示了性能测试,对比了第二批优化前后的4.9.2版本和4.9.3 Snapshot版本(包括当时还未合并进该版本的B和K的优化)的性能。

测试时,在电脑上同时运行所有 broker、生产者、消费者。老版本TPS不到 3w,而新版本有了自动聚批的能力,TPS 可达 6 w,相比于老版本提升了一倍。

加入 Apache RocketMQ 社区

十年铸剑,Apache RocketMQ 的成长离不开全球接近 500 位开发者的积极参与贡献,相信在下个版本你就是 Apache RocketMQ 的贡献者,在社区不仅可以结识社区大牛,提升技术水平,也可以提升个人影响力,促进自身成长。

社区 5.0 版本正在进行着如火如荼的开发,另外还有接近 30 个 SIG(兴趣小组)等你加​入,欢迎立志打造世界级分布式系统的同学加入社区,添加社区开发者微信:rocketmq666 即可进群,参与贡献,打造下一代消息、事件、流融合处理平台。

 title=

微信扫码添加小火箭进群

另外还可以加入钉钉群与 RocketMQ 爱好者一起广泛讨论:

 title=

钉钉扫码加群

关注「Apache RocketMQ」公众号,获取更多技术干货


阿里云云原生
1k 声望302 粉丝