实战案例
RocketMQ集群线上故障缩容实战案例
背景
现有一套RocketMQ的四主集群,其中1台机器经常发生消息积压,其他3台相同配置的机器不会有积压。增加机器和消费者的处理方式,效果改善并不明显。进一步查看机器性能指标发现I/O等待居高不下,通过和IT部门沟通并最终确认,该机器存在硬件问题,是电池故障导致的,因此需要停机更换机器电池。
因为该集群属于核心系统,在正式线上操作之前需要在本地预先演练,同时为了让一线用户无感知,我们避开业务高峰期,定于夜间低峰期执行。(理论上可以在任何时间操作,但为了规避风险,选择业务低峰期操作。)
现状分析
线上RocketMQ集群采取四主的部署架构,并部署两台NameSrv,其具体信息如表11-52所示。

本次发生故障的机器IP为10.x.x.16。
操作步骤
(1)关闭目标Broker写权限
bin/mqadmin updateBrokerConfig -b 10.x.x.16:10935 -n
'10.x.x.16:9876;10.x.x.111:9876' -k brokerPermission
-v 4
出现update broker config success提示,表示10.x.x.16:10935指令执行成功。 这里需要注意如下内容。
1)将Broker的写权限关闭后,非顺序消息不会立即拒绝,而是等客户端路由信息更新后,不会再向该Broker发送消息。 2)updateBrokerConfig指令是针对broker.properties做在线修改,会在修改Broker内存参数的同时将最新的参数值同步写入broker.properties配置文件。 3)brokerPermission的可选值为2(只写权限)、4(只读权限)、6(读写权限)。我们在处理完毕后一定要记得开放写权限,否则会降低集群的生产消费能力。因为Broker关闭写权限之后,其对应的消费者并不会触发重平衡,导致关联到了只读Broker的这一部分消费者永远不能消费集群中的消息。
(2)节点下线
通过rocketmq-console或者执行mqadmin命令监测节点流量。观察InTPS和OutTPS流量,理想情况都为0且不再变化时,该节点就可以写下线了。
在rocketmq-console的查询界面如图11-51所示。

也可通过如下命令查询节点流量。
bin/mqadmin clusterList -n '10.x.x.16:9876;10.x.x.111:9876'
运维人员在关闭了Broker写权限之后等了半个小时,发现依然有100个左右的生产和消费TPS,导致他不敢继续操作,此时我们查看Broker全部队列情况,发现这个异常TPS来自重试队列。
我们可以通过如下操作判断流量来自哪些topic,效果如图11-52所示。
bin/mqadmin brokerConsumeStats -b 10.x.x.16:10935 -n
'10.x.x.16:9876;10.x.x.111:9876' >> broker16ConsumeS
tats.tmp_1//可隔几秒多拉取几次做对比

通过上面的命令主要是查看#LastTime和#Diff。发现%RETRY%重试类队列#Diff有部分数据,而其他topic均为0。LastTime也储存在%RETRY%队列中,这个数据证明了此Broker的确没有接收新的业务消息,也没有有效的业务消费了,此时可以让该节点下线操作。
(3)停止Broker
使用如下命令停止Broker。
ps -ef | grep broker
Kill pid
注意,这里不能使用kill -9命令强制关闭Broker进程。
观察console,发现节点已经成功下线,如图11-53所示,broker-2已经下线,目前只有3个broker实例在运行。

(4)关机换电池,验证硬盘 经运维人员确认,与同集群内另一台Broker所在的机器10.x.x.111做硬盘I/O效率对比,发现10.x.x.16写入效率较之前有了很大提升,甚至超越了其他Broker实例的机器,确认硬件问题已经解决,如图11-54所示,查看机器IOPS的读写效率,有大量数据读写,而且读写效率很高。 (5)启动NameSrv,启动Broker 执行如下命令启动NameSrv,启动Broker。
nohup bin/mqbroker -c /conf/broker-2.properties &
(6)开启读写权限

执行如下命令开启读写权限。
bin/mqadmin updateBrokerConfig -b 10.x.x.16:10935 -n
'10.x.x.16:9876;10.x.x.111:9876' -k brokerPermission
-v 6
观察各节点流量是否恢复正常,如图11-55所示,broker-2生产和消费TPS在4000左右,Broker集群也恢复为4个实例。

此时通过控制台发现broker-2重新加入集群,并且因为写权限重新开放,生产消费的TPS也逐渐恢复了。通过观察应用日志,我们发现在关闭NameSrv以及Broker时偶尔会报连接错误,后续逐步恢复正常。
RocketMQ在线扩容实战
背景
随着业务发展壮大,我们必然会面临一个问题,现有的RocketMQ服务集群性能不足以支撑当前的业务需求,急需扩容升级。现有的MQ服务投产使用中不能间断,这个时候在线(热)扩容就呼之欲出了,下面为大家分享一次在线扩容的实践。
以快递业务为例,每一个快件在运输的过程中都会经过很多中心、网点,也对应了很多状态的变化,每一次状态变化都会产生大量的操作数据,这些数据又是诸多业务系统必须输入的,因此我们需要一个前置系统接收所有数据的服务,再把数据分发给各业务系统。使用RocketMQ集群承担这些大数据量的接收任务,现有的集群结构(四主四从)如图11-56所示。

很快现有的四主四从集群就不能支撑了,此处补充性能不足的证据,扩容形式初步有两套方案,扩容到八主或者八主八从,最终决定了八主八从的方案,考量因素如下。
1)八主八从可以满足业务增长需求。 2)二主、四主四从扩容到八主八从可以实现动态无感知扩容,无须下线从节点,保证了线上应用的正常运行。 3)八主八从方案相比八主方案,当主节点宕机时从节点可以继续支撑消费,更好地保障了消息的实时性,部分业务也确实有这个需求。
扩容操作的集群架构演变如图11-57所示。
总体思路
1)搭建扩容的四主四从RocketMQ实例。 2)更改配置与之前节点保持一致。

3)从现有的Broker上复制${ROCKETMQ_HOME}/store/config/目录下的topics.json和subscriptionGroup.json文件到新的Broker服务器上。 4)启动扩容后的节点加入现有生产集群。
执行步骤
第一步:通知所有生产者和消费者应用负责人实时监控应用,及时发现和上报任何异常。 第二步:新加4台新服务器。 第三步:新加4台新服务器,Linux内核参数调优,调优脚本如下所示。
# 修改 /etc/sysctl.conf 文件
echo 'vm.overcommit_memory=1' >> /etc/sysctl.conf
echo 'vm.min_free_kbytes=5000000' >> /etc/sysctl.conf
echo 'vm.drop_caches=1' >> /etc/sysctl.conf
echo 'vm.zone_reclaim_mode=0' >> /etc/sysctl.conf
echo 'vm.max_map_count=655360' >> /etc/sysctl.conf
echo 'vm.dirty_background_ratio=50' >> /etc/sysctl.conf
echo 'vm.dirty_ratio=50' >> /etc/sysctl.conf
echo 'vm.page-cluster=3' >> /etc/sysctl.conf
echo 'vm.dirty_writeback_centisecs=360000' >> /etc/sysctl.conf
echo 'vm.swappiness=10' >> /etc/sysctl.conf
# 应用 sysctl 配置
sysctl -p
# 修改 /etc/profile 文件
echo "ulimit -n 655350" >> /etc/profile
# 修改 /etc/security/limits.conf 文件
echo "$USER hard nofile 655350" >> /etc/security/limits.conf
# 修改 I/O 调度器
echo 'deadline' > /sys/block/sda/queue/scheduler
# 检查 sysctl 配置
sysctl vm.overcommit_memory
sysctl vm.min_free_kbytes
sysctl vm.drop_caches
sysctl vm.zone_reclaim_mode
sysctl vm.max_map_count
sysctl vm.dirty_background_ratio
sysctl vm.dirty_ratio
sysctl vm.page-cluster
sysctl vm.dirty_writeback_centisecs
sysctl vm.swappiness
# 检查 ulimit 设置
su - root -c 'ulimit -n'
# 检查当前 I/O 调度器
cat /sys/block/sda/queue/scheduler
第四步:从生产者现有Broker上复制 ${ROCKETMQ_HOME}/store/config/
目录下的topics.json和subscriptionGroup.json文件到新Broker服务器上,以保证主题和消费组在新的实例内同步,注意扩容期间不进行主题和消费组的创建(线上环境是关闭自动创建主题和消费组的)。
第五步:启动4台新服务器并加入生产集群。
第六步:通知生产者和消费者在控制台观察消息是否分摊到新Broker上。
至此,在线扩容完成,需要注意评估好对业务的影响,做好通知工作以及兜底方案,确保在扩容过程中出现任何异常都能不影响当前业务的正常运转。