rocket 原生 API 使用
同步发送
生产者
// 创建一个生产者 (生产者组为 test-producer-group,生产者组不是那么重要)
DefaultMQProducer producer = new DefaultMQProducer("test-producer-group");
// 连接 name server
producer.setNamesrvAddr("127.0.0.1:9876");
// 启动
producer.start();
// 创建10个消息,消息将分摊到 4 个队列上 2-2-3-3
for (int i = 0; i < 10; i++) {
// 消息 Topic 为 testTopic
Message message = new Message("testTopic", "我是一个简单的消息".getBytes());
// 发送消息
SendResult sendResult = producer.send(message);
System.out.println("消息发送状态:" + sendResult.getSendStatus());
}
// 关闭生产者
producer.shutdown();
消费者
// 创建一个消费者(消费者组为 test-consumer-group)
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("test-consumer-group");
// 连接 name server
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅一个主题 * 标识订阅这个主题中所有的消息(可以根据 Tag 过滤)
consumer.subscribe("testTopic", "*");
// 设置一个监听器(MessageListenerConcurrently:并发模式)
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
// 全部内容有很多,包括消息头和消息体,消息体就是生产者发送的内容
System.out.println("消息全部内容" + msgs.get(0).toString());
System.out.println("消息体:" + new String(msgs.get(0).getBody()));
System.out.println("消费上下文:" + context);
// 返回值 CONSUME_SUCCESS 成功,消息会从 mq 出队
// 返回值 RECONSUME_LATER 失败, 消息会重新回到队列(默认消费重试16次)
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
// 启动
consumer.start();
异步发送
生产者
DefaultMQProducer producer = new DefaultMQProducer("async-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
Message message = new Message("asyncTopic", "我是一个异步消息".getBytes());
// 回调方法接收服务器响应,是异步的,不阻塞当前
producer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("发送成功");
}
@Override
public void onException(Throwable e) {
System.err.println("发送失败:" + e.getMessage());
}
});
producer.shutdown();
单向发送
生产者
DefaultMQProducer producer = new DefaultMQProducer("oneway-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
Message message = new Message("onewayTopic", "我是一个单向消息".getBytes());
// 单向,发完就不管
producer.sendOneway(message);
producer.shutdown();
批量发送
生产者
DefaultMQProducer producer = new DefaultMQProducer("batch-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
// 每个消息指定 Topic
List<Message> msgs = Arrays.asList(
new Message("batchTopic", "我是一组消息的A消息".getBytes()),
new Message("batchTopic", "我是一组消息的B消息".getBytes()),
new Message("batchTopic", "我是一组消息的C消息".getBytes())
);
// 同步发送一组消息(这是一次发送,这批次的消息会被放到一个队列上)
SendResult send = producer.send(msgs);
System.out.println(send);
// 关闭实例
producer.shutdown();
消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("batch-consumer-group");
consumer.setNamesrvAddr("127.0.0.1:9876");
consumer.subscribe("batchTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
// 会打印 3 次,虽然一次发送多个消息,但消费的时候还是一个一个来消费的
System.out.println("收到消息了" + new Date());
System.out.println(msgs.size());
System.out.println(new String(msgs.get(0).getBody()));
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
延迟消息
DefaultMQProducer producer = new DefaultMQProducer("ms-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
Message message = new Message("orderMsTopic", "我是一个延迟消息".getBytes());
// 给消息设置一个延迟时间,不同的延迟级别宝石不同的延迟时间
// messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"
message.setDelayTimeLevel(3);
producer.send(message);
System.out.println("发送时间" + new Date());
producer.shutdown();
顺序消息
- 因为消费者默认并发模式,也就是多线程,多线程是需要抢夺 cpu 调度权的,多线程天生不能保证顺序
- 就算改为单线程也不能保证顺序,假设 Topic 2 个队列,一个是空的一个有3条消息,消费者会轮询取消息
- 所以要保证顺序就需要满足两个条件:1,单线程模式消费;2,消息放到一个队列或 topic 只有一个队列
生产者
DefaultMQProducer producer = new DefaultMQProducer("orderly-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
// 发送一批消息,根据 msgModel.getOrderSn() 分组,每组消息放一个队列
msgModels.forEach(msgModel -> {
Message message = new Message("orderlyTopic", msgModel.toString().getBytes());
try {
// 第一个参数是消息,第二个参数是选择的具体队列,第三个参数是分组的 key
producer.send(message, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
// 哈希值取模是一个周期函数,保证每组消息轮询放到不同队列
int hashCode = arg.toString().hashCode();
int i = hashCode % mqs.size();
return mqs.get(i);
}
}, msgModel.getOrderSn()); // msgModel.getOrderSn() 会传到内部类的方法上
} catch (Exception e) {
e.printStackTrace();
}
});
producer.shutdown();
消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("orderly-consumer-group");
consumer.setNamesrvAddr("127.0.0.1:9876");
consumer.subscribe("orderlyTopic", "*");
// MessageListenerConcurrently 并发模式(多线程消费,消费失败默认重试16次)
// MessageListenerOrderly 顺序模式(单线程的,消费失败默认重试次数为 Integer.Max_Value)
consumer.registerMessageListener(new MessageListenerOrderly() {
@Override
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
System.out.println("线程id:" + Thread.currentThread().getId());
System.out.println(new String(msgs.get(0).getBody()));
return ConsumeOrderlyStatus.SUCCESS;
}
});
consumer.start();
带 Tag
生产者
DefaultMQProducer producer = new DefaultMQProducer("tag-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
// 指定 Tag 为 vip1
Message message = new Message("tagTopic", "vip1", "vip1消息".getBytes());
// 指定 Tag 为 vip2
Message message2 = new Message("tagTopic", "vip2", "vip2消息".getBytes());
// 发送这两个消息
producer.send(message);
producer.send(message2);
producer.shutdown();
消费者1
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("tag-consumer-group-a");
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅 tagTopic,只接收 tag 为 vip1 的消息
consumer.subscribe("tagTopic", "vip1");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
System.out.println("消费者1:" + new String(msgs.get(0).getBody()));
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
消费者2
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("tag-consumer-group-b");
consumer.setNamesrvAddr("127.0.0.1:9876");
// 订阅 tagTopic,只接收 tag 为 vip1 或 vip2 的消息(两个消息都会接收)
consumer.subscribe("tagTopic", "vip1 || vip2");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
System.out.println("消费者2:" + new String(msgs.get(0).getBody()));
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
带 Key
生产者
DefaultMQProducer producer = new DefaultMQProducer("key-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
String key = UUID.randomUUID().toString();
// topic、tag、key
Message message = new Message("keyTopic", "vip1", key, "我是带key的消息".getBytes());
producer.send(message);
producer.shutdown();
消费者
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("key-consumer-group");
consumer.setNamesrvAddr("127.0.0.1:9876");
// 不顾虑 tag
consumer.subscribe("keyTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
MessageExt messageExt = msgs.get(0);
System.out.println("消息主体:" + new String(messageExt.getBody()));
System.out.println("消息key:" + messageExt.getKeys());
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
重试
生产者
DefaultMQProducer producer = new DefaultMQProducer("retry-producer-group");
producer.setNamesrvAddr("127.0.0.1:9876");
producer.start();
// 发送失败重试次数
producer.setRetryTimesWhenSendFailed(2);
producer.setRetryTimesWhenSendAsyncFailed(2);
String key = UUID.randomUUID().toString();
Message message = new Message("retryTopic", "vip1", key, "我是一条重试消息".getBytes());
producer.send(message);
producer.shutdown();
消费者
/**
* 重试的时间间隔
* 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
* 默认重试16次还是失败就放入死信队列,死信队列的 Topic 为:%DLQ%消费者组名称,这里就是 %DLQ%retry-consumer-group
* 死信队列的消息处理为:写个订阅这个死信队列的消费者
*/
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("retry-consumer-group");
consumer.setNamesrvAddr("127.0.0.1:9876");
consumer.subscribe("retryTopic", "*");
// 设定消费者重试次数,一般业务3-5次消费不成功就要另外处理了,记录下来,也不用进死信队列
consumer.setMaxReconsumeTimes(16);
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
MessageExt messageExt = msgs.get(0);
// 重试次数
int times = messageExt.getReconsumeTimes();
if (times > 3){
// 3次都消费失败,记录下来,返回成功
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
// 业务处理,报错会视为消费失败消息重新回到队列
...
}
});
consumer.start();