前言
基于前两篇,RocketMq 学习 中文文档(一) RocketMq 集群搭建 部署 (2m-2s-async)我们已经了解了rocketmq的工作流程和集群搭建,本文介绍java接入的代码部分.下篇:顺序消息和事务消息
目录
1.生产者
2.消费者
3.演示一下master宕机:
4.消息重试:
5.广播消费
6.集群消费
正文
1.普通消费
依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.3.2</version>
</dependency>
1.生产者
/**
* 普通消息生产者
*
* @throws Exception
*/
@Test
public void test1() throws Exception {
//设置组名,并实例化
DefaultMQProducer producer = new
DefaultMQProducer("producerGroup1");
// 名称服务,分号分割
producer.setNamesrvAddr("192.168.229.5:9876;192.168.229.6:9876");
producer.start();
for (int i = 0; i < 10; i++) {
//消息实例
Message msg = new Message("topic1" /* Topic */,
"TagA" /* Tag */,
("Hello RocketMQ " +
i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
}
producer.shutdown();
}
- 发送消息是向2个节点的broker的master发送,发送使用默认的负载均衡机制,有的发向broker-a,有的发向broker-b
- 因为使用的主从结构,slave与master的消息同步
2.消费者
/**
* 普通消息消费者
* 采用的是Consumer Push的方式
*/
@Test
public void test2() {
//实例化消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumerGroup1");
consumer.setNamesrvAddr("192.168.229.5:9876;192.168.229.6:9876");
try {
//订阅topic1下的所有tag的消息
consumer.subscribe("topic1", "*");
//注册回调
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Consumer Started.%n");
while (true) {
}
} catch (MQClientException e) {
e.printStackTrace();
}
}
3.演示一下master宕机:
此刻默认是从master上消费,当master都健在时,一切正常.
此刻:把节点B的master停掉,master有一些消息未消费,则
停掉broker-b-master前(有几条消息未被消费):
停掉broker-b-master后: b节点只有一个slave(只能从此节点消费,不能发送了)
此刻发送10条消息测试,发现broker-b节点不再接收新消息,新消息全到master活着的A节点
启动一个消费者,消费topic1下的所有
可以看到,broker-b分片上的遗存的消息仍可被消费
主从方式保证了消息的高可用,现在是异步方式,会发生极少量消息丢失,如果业务是严格要求消息可用性,可使用同步刷盘,可靠性100%,性能相较异步略低,但也很高.
4.消息重试:
消息重试有两种,1.发送失败,2.消费失败
4.1发送失败
由于网络抖动,或其他因素导致发送失败,可以设置重试次数,在2000(超时时间范围内)
4.1消费失败
消息重试重要的功能在消费失败时,有两种失败情况:1.timeout,2.exception,rocketmq提供两种状态:1. CONSUME_SUCCESS 2. RECONSUME_LATER
1.timeout
当发生超时时,消费端会一直重试,直至成功
2.exception
当发生异常时,可以控制返回状态为CONSUME_SUCCESS 或RECONSUME_LATER,当返回RECONSUME_LATER时,broker会保留这条消息,而消费端会根据设置的次数进行重复消费,一般重试个3次就差不多了,有个重试策略,重试间隔时间越来越长: 10s、30s、1mins、2mins等,当超过次数后,需要额外处理失败的消息.
/**
* 普通消息消费者
*/
@Test
public void test4() {
//实例化消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumerGroup1");
consumer.setNamesrvAddr("192.168.229.5:9876;192.168.229.6:9876");
try {
//订阅topic1下的所有tag的消息
consumer.subscribe("topic1", "*");
//注册回调
consumer.registerMessageListener(new MessageListenerConcurrently() {
int count = 1;
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
try {
String body = new String(msgs.get(0).getBody(), "utf-8");
System.out.printf("%s Receive New Messages: %s %n", count++, msgs);
if ("Hello RocketMQ 3".equals(body)) {
if(msgs.get(0).getReconsumeTimes() ==4){
//TODO 超过最大重试次数后,应手动处理这条消息
}
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Consumer Started.%n");
while (true) {
}
} catch (Exception e) {
e.printStackTrace();
}
}
结果如下:
显然,同一条消息被消费了多次,时间间隔越来越长,业务中可根据重试的次数msg.getReconsumeTimes() 来保证消息失败时,应该手动管理这条消息了
5.广播消费
启动两个客户端即可
/**
* 普通消息消费者1
*/
@Test
public void test5() {
```此处省略代码```
//广播消费
consumer.setMessageModel(MessageModel.BROADCASTING);
```此处省略代码```
System.out.printf("consumer1: %s Receive New Messages: %s %n", count++, msgs);
```此处省略代码```
}
/**
* 普通消息消费者2
*/
@Test
public void test6() {
```此处省略代码```
//广播消费
consumer.setMessageModel(MessageModel.BROADCASTING);
```此处省略代码```
System.out.printf("consumer2: %s Receive New Messages: %s %n", count++, msgs);
```此处省略代码```
}
结果两个节点消费情况一样:
6.集群消费
同上,开两个消费端,消费模式改为集群 CLUSTERING,测试producer发10条消息,可以看到,consumer1+consume2两者共消费10条,各不重复,符合预期