一:RocketMQ简介
RocketMQ是分布式、队列模型的消息中间件, MetaQ 的 3.0 版本。
特点
数据可靠性
消费失败重试
严格的消息顺序
定时消息
消息查询
消息回溯
单机支持的队列数(5万)
支持push、pull两种方式消费消息
适用场景
应用解耦、流量削峰、异步处理、消息通讯
二:RocketMQ安装配置
安装jdk
安装RocketMQ
下载安装包如alibaba-rocketmq3.5.8.zip- Broker 集群部署方式
进入conf目录,提供以下几种broker部署方式:
2m-noslave
2m-2s-sync
2m-2s-async
- 启动namesrv
nohup sh mqnamesrv &
- 启动broker master
nohup sh mqbroker -n 172.16.8.106:9876 -c ../conf/2m-2s-sync/broker-a.properties &
- 启动 broker slave
nohup sh mqbroker -n 172.16.8.106:9876 -c ../conf/2m-2s-sync/broker-b.properties &
broker.properties文件关键配置:brokerName、brokerId、namesrvAddr、brokerRole
broker master与slave配对规则
7.关闭nameserver和所有的broker
sh mqshutdown namesrv
sh mqshutdown broker
nameserver监听9876端口,broker默认监听10911端口,启动前,先开放必要端口
三:web监控界面安装
四:RocketMQ的结构组成-多master多slave部署图
下面解读一下它们之间的关系:
- 1.NameServer互相独立,彼此没有通信关系,单台NameServer挂掉,不影响其他NameServer。NameServer不去连接别的机器,不会主动推消息。
- 2.单个broker(Master、Slave)与所有NameServer进行定时注册,以便告知NameServer自己还活着。Broker每隔30秒向所有NameServer发送心跳,心跳包含了自身的topic配置信息。NameServer每隔10秒,扫描所有还存活的broker连接,如果某个连接的最后更新时间与当前时间差值超过2分钟,则断开此连接。此外,NameServer也会断开此broker下所有与slave的连接。同时更新topic与队列的对应关系,但不会通知生产者和消费者。
Broker slave 同步或者异步从Broker master 上拷贝数据。 - 3.consumer随机与一个NameServer建立长连接,如果该NameServer断开,则从NameServer列表中查找下一个进行连接。
consumer主要从NameServer中根据topic查询broker的地址,查到就会缓存到客户端,并向提供topic服务的master、slave建立长连接,且定时向master、slave发送心跳。如果broker宕机,则NameServer会将其剔除,而consumer端的定时任务MQClientInstance.this.updateTopicRouteInfoFromNameServer每30秒执行一次,会将topic对应的broker地址拉取下来,此地址已经为slave地址了,故此时consumer会从slave上消费。 消费者与master和slave都建有连接,在不同场景有不同的消费规则。 - 4.Producer随机与一个NameServer建立长连接,每隔30秒(此处时间可配置)从NameServer获取topic的最新队列情况,这就表示如果某个broker
master宕机,producer最多30秒才能感知,在这个期间,发往该broker
master的消息将会失败。Producer会向提供topic服务的master建立长连接,且定时向master发送心跳。生产者与所有的master连接,但不能向slave写入。
客户端是先从NameServer寻址的,得到可用Broker的IP和端口信息,然后自己去连接broker。
(ps:我们在设计系统的时候,有一些全局使用的公用信息,可以单独独立一个模块进行专门的管理;各个子模块只需要定时向该模块更新信息即可。)
五:RocketMQ为什么使用nameserver?
NameServer在RocketMQ中所扮演的角色:
- NameServer 用来保存活跃的 broker 列表,包括 Master 和 Slave 。
- NameServer 用来保存所有 topic 和该 topic 所有队列的列表。
对于RocketMQ 来说,topic 的数据在每个 Master 上是对等的,没有哪个 Master 上有 topic 上的全部数据,所以对于zookeeper的Master 选举功能在Rocket中使用不到。
六:Producer
DefaultMQProducer
—>ClientCofig
--->MQProducer ->MQAdmin
TransactionMQProducer
—> DefaultMQProducer
提供多种方式发送消息的API
producer.send(msg, selector, arg, sendCallback, timeout);
producer.sendOneway(msg, selector, arg);
producer.sendMessageInTransaction(msg, tranExecuter, arg);
在执行producer start()方法时,最终调用的是DefaultMQProducerImpl的start()方法,TransactionMQProducer在调用DefaultMQProducerImpl的start()方法前会先调用DefaultMQProducerImpl.initTransactionEnv()方法初始化线程池。
DefaultMQProducerImpl真正的实现类
七:Consumer
DefaultMQPushConsumer
—>ClientConfig
-->MQPushConsumer—>MQConsumer-->MQAdmin
DefaultMQPushConsumerImpl真正的实现类
- 1.主题订阅
consumer.subscribe(topic, subExpression);
consumer.unsubscribe(topic);
- 2.注册监听
consumer.registerMessageListener(messageListener);
Listener 接口方法:
MessageListenerOrderly ->是有序的
MessageListenerConcurrently ->是无序的
new MessageListenerOrderly(){
public ConsumeOrderlyStatus consumeMessage(List<MessageExt >
msgs, ConsumeOrderlyContext context){
context.setAutoCommit(true);
return ConsumeOrderlyStatus.SUCCESS;
//将offset更新到本地,定时更新到broker
}
}
DefaultMQPullConsumer
—>ClientConfig
-->MQPullConsumer—>MQConsumer-->MQAdmin
DefaultMQPullConsumerimpl真正的实现类
方法:
consumer.fetchSubscribeMessageQueues(topic);
consumer.pull(mq, subExpression, offset, maxNums, pullCallback, timeout);
consumer.pullBlockIfNotFound(mq, subExpression, offset, maxNums, pullCallback);
consumer.updateConsumerOffset(mq, offset);
consumer.fetchConsumerOffset(mq, fromStore);
八:消息一致性
rocketmq的顺序消息需要满足2点:
- 1.Producer端保证发送消息有序,且发送到同一个队列。
SendResult sendResult = producer.send(msg, new MessageQueueSelector()
{
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg)
{
Integer id = (Integer) arg;
int index = id % mqs.size();
return mqs.get(index);
}
}, “AC0001”);
}
MessageQueueSelector实现:
SelectMessageQueueByRandoom、SelectMessageQueueByHash
- 2.consumer端保证消费同一个队列。
Consumer.registerMessageListener(new MessageListenerOrderly(){})
九:消息重复性
- 消费端业务操作保持幂等性
- 日志表(消费成功)
十:消息优先级
处于一个队列,可用整数来描述每条消息的优先级,在投递前先按优先级排好序,然后令优先级高的消息先投递。RocketMQ没有特意支持消息优先级,它的所有的消息都是持久化,如果按优先级排序,开销会非常大,可以通过变通方式实现类似功能,即不同优先级各对应一个队列,发送消息时根据优先级发送到与之对应的队列中。
十一:消息过滤
Broker端过滤-RocketMQ支持根据msgId、key、Header、body进行过滤。根据Message Key查询仅仅返回符合条件的最近64条数据,所以key值尽量唯一,并且有业务区分度。
十二:发送消息负载均衡
使用Roundbin方式,轮询发送消息,每个队列接收平均的消息量。也可以自定义选择发往哪个队列。