当前位置:首页 > 公众号精选 > 架构师社区
[导读]在引入 RocketMQ 之前,快手已经在大量的使用 Kafka 了,但并非所有情况下 Kafka 都是最合适的。

作者:黄理,10 多年软件开发和架构经验,热衷于代码和性能优化,开发和参与过多个开源项目。曾在淘宝任业务架构师多年,当前在快手负责在线消息系统建设工作。

为什么建设在线消息系统



在引入 RocketMQ 之前,快手已经在大量的使用 Kafka 了,但并非所有情况下 Kafka 都是最合适的,比如以下场景:
  • 业务希望个别消费失败以后可以重试,并且不堵塞后续其它消息的消费。
  • 业务希望消息可以延迟一段时间再投递。
  • 业务需要发送的时候保证数据库操作和消息发送是一致的(也就是事务发送)。
  • 为了排查问题,有的时候业务需要一定的单个消息查询能力。

为了应对以上这类场景,我们需要建设一个主要面向在线业务的消息系统,作为 Kafka 的补充。在考察的一些消息中间件中,RocketMQ 和业务需求匹配度比较高,同时部署结构简单,使用的公司也比较多,于是最后我们就采用了 RocketMQ

部署模式和落地策略



在一个已有的体系内落地一个开源软件,通常大概有两种方式:

方式一:在开源软件的基础上做深度修改,很容易实现公司内需要的定制功能。但和社区开源版本分道扬镳,以后如何升级?
方式二:尽量不修改社区版本(或减少不兼容的修改),而是在它的外围或者上层进一步包装来实现公司内部需要的定制功能。
注:上图方式一的图画的比较极端,实际上很多公司是方式一、方式二结合的。 我们选择了方式二。最早的时候,我们使用的是 4.5.2 版本,后来社区 4.7 版本大幅减小了同步复制的延迟,正好我们的部署模式就是同步复制,于是就很轻松的升级了 4.7 系列,享受了新版本的红利。 在部署集群的时候,还会面临很多部署策略的选择:
  • 大集群 vs 小集群
  • 选择副本数
  • 同步刷盘 vs 异步刷盘
  • 同步复制  vs 异步复制
  • SSD vs 机械硬盘

大集群会有更好的性能弹性,而小集群具有更好的隔离型,此外小集群可以不需要跨可用区 /IDC 部署,所以会有更好的健壮性 。我们非常看重稳定性,因此选择了小集群。集群同步复制异步刷盘,首选 SSD。

客户端封装策略



如上所述,我们没有在 RocketMQ 里面做深度修改,所以需要提供一个 SDK 来实现公司内需要的定制功能,这个 SDK 大概是这样的:


对外只提供最基本的 API,所有访问必须经过我们提供的接口。简洁的 API 就像冰山的一个角,除了对外的简单接口,下面所有的东西都可以升级更换,而不会破坏兼容性。 业务开发起来也很简单,只要需要提供 Topic(全局唯一)和 Group 就可以生产和消费,不用提供环境、NameServer 地址等。SDK 内部会根据 Topic 解析出集群 NameServer 的地址,然后连接相应的集群。生产环境和测试环境环境会解析出不同的地址,从而实现了隔离。 上图分为 3 层,第二层是通用的,第三层才对应具体的 MQ 实现,因此,理论上可以更换为其它消息中间件,而客户端程序不需要修改。 SDK 内部集成了热变更机制,可以在不重启 Client 的情况下做动态配置,比如下发路由策略(更换集群 NameServer 的地址,或者连接到别的集群去),Client 的线程数、超时时间等。通过 Maven 强制更新机制,可以保证业务使用的 SDK 基本上是最新的。

集群负载均衡 & 机房灾备



所有的 Topic 默认都分配到两个可用区,生产者和消费者会同时连接至少两个独立集群(分布在不同的可用区),如下图:


生产者同时连接两个集群,如果可用区 A 出现故障,流量就会自动切换到可用区 B 的集群 2 去。我们开发了一个小组件来实现自适应的集群负载均衡,它包含以下能力:
  • 千万级 OPS

  • 灵活的权重调整策略

  • 健康检查支持/事件通知

  • 并发度控制(自动降低响应慢的服务器的请求数)

  • 资源优先级(类似 Envoy,实现本地机房优先,或是被调服务器很多的时候选取一个子集来调用)

  • 自动优先级管理

  • 增量热变更


实际上它并不仅仅用于消息生产者,而是一个通用的主调方负载均衡类库,可以在 Github 上找到: https://github.com/PhantomThief/simple-failover-java。
核心的 SimpleFailover 接口和 PriorityFailover 类没有传递第三方依赖,非常容易整合。

多样的消息功能


延迟消息

延迟消息是非常重要的业务功能,不过 RocketMQ 内置的延迟消息只能支持几个固定的延迟级别,所以我们又开发了单独的 Delay Server 来调度延迟消息:


上图这个结构没有直接将延迟消息发到 Delay Server,而是更换 Topic 以后存入 RocketMQ。这样的好处是可以复用现有的消息发送接口(以及上面的所有扩展能力)。对业务来说,只需要在构造消息的时候额外指定一个延迟时间字段即可,其它用法都不变。

事务消息

RocketMQ 4.3 版本以后支持了事务消息,可以保证本地事务和消费发送同时成功或者失败,对于一些业务场景很有帮助。 事务消息的用法和原理有很多资料,这里就不细述了。但关于事务消息的实践网上资料较少,我们可以给出一些建议。 首先,事务消息功能一直在不断完善,应该使用最新的版本,至少是 4.6.1 以后的版本,可以避免很多问题。 其次,事务消息性能是不如普通消息的,它在内部实际上会生成 3 个消息(一阶段 1 个,二阶段 2 个),所以性能大约只有普通消息的 1/3,如果事务消息量大的话,要做好容量规划。回查调度线程也只有 1 个,不要用极限压力去考验它。 最后有一些参数注意事项。在 Broker 的配置中:
  • transientStorePoolEnable 这个参数必须保持默认值 false,否则会有严重的问题。
  • endTransactionThreadPoolNums是事务消息二阶段处理线程大小,sendMessageThreadPoolNums 则指定一阶段处理线程池大小。如果二阶段的处理速度跟不上一阶段,就会造成二阶段消息丢失导致大量回查,所以建议 endTransactionThreadPoolNums 应该大于 sendMessageThreadPoolNums,建议至少 4 倍。
  • useReentrantLockWhenPutMessage 设置为 true(默认值是 false),以免线程抢锁出现严重的不公平,导致二阶段处理线程长时间抢不到锁。
  • transactionTimeOut 默认值 6 秒太短了,如果事务执行时间超过 6 秒,就可能导致消息丢失。建议改到 1 分钟左右。
生产者 Client 也有一个注意事项,如果有多组 Broker,并且是 2 副本(有 1 个 Slave),应该打开 retryAnotherBrokerWhenNotStoreOK,以免某个 Slave 出现故障以后,大量消息发送失败。

分布式对账监控



除了比较一些常规的监控手段以外,我们开发了一个监控程序做分布式对账。可以发现我们的集群以及我们提供的 SDK 是否有异常。


具体做法是在每个 Broker 上都建立一个监控专用的 Topic,监控程序使用我们自己提供的 SDK 框架来连接集群(就像我们的业务用户那样),监控生产者会给每个集群发送少量消息。然后检查发送是否成功:

发送成功

成功

刷盘超时

Slave 超时

Slave 不可用

发送失败

具体错误码


生产者只对这些结果进行打点,不判断是否正常,具体到监控(或者演练)场景可以配置不同的报警规则。 消费者收到了消息会通过 TCP 旁路 ACK 生产者,生产者这边会做分布式对账,将对账结果打点:
  • 收到消息
  • 消息丢失(或超时未收到消息)
  • 重复收到消息
  • 消息生成到最终消费的时间差
  • ACK 生产者失败(由消费者打点)
同样监控程序只负责打点,报警规则可另外配置。 这套机制也可以用于分布式性能压测和故障演练 。在做压测的时候,每个消息都 ACK 的话,对生产者的内存压力很大,因为它发出去的消息,需要在内存中保留一段时间(直到到达这个消息的对账时间),这段时间消费者 ACK 或者重复 ACK 都需要记录。所以我们实现了按比例抽样对账的功能,开启以后只有需要对账的消息才会在内存中保留一段时间。 顺便说一下,我们做压测时,合格的标准是异步生产不失败、消费不延迟、每一个消息都不丢失。这样做是为了保证压测时能给出更加准确的,可供线上系统参考的性能数字,而不是制造理想条件,追求一个大的数字。比如异步生产比同步生产更脆弱(压测 Client 如果同步生产,Broker 抖动的时候,同步 Client 会被堵塞导致发送速度降低,于是降低了 Broker 压力,消息发送不容易失败,但是会看到发送速率在波动),更贴近生产环境的实际情况,我们就选择异步生产来评估。

性能优化



Broker 默认的参数在我们的场景下(SSD、同步复制、异步刷盘)不是最优的,有的参数也许在大多数场景下都不是最优的。我们列出一些重要的参数,供大家参考:
参数 默认值 说明
flushCommitLogTimed False 默认值不合理,异步刷盘这个参数应该设置成 true,导致频繁刷盘,对性能影响极大。
deleteWhen 04 几点删除过期文件的时间,删除文件时有很多磁盘读,这个默认值是合理的,有条件的话还是建议低峰删除。
sendMessageThreadPoolNums 1 处理生产消息的线程数,这个线程干的事情很多,建议设置为 2~4,但太多也没有什么用。因为最终写 commit log 的时候只有一个线程能拿到锁。
useReentrantLockWhenPutMessage False 如果前一个参数设置比较大,这个最好设置为 true,避免高负载下自旋锁空转消耗 CPU。
sendThreadPoolQueueCapacity 10000 处理生产消息的队列大小,默认值可能有点小,比如 5 万 TPS(异步发送)的情况下,卡 200ms 就会爆。设置比较小的数字可能是担心有大量大消息撑爆内存(比如 100K 的话, 1 万个的消息大概占用 1G 内存,也还好),具体可以自己算,如果都是小消息,可以把这个数字改大。可以修改 Broker 参数限制 Client 发送大消息。
brokerFastFailureEnable True Broker 端快速失败(限流),和下面两个参数配合。这个机制可能有争议,client 设置了超时时间,如果 client 还愿意等,并且 sendThreadPoolQueue 还没有满,不应该失败,sendThreadPoolQueue 满了自然会拒绝新的请求。但如果 Client 设置的超时时间很短,没有这个机制可能导致消息重复。可以自行决定是否开启。理想情况下,能根据 Client 设置的超时时间来清理队列是最好的。
waitTimeMillsInSendQueue 200 200ms 很容易导致发送失败,建议改大,比如 1000ms。
osPageCacheBusyTimeOutMills 1000 Page cache 超时时间,如果内存比较多,比如 32G 以上,建议改大点。


总结

得益于简单、几乎 0 依赖的部署模式,使得我们部署小集群的成本非常低;不对社区版本进行魔改,保证我们可以及时升级;统一 SDK 入口方便集群维护和功能升级;通过复合小集群+自动负载均衡实现多机房多活;充分利用 RocketMQ 的功能,比如事务消息、延迟消息(增强)来满足业务的多样性需求;通过自动的分布式对账,对每一个 Broker 以及我们的 SDK 进行正确性监控。
本文也进行了一些性能参数的分享,但写的比较简单,基本只说了怎么调,但没能细说为什么,以后我们会另写文章详述。目前 RocketMQ 已经应用在公司在大多数业务线,期待将来会有更好的发展!


免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

业内消息,近日Alphabet旗下谷歌公司发言人表示为控制成本正在进行最新裁员,但具体人数不详。该发言人表示,裁员并非全公司范围,受影响的员工将能够申请内部职位,但没有具体说明受影响的员工人数或涉及的团队。

关键字: 谷歌 裁员

几天前,以南印度组织零售商协会(ORA)为代表的20多家零售连锁店和4300家商店宣布将从5月1日起停止销售一加设备。4月17日,全印度移动零售商协会(AIMRA)代表印度15万多家线下智能手机零售商通知一加,其成员正在...

关键字: 印度 一加 小米 Poco

业内消息,近日光刻机制造商阿斯麦(ASML)公布了2024年第一季度业绩,财报显示,该公司当季总净销售额53亿欧元,环比下降27%;毛利率51.0%,上季度为51.4%;净利润12亿欧元(当前约92.4亿元人民币),环比...

关键字: 光刻机 ASML

近日有韩媒称,由于薪资谈判破裂,劳资双方未能缩小对涨薪的意见分歧,三星电子全国工会(NSEU)即日起将发起公司成立以来首次集体行动,工会当天在华城市(Hwaseong)京畿道华城园区的组件研究大楼(DSR)前举行文化活动...

关键字: 三星

昨天上午,华为终端官微宣布全新重磅新机开售,约一分钟线上即告售罄,线下门店排起长队,气势丝毫不输苹果,和 Mate 60 Pro 一样没有发布会,这次官方同样推出了 “HUAWEI Pura 70 系列 先锋计划”,可以...

关键字: 麒麟芯片 华为

针对光伏优化器(MPPT)的非隔离DC-DC升压电路,推荐瑞森半导体低压MOS-SGT系列。极低导通电阻,低损耗,高雪崩耐量,高效率,非常适合高频应用。

关键字: 光伏优化器 MPPT

业内消息,近日东芝正在计划在日本裁员5000名员工,相当于日本员工总数的7%左右,这是其加速重组的最新举措。据知情人士透露,裁员的主要对象是总部的后勤部门,同时该公司将寻求员工自愿退休。

关键字: 裁员 东芝

昨天海能达发布公告,称针对产品禁售等判令提起的上诉结果已出:法院决定暂停执行一审法院对公司颁布的产品禁售令及罚款等,公司将与全球合作伙伴紧密合作,即刻恢复正常的商业活动并启动相关产品的销售。

关键字: 禁售令 海能达

业内消息,华为Pura 70第一批现货已到总代,部分经销商也已完成打款,等待华为打响开售“发令枪”。

关键字: 华为Pura 70 华为

业内消息,近日京东集团创始人、董事会主席刘强东以“采销东哥”AI 数字人开启直播首秀,同时亮相京东家电家居、京东超市采销直播间,不到1小时直播间观看量超2000万,并创造京东超市采销直播间开播以来观看人数的最高峰。

关键字: 京东 AI 数字人 刘强东 直播
关闭
关闭