1.部署Rocketmq
1.1 配置安装
参考使用手册
1.1.1 修改配置
修改hosts
vim /etc/hosts
172.22.31.94 rocketmq-nameserver01
172.22.31.95 rocketmq-nameserver02
172.22.31.94 rocketmq-master01
172.22.31.95 rocketmq-master02
配置2master无slave
vim conf/2m-noslave/broker-01.properties
#所属集群名字
brokerClusterName=xdf-oc-t
#broker名字,注意此处不同的配置文件填写的不一样
brokerName=broker-01
#0 表示 Master,>0 表示 Slave
brokerId=0
#nameServer地址,分号分割
namesrvAddr=rocketmq-nameserver01:9876;rocketmq-nameserver02:9876
#在发送消息时,自动创建服务器不存在的topic,默认创建的队列数
defaultTopicQueueNums=64
#是否允许 Broker 自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
#是否允许 Broker 自动创建订阅组,建议线下开启,线上关闭
autoCreateSubscriptionGroup=true
#Broker 对外服务的监听端口
listenPort=10911
#删除文件时间点,默认凌晨 4点
deleteWhen=04
#文件保留时间,默认 48 小时
fileReservedTime=48
#commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
#ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
#destroyMapedFileIntervalForcibly=120000
#redeleteHangedFileInterval=120000
#检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
#存储路径
storePathRootDir=/neworiental/rocketmq/store
#commitLog 存储路径
storePathCommitLog=/neworiental/rocketmq/store/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/neworiental/rocketmq/store/consumequeue
#消息索引存储路径
storePathIndex=/neworiental/rocketmq/store/index
#checkpoint 文件存储路径
storeCheckpoint=/neworiental/rocketmq/store/checkpoint
#abort 文件存储路径
abortFile=/neworiental/rocketmq/store/abort
#限制的消息大小
maxMessageSize=65536
#flushCommitLogLeastPages=4
#flushConsumeQueueLeastPages=2
#flushCommitLogThoroughInterval=10000
#flushConsumeQueueThoroughInterval=60000
#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=ASYNC_MASTER
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=ASYNC_FLUSH
#checkTransactionMessageEnable=false
#发消息线程池数量
sendMessageThreadPoolNums=128
#发送消息是否使用可重入锁
useReentrantLockWhenPutMessage=true
#拉消息线程池数量
#pullMessageThreadPoolNums=128
需要以下两项配置,不然多线程发送报错:[TIMEOUT_CLEAN_QUEUE]broker busy, start flow control for a while
#发消息线程池数量
sendMessageThreadPoolNums=128
#发送消息是否使用可重入锁
useReentrantLockWhenPutMessage=true
1.1.3 修改启动脚本jvm参数
vim runbroker.sh; vim runserver.sh
1.2 启动服务
1.2.1 启动namesrv
94/95两台机器上分别启动
nohup sh mqnamesrv >/dev/null 2>&1 &
1.2.2 启动broker
94/95两台机器上分别启动
nohup sh mqbroker -c /neworiental/rocketmq/rocketmq-4.6.1/conf/2m-noslave/broker-01.properties >/dev/null 2>&1 &
nohup sh mqbroker -c /neworiental/rocketmq/rocketmq-4.6.1/conf/2m-noslave/broker-02.properties >/dev/null 2>&1 &
1.2.3 启动console
docker run -d --restart always --name rocketmq-console \
-e "JAVA_OPTS=-Drocketmq.namesrv.addr=172.22.31.94:9876;172.22.31.95:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false" \
-p 8080:8080 -t styletang/rocketmq-console-ng
2.压力测试
2.1 服务器配置
4台服务器配置 12c32g,2台mq,生产消费个1台;
2.2 模拟订单场景-严格顺序消息
2.2.1 配置简介
mq集群:两台机器部署,2m-noslave;2 namesrv;
顺序消息:单条消息模拟网报订单对象5k大小;
2.2.2 顺序消息
- Rocketmq 将消息路由到1台 broker,同一个orderId 的消息路由到同一个队列,从而保证顺序消息;但是无法利用多节点资源,通过配置多个 topic 路由到多个broker,充分利用多节点资源;
- 使用redis分布式锁 + 同一个订单根据订单号取模路由到同一个 topic 下的同一个 queue 保证顺序消息。
2.2.3 程序简介
- producer,100线程,4 topic;consumer,100线程,模拟入库耗时20ms;
- 设定100个线程,每个线程循环10000次,总共次数100w,与订单数量取模,保证订单数量小于等于2000。
- 每个订单操作的次数 orderUpdates = thread * circleCounts/orderCount=500次。
thread | circleCounts | orderCount | orderUpdates |
---|---|---|---|
100 | 10000 | 2000 | 500 |
2.2.4 操作步骤
--首先启动消费注册到namesrv
nohup java -jar amqp.jar --spring.profiles.active=ordered-rmq-c > consumer.log 2>&1 &
--后启动生产
nohup java -jar amqp.jar --spring.profiles.active=ordered-rmq-p > producer.log 2>&1 &
--删除order_code
redis-cli -h 10.202.80.118 -p 7921 -a do7l8KMbwuta keys "order_code*" | xargs -I {} redis-cli -h 10.202.80.118 -p 7921 -a do7l8KMbwuta del {}
redis-cli -a do7l8KMbwuta -h 10.202.80.118 -p 7921
--杀掉进程&删除日志
ps -ef|grep amqp | grep -v grep | awk '{print $2}'|xargs kill -9 && rm -rf *log*
-- 查看同一订单的顺序
cat logs/spring-rabbit/INFO/2020-03-13.log | grep order_code_0 > order_code_0
2.2.5 测试结果
(a) topic 下 64 queue
进程数量 | 生产消息tps | 消费消息tps | 2个broker/cpu | producer/cpu | consumer/cpu |
---|---|---|---|---|---|
1 | 8k+ | 5-6k | 2-3% | 40% | 10% |
2 | 10K+ | 6K+ | 2-3% | 55% | 15% |
(b) topic 下 128 queue
修改queue的数量,先控制台修改topic配置,然后程序修改topic配置
进程数量 | 生产消息tps | 消费消息tps | 2个broker/cpu | producer/cpu | consumer/cpu |
---|---|---|---|---|---|
1 | 8k+ | 5-6k | 2-3% | 38% | 10% |
2 | 10k+ | 8k+ | 2-4% | 55% | 18% |
© 小结:
-
增加生产进程,生产消息tps无明显提升,2个生产者时同一订单的并发量增加2倍,查看日志发现获取redis分布式锁的时间成几何倍数增加,所以生产消息无明显提升。
-
增加topic下queue的数量,理论上提高了并发度,测试发现消费消息tps提高2k,生产消息tps未提高,大部分耗时在获取redis分布式锁。
-
正常操作一般是下单、支付、撤单、转退班(XDF特有)、优惠重算(XDF特有)等几个动作,生产环境几乎不存在同一订单操作500次,理论上 tps 高于压测值。
2.2.6 arthas火焰图优化
- 启动arthas,开启火焰图
java -jar arthas-boot.jar
profiler start
profiler stop
- 火焰图分析
logback占比26%左右,Logger.info 占比20%,Logger.debug 占比 6%
- 程序分析
分别配置(20/100线程*10000次)发送订单消息,有无日志时间对比如下:
20发送线程,有/无日志打印对比,71s:58s,日志占比18.3%
100发送线程,有/无日志打印对比,144s:129s,日志占比10.4%
2.3 benchmark测试-并发消息
128线程,5k数据包
2.3.1 操作步骤
sh producer.sh -n 172.22.31.94:9876;172.22.31.95:9876 -w 128 -s 5000
sh consumer.sh -n 172.22.31.94:9876;172.22.31.95:9876
2.3.2 测试结果
进程/线程数量 | 生产消息tps | Average RT | Max RT | 消费消息tps | 2个broker/cpu | producer/cpu | consumer/cpu |
---|---|---|---|---|---|---|---|
1/128 | 50-60k | 1.2 | 298 | 50-60k | 15% | 11% | 13% |
2/128 | 60-80k | 1.6 | 1516 | 60-80k | 20-30% | 20% | 27% |