rocketmq
RocketMQ
业务考量
- 削峰
- Producer->MQ 的吞吐量
- MQ-> Consumer的吞吐量
- 解耦
- 一对多的消息传递
启动
-
修改启动命令的Xms和Xmx
- bin/runserver.sh
- bin/ runbroker.sh
-
broker所在 机器配置指向namesrv的环境变量
export NAMESRV_ADDR='localhost:9876'
-
启动namesrv 和broker
- nohup bin/mqnamesrv &
- nohup bin/mqbroker &
-
测试发送和消费
#发1000条 bin/tools.sh org.apache.rocketmq.example.quickstart.Producer #SendResult [sendStatus=SEND_OK, msgId=C0A876B41AC3421104065E5F0A4B03E7, offsetMsgId=C0A876B400002A9F000000000003AFF0, messageQueue=MessageQueue [topic=TopicTest, brokerName=localhost.localdomain, queueId=2], queueOffset=249, recallHandle=null] #消费 bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer # ConsumeMessageThread_please_rename_unique_group_name_4_7 Receive New Messages: [MessageExt [brokerName=localhost.localdomain, queueId=3, storeSize=242, queueOffset=197, sysFlag=0, bornTimestamp=1781880486461, bornHost=/192.168.118.180:49648, storeTimestamp=1781880486462, storeHost=/192.168.118.180:10911, msgId=C0A876B400002A9F000000000002E87A, commitLogOffset=190586, bodyCRC=1116443590, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={CONSUME_START_TIME=1781880681810, MSG_REGION=DefaultRegion, UNIQ_KEY=C0A876B41AC3421104065E5F08BD0314, CLUSTER=DefaultCluster, MIN_OFFSET=0, TAGS=TagA, WAIT=true, TRACE_ON=true, MAX_OFFSET=250}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 55, 56, 56], transactionId='null'}]]
集群架构
普通集群
- NameServer集群
- 高可用
- Broker集群+主从
- 性能提升 + 备份
- 不具备高可用(一个broker宕机,消息全部进入其他broker)
- 集群规划
| 机器 | nameServer部署 | broker部署 |
|---|---|---|
| worker1 | nameServer | broker1,broker2-s |
| worker2 | nameServer | broker2,broker1-s |
| worker3 | nameServer |
Dledger集群
broker:leader+ follower
leader接受请求,转发到其他broker(follower)
测试:docker部署
| 机器 | nameServer部署(端口) | broker部署(端口) | dashboard |
|---|---|---|---|
| worker1 | nameServer (9877) | broker1(10911) | dashboard (18082) |
| worker2 | nameServer(9878) | broker2(10921) | |
| worker3 | nameServer(9879) | broker3(10931) |
-
配置
#1.为每个节点创建独立的docker挂载出的配置、数据、日志和存储目录。 # 创建根目录 mkdir -p /opt/rocketmq-dledger cd /opt/rocketmq-dledger # 循环创建 3 个 NameServer 和 3 个 Broker 的目录 for i in 1 2 3; do mkdir -p nameserver${i}/logs nameserver${i}/store mkdir -p broker${i}/logs broker${i}/store broker${i}/conf done #2.写broker.conf,配置dledger集群 #2.1 vi /opt/rocketmq-dledger/broker1/conf/ brokerClusterName = RaftCluster brokerName=RaftNode00 brokerIP1=192.168.118.180 listenPort=10911 namesrvAddr=192.168.118.180:9877;192.168.118.180:9878;192.168.118.180:9879 enableDLegerCommitLog=true dLegerGroup=RaftNode00 dLegerPeers=n0-192.168.118.180:10913;n1-192.168.118.180:10923;n2-192.168.118.180:10933 dLegerSelfId=n0 sendMessageThreadPoolNums=16 #2.2 vi /opt/rocketmq-dledger/broker2/conf/broker.conf brokerClusterName = RaftCluster brokerName=RaftNode00 brokerIP1=192.168.118.180 listenPort=10921 namesrvAddr=192.168.118.180:9877;192.168.118.180:9878;192.168.118.180:9879 enableDLegerCommitLog=true dLegerGroup=RaftNode00 dLegerPeers=n0-192.168.118.180:10913;n1-192.168.118.180:10923;n2-192.168.118.180:10933 dLegerSelfId=n1 sendMessageThreadPoolNums=16 #2.3 vi /opt/rocketmq-dledger/broker3/conf/broker.conf brokerClusterName = RaftCluster brokerName=RaftNode00 brokerIP1=192.168.118.180 listenPort=10931 namesrvAddr=192.168.118.180:9877;192.168.118.180:9878;192.168.118.180:9879 enableDLegerCommitLog=true dLegerGroup=RaftNode00 dLegerPeers=n0-192.168.118.180:10913;n1-192.168.118.180:10923;n2-192.168.118.180:10933 dLegerSelfId=n2 sendMessageThreadPoolNums=16 #3 执行以下命令,把所有 broker 和 nameserver 目录的所有权交给 UID 3000: cd /opt/rocketmq-dledger chown -R 3000:3000 ./broker1 ./broker2 ./broker3 ./nameserver1 ./nameserver2 ./nameserve -
- 创建docker-compose.yml
container_name: broker1
restart: always
ports:
- "10911:10911"
- "10911:10911/udp"
- "10912:10912"
- "10909:10909"
- "10913:10913"
volumes:
- ./broker1/logs:/home/rocketmq/logs
- ./broker1/store:/home/rocketmq/store
- ./broker1/conf/broker.conf:/home/rocketmq/rocketmq-5.5.0/conf/broker.conf
environment:
- JAVA_OPT_EXT=-server -Xms256m -Xmx256m
command: sh mqbroker -c /home/rocketmq/rocketmq-5.5.0/conf/broker.conf -n "192.168.118.180:9877;192.168.118.180:9878;19
2.168.118.180:9879"
depends_on:
- nameserver1
- nameserver2
- nameserver3
broker2:
image: apache/rocketmq:5.5.0
container_name: broker2
restart: always
ports:
- "10921:10921"
- "10921:10921/udp"
- "10922:10922"
- "10919:10919"
- "10923:10923"
volumes:
- ./broker2/logs:/home/rocketmq/logs
- ./broker2/store:/home/rocketmq/store
- ./broker2/conf/broker.conf:/home/rocketmq/rocketmq-5.5.0/conf/broker.conf
environment:
- JAVA_OPT_EXT=-server -Xms256m -Xmx256m
command: sh mqbroker -c /home/rocketmq/rocketmq-5.5.0/conf/broker.conf -n "192.168.118.180:9877;192.168.118.180:9878;192.168.118.180:9879"
depends_on:
- nameserver1
- nameserver2
- nameserver3
broker3:
image: apache/rocketmq:5.5.0
container_name: broker3
restart: always
ports:
- "10931:10931"
- "10931:10931/udp"
- "10932:10932"
- "10929:10929"
- "10933:10933"
volumes:
- ./broker3/logs:/home/rocketmq/logs
- ./broker3/store:/home/rocketmq/store
- ./broker3/conf/broker.conf:/home/rocketmq/rocketmq-5.5.0/conf/broker.conf
environment:
- JAVA_OPT_EXT=-server -Xms256m -Xmx256m
command: sh mqbroker -c /home/rocketmq/rocketmq-5.5.0/conf/broker.conf -n "192.168.118.180:9877;192.168.118.180:9878;192.168.118.180:9879"
depends_on:
- nameserver1
- nameserver2
- nameserver3
#=================================dashboard=====================
dashboard:
image: apacherocketmq/rocketmq-dashboard:latest
container_name: rocketmq-dashboard
restart: always
ports:
- "8082:8082"
environment:
- JAVA_OPTS=-Drocketmq.namesrv.addr=192.168.118.180:9877;192.168.118.180:9878;192.168.118.180:9879 -Dcom.rocketmq.sendMessageWithVIPChannel=false
volumes:
- /etc/localtime:/etc/localtime:ro
启动集群:
cd /opt/rocketmq-dledger
docker-compose up -d
查看日志:
docker-compose logs -f broker1
停止并清理集群(保留数据):
docker-compose down
Controller集群
DashBoard设置
Topic设置
- 类型:普通、FIFO、事务、延迟
- 队列数量
- perm:权限
ConsumerGroup设置
除了广播消费外,其他设置都以客户端ConsumerGroup配置为准
-
是否广播消费:(默认集群消费)
广播消费优先级最高。dashboard中和客户端中,任一配置为广播消费,则是广播消费。
- 集群模式下,消费offset由broker端管理,多个consumer共同消费
- 广播模式下,offset由consumer自行保管,每个consumer都消费所有消息
-
是否有序消费:(默认无序)
-
重试队列数量,默认1
-
最大重试次数,默认16
消息过滤
broker.conf 添加参数 enablePropertyFilter=true
-
简单过滤
生产者发送。设置tag consumer订阅topic时。subExpression中写规则, - “*” 所有 - “TAG1 || TAG3” 多个 -
sql过滤
生产者发送,设置Propperty consumer订阅时,添加 FilterExpression
消息机制
消息确认机制
//2.生产者->MQ
/*DefaultMQProducer.send方法
同步、异步 两种
SendResult中 sendStatus=SEND_OK表示发送成功
*/
public SendResult send(Message msg)
public void send(Message msg, SendCallback sendCallback)
//3.MQ->消费者
/*
DefaultMQPushConsumer.registerMessageListener监听中返回状态 进行消费确认。
MessageListenerOrderly和ConsumeConcurrently 串行和并行两种消费类型
ConsumeOrderlyStatus.SUCCESS 消费成功 SUSPEND_CURRENT_QUEUE_A_MOMENT 暂停队列拉取,一会进行重试
ConsumeConcurrentlyStatus.CONSUME_SUCCESS 消费成功 RECONSUME_LATER 稍后重新消费
*/
顺序消息机制
场景:有序事件处理、撮合交易、数据实时增量同步
- 相同消息组的消息按照先后顺序被存储在同一个队列。
- 不同消息组的消息可以混合在同一个队列中,且不保证连续
- 生产顺序性
- 单一生产者
- 串行发送
- 消息上设置相同消息组(MessageGroup),为了确保进入同一个MessageQueue
- 消费顺序性
- 投递顺序
- PushConsumer:按照存储顺序一条一条投递给消费者
- SimpleConsumer:消息消费的顺序性需要由业务方自行保证
- 使用MessageListenerOrderly
- 有限重试
- 投递顺序
定时消息
消息被发送至服务端后,在指定时间后才能被消费者消费
定时时长最大值默认为24小时,超过范围则定时不生效,服务端会立即投递消息
定时消息仅支持在 MessageType为**Delay **的主题内使用、
-
使用场景:
- 分布式定时调度(24h内)
- 任务超时处理
-
//设置定时推送到Consumer message.setDeliverTimeMs(timeMs); //设置延迟多久推送到Consumer 18种级别: 1s 5s 10s 30s 1min 2 3 4 5 ...1h 2h message.setDelayTimeLevel(3);//10s
批量消息
- 生产者批量发送
//维护一个messages,一次发送。
List<Message> messages;
//ListSplitter 为了将大List拆分
ListSplitter splitter = new ListSplitter(messages);
while (splitter.hasNext()) {
List<Message> listItem = splitter.next();
SendResult sendResult = producer.send(listItem);
System.out.printf("%s", sendResult);
}
事务消息机制
消息可靠性
消息不丢失
-
producer->MQ
- 同步发送+多次尝试:io降低
- 事务消息机制: 多次网络请求
-
Broker消息不丢失
- 同步刷盘:io负担
- DLedger集群:自动故障切换、极高数据可靠、写入性能较低、高网络IO
- Controller集群+同步刷盘:秒级自动故障切换、数据高可靠、写入性能接近原生主从、
-
MQ->consumer
- 同步处理消息,再提交offset
-
MQ集群挂了
- 增加临时降级存储
-
关注重试队列 和 死信队列,对死信队列单独唯独维护 消费者。
消息顺序性
- 生产顺序性
- 单一生产者
- 串行发送
- 消息上设置相同消息组(MessageGroup),为了确保进入同一个MessageQueue
- 消费顺序性
- 投递顺序
- PushConsumer:按照存储顺序一条一条投递给消费者
- SimpleConsumer:消息消费的顺序性需要由业务方自行保证
- 使用MessageListenerOrderly
- 有限重试
- 投递顺序
消息幂等性
- 生产者发送
- 发送消息时,自动分配唯一id。重试发送时,自己会校验
- 消费者消费
- 通过指定业务id作为key,判断是否已经消费过。
快速处理消息积压
-
判断消费卡点,有没有能优化的地方
-
5.x,加Consumer即可
-
4.x 加customer,但数量<=messagequeue,极端 情况下要 新建topic,创建多messagequeue,之后消费新topic中的
其他问题
- RocketMQ消费消息是推模式还拉模式
- 推模式:长轮训,拉取
- RocketMQ消息是如何存储的
- commitlog
- consumeroffsit
- indexFile
- RocketMQ生产环境如何优化
-
生产者
- 批量发送、异步发送
- 合理设置超时时间
-
消费者
- 增加消费线程数 setConsumeThreadMax/Min
- 批量消费 setConsumeMessageBatchMaxSize()
- 合理设置重试次数
-
Broker
- 增加Broker和MessageQueue数量
- 主从异步复制、异步刷盘
- 消费者设置长轮训
- jvm 堆内存大小,垃圾收集器选择G1
-
其他
- 消息存储优化:文件预热设置
- 监控告警
- 消息压缩 message.setCompressed(true);
-

浙公网安备 33010602011771号