上篇文章介绍了RocketMQ的构成与消息发送方式,接下来我们继续RocketMQ的消费模式、事务消息与持久化。上一篇文章的链接:RocketMQ使用浅析(一)
RocketMQ消费方式
1.推模式
RocketMQ服务器主动给客户端推送消息,当客户端连接到服务器时,服务器会hold这个连接一段时间,这个时间如果有新消息到达,会通过hold的这个连接通道直接返回给客户端,消息推送非常及时,但是对于服务端的压力比较大
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumerGroup");
//设置namesrv地址
consumer.setNamesrvAddr("localhost:9876");
//订阅主题和标签
consumer.subscribe("TOPIC_TEST", "*");
//注册消息监听器
consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; //返回消费状态
});
consumer.start(); //启动消费者
2.拉模式
客户端通过长轮询主动去拉服务端的消息,可以自主控制消息的消费时间,RocketMQ服务端的压力会减轻
拉模式采用的DefaultMQPullConsumer来实现。
RocketMQ事务消息
RocketMQ的事务消息解决了,消息已发送出去,但是本地事务异常回滚,无法进行消息撤回的问题。
事务消息分为以下步骤
1.生产者向Broker发送半消息
2.所有半消息存储在固定Topic:RMQ_SYS_TRANS_HALF_TOPIC中,对于消费者不可见
3.服务端将消息持久化,并向生产者返回ACK确认发送成功
4.生产者执行本地事务,根据事务结果向服务器进行二次确认(commit或者rollback)
5.如果服务端收到为提交,就将半消息拷贝到原始队列中,等待消费者消费
6.如果服务端迟迟收不到二次确认,会返查生产者,查看消息的状态
TransactionMQProducer producer = new TransactionMQProducer("producer_group");
producer.setNamesrvAddr("localhost:9876");
// RocketMQ服务端消息返查
producer.setTransactionCheckListener(msg -> LocalTransactionState.COMMIT_MESSAGE);
producer.start();
// 消息内容
Message message = new Message("topic_name", "tag_name", "Transactional Message".getBytes());
// 本地事务
LocalTransactionExecuter executer = (msg, arg) -> {
return LocalTransactionState.COMMIT_MESSAGE;
};
//消息发送
producer.sendMessageInTransaction(message, executer);
消息如何持久化
1.当个Broker实例下,当生产者发送的消息内容,全部会写到一个日志数据文件来存储(commitlog)
2.当消息到达 commitlog 后,会采用异步转发到消息队列,也就是 consumerqueue,该文件夹下有三级目录:
第一级目录:topic命名的文件夹
第二级目录:MessageQueue 队列ID命名的文件夹
第三级目录: 具体的consumerQueue文件(该文件记录了,commitLog文件的位移offset,根据位移就能从commitLog找到具体的消息)
这样分层之后, RocketMQ 至少可以得到以下几个讯息:
- 2.1 先通过topic名称,可以定位到具体的文件夹;
- 2.2 然后根据消息队列ID找到具体的文件;
- 2.3 最后根据文件内容,或得位移offset,然后根据定位commitLog消息内容。