WhaleDI 消息队列稳定性提升实践
互联网电商企业中,其业务功能可能包含注册、订单、库存、物流......同时在这些业务过程中会涉及许多峰值时刻,如秒杀活动、周年庆、定期特惠等。这些活动都对分布性系统中的各项微服务应用的稳定性和处理性能带来很大的挑战,以最基础的注册流程为例:
传统处理方法
用户注册后,一般系统需要发送注册邮件和短信通知,以告知用户注册成功。通常的做法为:
只有以上三个任务(注册+邮件通知+短信通知)全部完成后,才返回注册结果到客户端,用户才能使用账号登录。假设每个任务耗时分别为 50ms,则用户需要在注册页面等待总共 150ms 才能登录。
同时由于注册系统强依赖于邮件和短信发送系统,一旦发送系统异常,注册系统将受到连锁影响,降低了系统的可用性。
使用了消息队列的异步解耦的处理方法
对于用户来说,注册功能实际只需要注册系统存储用户的账户信息后,该用户便可以登录,后续的注册短信和邮件不是即时需要关注的步骤。
对于注册系统而言,发送注册成功的短信和邮件通知并不一定要绑定在一起同步完成,所以实际当数据写入注册系统后,注册系统就可以把其他的操作放入对应的消息队列中然后马上返回用户结果,由消息队列 MQ 异步地进行这些操作。
由此,用户只需在注册页面等待注册数据写入注册系统和消息队列的时间,等待 55ms 即可登录。同时注册流程也不会受邮件系统和短信系统的可用性影响,从而提升了整体的稳定性。
稳定性提升实践
消息队列的应用场景非常丰富,在支持顺序消息、事务消息、延时消息,在削峰填谷、海量消息存储等方面都能起到重要的作用。但是往往越底层的应用,其稳定性要求也越高,作为应用之间连接的桥梁,一旦消息队列发生故障,整个业务系统都可能会瘫痪。
首先看下 WhaleDI-MQ 的高可用部署架构,其包含服务端组件和客户端组件两大部分,其中服务端组件包含 Namesrv、Broker 和 Zookeeper,客户端组件包含生产组 producer 和消费者 Consumer,架构如下图所示:
Namesrv 为无状态服务,是 WhaleDI-MQ 的注册中心,用于收集和更新路由信息;WhaleDI-MQ 通过部署多个 Namesrv 节点保障高可用,当一个 Namesrv 异常退出后,客户端能够自动重连到其他的 Namesrv 节点。
Broker 为实际对外提供消息发送和消费服务的节点,消息会轮询发送到各个主节点 Broker 中,主备之间通过同步双写保障数据的可靠性;单个 Broker master 节点异常时,备节点会自动切换为 master 节点,继续提供服务;当一组 Broker 的 master、slave 节点全部异常时,其他的 Broker 节点仍然可以提供服务,保证了服务的可用性。
WhaleDI-MQ 利用 ZK 特性监控 Broker 的主备状态,实现了 Broker 的自动切换功能。Zookeeper 自身采用多节点(奇数个)部署的方式,利用 ZAB 协议特性保证自身组件的高可用。
Producer 为生产者客户端,采用多节点集群部署模式,具备极强的扩展能力,某个 Producer 异常,不影响其它 Producer 节点发送消息。
Consumer 为消费者客户端,和 Producer 一样采用多节点集群部署模式,当某个 Consumer 节点异常时,WhaleDI-MQ 根据负载策略动态再平衡,重新调整队列路由。
下面,我们将从 Namesrv、Broker、异地容灾等几个方面给大家讲解稳定性提升实践。
01 Namesrv 稳定性提升
Namesrv 是 Rocketmq 的无状态注册服务,主要作用为:
作为 Broker 的注册中心,维护 Broker 的服务地址和路由信息
客户端通过 Namesrv 获取以及更新路由信息
Rocketmq 是通过部署多个 Namesrv 节点来保证高可用,每个 Namesrv 的节点维护的数据都是相同的,客户端初始化时仅会选择其中的一个 Namesrv 节点建立网络链接,若建链失败,则根据异常条件重新选择其他的 Namesrv 节点。
>>>>故障场景:
若连接的 Namesrv 节点 cpu hang 死,由于客户端已经和故障的 Namesrv 节点建立连接,因而不会再选择其他的 Namesrv 节点连接,由于当前的 Namesrv 故障,导致后续的路由更新、状态通知等全部超时失败,进而无法进行正常发送和消费消息,导致业务应用异常。
>>>>解决方案:
WhaleDI-MQ 增加了 Namesrv 链接自我检测机制,对于 netty 异常链接定期检测,若发现链接不可用则进行异常断链,重新选择其他的 Namesrv 进行连接。
>>>>应用成果:
即便客户端已经和故障的 Namesrv 节点建立了连接,但是若后续的路由获取、心跳上报等服务在一定时间内异常次数超过阈值,客户端依然会和当前的故障节点主动断链,重新选择其他正常的 Namesrv 节点。
02 Broker 支持主备模式自动切换
Rocketmq4.5 之前的版本 Broker 采用的是 M-S 的部署模式,主节点异常后,程序缺乏状态调度手段,必须人工介入才能进行主备切换,无法满足电信行业的高可用要求。
传统 M-S 部署方式消息写入模式如下:
Producer 客户端发送消息到 Broker master 节点
Master 节点同步写入到 Slave 从节点
Slave 通知 Maser 节点消息写入成功
Master 节点返回成功写入状态至消息客户端
Rocketmq 自 4.5 版本起引入了 Dledger 多副本框架,基于 raft 共识算法(分布式数据一致性协议 paxos),是一种强一致性、去中心化、高可用的分布式协议,确保集群中的每个节点都同意一系列相同的状态转换。
Leader 选举:Leader 异常或者服务初期启动,通过多数派共识算法,决策出主节点;数据同步:领导者确认后,由 Leader 接受客户端的请求,写入 node log(此时数据没有提交,因而不会更新节点数据),并同步到从节点,当收到多数的从节点应答后,更新本地数据,响应客户端数据写入成功,并通知其他的节点更新数据。
>>>>痛点描述:
利用 raft 的特性,Dledger 天然支持自动选主和切换,但是也正是由于多数派原则,防止脑裂风险,Broker 节点至少需要 3 副本,相较于原来的主备模式,至少需要额外增加一个 Broker 节点,增大了部署硬件资源的成本。
>>>>解决方案:
浩鲸科技 WhaleDI-MQ 引入 Zookeeper 协同主备状态控制,仍采用一主一备模式实现主从自动切换的能力,减少了部署的节点数,又满足了电信行业的高可用的要求。
由于 ZK 的作用仅仅为 Broker 主备状态控制,其资源占用非常少,可以和 Dubbo 或者其他的业务应用共用 zk,甚至可以将 zk 部署到 WhaleDI-MQ 的服务器上,从而节省了硬件部署资源。
>>>>应用成果:
WhaleDI-MQ 部署时仍采用一主一备的模式,利用 zk 做状态控制,就可以实现主备自动切换的功能,降低了消息组件部署的主机数量,给客户节省了成本。
03 异地容灾
>>>>痛点描述:
一般的消息队列只支持主备部署模式,即便采用异地部署,主备节点仍在一个大集群中,若异地距离比较远网络时延较大时,将极大的影响消息发送的性能,不满足浩鲸科技电信级商用项目的要求。若 MQ 部署在同一个机房中,一旦遭遇火灾、地震等不可抗力的灾难时,难以快速恢复消息服务,导致业务长时间中断,并可能丢失大量的业务消息。
>>>>解决方案:
WhaleDI-MQ 通过异地构建一套消息容灾集群,不间断地从主站点同步消息数据,当主节点遭受意外情况且系统无法恢复时,可以在两分钟之内将容灾集群切换为主站点集群,快速恢复业务,减少中断时长,从而降低客户的损失。
异地消息容灾集群能够自动感知主站点的 Broker 节点状态,并建立数据复制通道,即便主站点发生主备切换或者同步链路断开,容灾节点也能够根据名服务重新获取路由信息,建链续传。
容灾消息复制支持同步和异步两种数据复制模式,业务可以根据实际需要配置复制模式:
同步复制:保证数据零丢失;异步复制:容灾复制对主站点自身的消息写入服务影响比较小,数据复制会有稍许的延时(秒级)。
应用成果:WhaleDI-MQ 容灾站点可以在主站点异常不可用时,进行一键容灾切换,将容灾站点切换为主站点,快速地恢复服务。
04 消息发送稳定性提升
Producer 发送消息的时候,默认会轮询所有的 message queue 发送,以达到让消息平均落在不同的 queue 上。由于 queue 散落在不同的 Broker,所以消息就发送到不同的 Broker 上,如下图:
>>>>故障场景:
当 BrokerA 出现以下情况时:
BrokerA 磁盘阻塞或写入超时
生产者和 BrokerA 之间网络超时、丢包等
BrokerA cpu、内存等使用率超过 100%
由于发生上述故障时,BrokerA 的进程正常,并不会使 namesrv 剔除 BrokerA 的路由数据,导致每当消息发送轮询到故障 BrokerA 节点时便会发生超时(默认 5 秒),超时后客户端轮询到 BrokerB 节点则又正常发送消息,等下次再轮询到 BrokerA 节点时,又会触发 5 秒的超时,导致 tps 骤降,引起业务异常。
>>>>解决方案:
发送客户端引入故障熔断机制
资源隔离:单个 Broker 的异常不会影响其他 Broker 的消息发送
超时熔断:当前的 Broker 在一定的时间内超时达到了一定的次数,并执行服务降级,并使用异步的机制探测恢复的情况
失败熔断:当发送失败的调用次数达到一定阈值,如 system busy、io 满载等则自动降级,并使用进行异步机制探测恢复的情况
>>
应用成果:
BrokerA 故障期间,消息不再往故障节点发送消息,而是转而路由到其他正常的 Broker 节点,保证了消息发送的成功率。同时异步的检测故障节点的恢复情况,若节点恢复,则消息会重新往此节点发送。
05 服务节点自愈
>>>>痛点描述:
一般的消息服务组件不具备应用自愈的能力,当 MQ 部署主机异常重启时,需要人工介入,手动重启服务组件。从异常发生,到告警系统捕获到集群异常信息通知到运维人员,再到运维人员上线分析告警原因,逐个登录到 MQ 的各个主机上重启 Namesrv 和 Broker,往往至少需要耗费一个小时修复周期,导致在分秒必争的电信级生产环境中,给客户造成极大的损失。
>>>>方案描述:
WhaleDI-MQ 提供统一的健康状态监控+调度的功能,定时检查各个服务节点的运行情况,当检测到节点异常时,统一调度将会自动拉起故障节点。
>>>>应用成果:
利用统一调度功能,WhaleDI-MQ 的 Namesrv、Broker 和 ZK 皆具备了服务自愈的能力,进程异常退出后,无需人工介入,自动恢复消息服务组件,修复的时间由原来的至少 1 小时降低到 2 分钟;同时程序自愈的能力也降低了人工介入误操作的概率,保障了生产系统的安全。
实践总结
浩鲸科技具有数百个行业稳定落地的实践经验,同时基于 HATT 混沌工程,我们从网络、内存、IO、磁盘、cpu 等多个维度,编写了上百个测试用例,充分验证了 WhaleDI-MQ 稳定性能力,并对相关的不足点进行了优化提升,使得 SLA 可用性达到了 99.99%。
WhaleDI 分布式消息产品已经有效支撑了浩鲸科技众多电信级的项目平稳运行,全面助力客户应用数字化转型。随着业务应用云原生化的不断深入,需要 MQ 进一步加强产品的稳定性,如故障数据检查同步算法、磁盘坏道数据 mock、主容站点数据同步压缩加速、主备切换时长、客户端缩短感知等方面,针对这些场景,我们会继续深入技术研究,力争在未来企业应用的各种复杂场景下,更好地保障系统应用高效平稳运行。
版权声明: 本文为 InfoQ 作者【鲸品堂】的原创文章。
原文链接:【http://xie.infoq.cn/article/18e4621a4d1953538dd7e1b52】。文章转载请联系作者。
评论