rocketmq使用文档
rocketmq-starter
- 快速接入RocketMQ
- 支持多数据源接入
- 支持普通消息,顺序消息,事务消息,重试消息,延时消息
- 支持集群模式,广播模式。
说明
(一)application.yml配置说明
参数名 | 含义 | 是否必填 |
---|---|---|
namesrv-addr | 注册中心地址 | 是 |
group-id | 消费组 | 消费者必须填写 |
access-key | 访问秘钥 | 否 |
secret-key | 访问秘钥 | 否 |
scope | 会做逻辑上的隔离,如果怕和别人topic冲突可以加上这个字段 | 否 |
message-model | CLUSTERING-集群消费模式,BROADCASTING-广播消费模式 | 否(默认集群模式) |
ordered | true-有序消息,false-无序消息 | 否(默认无序消息) |
ts | true-事务消息,false-普通消息 | 否(默认不开启分布式事务) |
consumer-retry-count | 消费者失败或超时重试次数 | 否(默认16次) |
(二)消息体支持的类型
参数名 | 含义 |
---|---|
JSON | Json |
String | 字符串(Json也可以用Json字符串方式) |
Binary | 二进制 |
Object | 对象 |
快速接入
前置准备
引入Maven依赖
<dependency>
<groupId>com.yichehui.framework</groupId>
<artifactId>ych-rocketmq-starter</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
应用场景:一个消费组,一个消息类型(普通消息/顺序消息/事务消息/广播消息)下,生产或消费一个或者多个Topic
(一)普通消息
(1)application.yml
ych:
mq:
rocket:
group-id: CONSUMER-GROUP #消费组
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #注册中心地址
consumer-retry-count: 1 #重试次数
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
(2)消息生产者
import com.yichehui.rocketmq.mq.producer.ProduceMessage;
import com.yichehui.rocketmq.mq.producer.Producer;
import com.yichehui.rocketmq.mq.producer.SendResultDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PushEnumController {
@Autowired
private Producer producer;
@GetMapping("/send")
public SendResultDetail send() {
String jsonString = "{\n" +
" \"msg\":\"hello\"\n" +
"}";
ProduceMessage message = ProduceMessage.fromString("wwwww", "", jsonString);
return producer.send(message);
}
}
此处ProduceMessage message = ProduceMessage.fromString(“wwwww”, “”, json);中的wwwww为Topic名,代表向wwwww这个Topic发送消息。 “” 为tag(rocketmq二级topic)此处为空,jsonString为发送的消息具体内容。
除了fromString之外还提供fromJSON,fromBinary,fromObject等不同类型的消息体格式
(3)消费者
import com.yichehui.rocketmq.mq.consumer.ConsumeMessage;
import com.yichehui.rocketmq.mq.consumer.MessageListener;
import org.springframework.stereotype.Component;
@Component
public class RocketmqMessageListener implements MessageListener {
// 只有多数据源情况才需要值
@Override
public String getId() {
return "";
}
// 监听的topic名
@Override
public String getTopic() {
return "wwwww";
}
// 只有有tag情况下才需要值
@Override
public String getTag() {
return "";
}
@Override
public void process(ConsumeMessage message) {
System.out.println("topic: => " + message.getTopic());
System.out.println("message: => " + message.getValueAsJson());
// 此处模拟异常,将会进行重试
int i = 1 / 0;
}
}
此处return “wwwww”;中的wwwww为Topic名,代表监听这个Topic
getValueAsJson代表以Json对象格式接收,除此之外也封装了其他类型、
int i = 1 / 0; 模拟抛出异常,由于consumer-retry-count: 1 所以会进行一次重试
(二)顺序消息
(1)application.yml
ych:
mq:
rocket:
group-id: CONSUMER-GROUP #消费组
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #注册中心
consumer-retry-count: 10 #重试次数
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
ordered: true #顺序消息需标注
(2)消息生产者
原理:同一个RocketMQ Queue消息有序;根据此处传的 shardingKey,SDK会对RocketMQ Queue数取余,不同shardingKey发送到指定RocketMQ Queue,
以下示例模拟8个用户"生成订单", “下单”, "支付"三个步骤,对于每个用户三个步骤有序
import com.yichehui.rocketmq.mq.producer.ProduceMessage;
import com.yichehui.rocketmq.mq.producer.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class Demo {
@Autowired
private Producer producer;
public void send() {
List<String> orderStep = Arrays.asList("生成订单", "下单", "支付");
for (int userId = 0; userId < 8; userId++) {
for (int j = 0; j <= 2; j++) {
ProduceMessage message = ProduceMessage.fromString("wwwww", "", "用户" + userId + orderStep.get(j));
message.setShardingKey(userId);
SendResultDetail sendResultDetail = producer.send(message);
System.out.println(sendResultDetail);
}
}
}
}
(2)消息消费者
import com.yichehui.rocketmq.mq.consumer.ConsumeMessage;
import com.yichehui.rocketmq.mq.consumer.MessageListener;
import org.springframework.stereotype.Component;
@Component
public class RocketmqMessageListener implements MessageListener {
@Override
public String getId() {
return "";
}
@Override
public String getTopic() {
return "wwwww";
}
@Override
public String getTag() {
return "";
}
@Override
public void process(ConsumeMessage message) {
System.out.println(message.getValueAsString());
}
}
(三)事务消息
RocketMQ 3.0.8 以及之前的版本支持分布式事务消息;
RocketMQ 3.0.8 之后删除分布式事务功能(付费商用:阿里云ONS服务);
RocketMQ 4.0.0 开始 apache孵化,但是也不支持分布式事务消息;
RocketMQ 4.3.0 开始支持分布式事务消息。
建议使用RocketMQ 4.7.1版本
回查时间间隔可以在RocketMQ Broker配置
事务消息QPS会降低
使用时需要指本地事务与事务回查逻辑
对于某个事务会有UNKNOW ,COMMIT,ROLLBACK 状态
本地事务UNKNOW或者无响应会触发回查逻辑,直到COMMIT(提交)或ROLLBACK (回滚)
(1)application.yml
ych:
mq:
rocket:
group-id: CONSUMER-GROUP #消费组
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #连接地址
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
ts: true #如果是事务消息需要添加
(2)消息生产者
import com.yichehui.rocketmq.mq.producer.ProduceMessage;
import com.yichehui.rocketmq.mq.producer.Producer;
import com.yichehui.rocketmq.mq.producer.SendResultDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PushEnumController {
@Autowired
private Producer producer;
@GetMapping("/send/{id}")
public SendResultDetail queryEnumList(@PathVariable Long id) {
ProduceMessage message = ProduceMessage.fromString("wwwww", "", "" + id);
return producer.send(message);
}
}
(3)消费者
import com.yichehui.rocketmq.mq.consumer.ConsumeMessage;
import com.yichehui.rocketmq.mq.consumer.MessageListener;
import org.springframework.stereotype.Component;
@Component
public class RocketmqMessageListener implements MessageListener {
@Override
public String getId() {
return "";
}
@Override
public String getTopic() {
return "wwwww";
}
@Override
public String getTag() {
return "";
}
@Override
public void process(ConsumeMessage message) {
System.out.println("topic: => " + message.getTopic());
System.out.println("message: => " + message.getValueAsString());
}
}
(4)本地事务与回查事务
import com.yichehui.rocketmq.mq.producer.YchTransactionListener;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class YchTransactionListenerImpl implements YchTransactionListener {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Override
public LocalTransactionState executeLocalTransaction(Message message, Object o) {
String sss = new String(message.getBody(), Charset.defaultCharset());
if ("1".equals(sss)) {
// new Date()为获取当前系统时间
String dateTime = df.format(new Date());
System.out.println("执行本地事务,模拟断电等异常" + dateTime);
return LocalTransactionState.UNKNOW;
} else if ("2".equals(sss)) {
// new Date()为获取当前系统时间
String dateTime = df.format(new Date());
System.out.println("执行本地事务,模拟本地事务失败" + dateTime);
return LocalTransactionState.ROLLBACK_MESSAGE;
} else if ("3".equals(sss)) {
String dateTime = df.format(new Date());
System.out.println("执行本地事务,模拟本地事务成功" + dateTime);
return LocalTransactionState.COMMIT_MESSAGE;
}
return LocalTransactionState.UNKNOW;
}
@Override
public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
String dateTime = df.format(new Date());
System.out.println("模拟第回查成功" + dateTime);
return LocalTransactionState.COMMIT_MESSAGE;
}
}
(四)延时消息
开源版本的RocketMQ中,对延迟消息并不支持任意时间的延迟设定(商业版本中支持),而是只支持18个固定的延迟级别
1到18分别对应messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h。
import com.yichehui.rocketmq.mq.producer.ProduceMessage;
import com.yichehui.rocketmq.mq.producer.Producer;
import com.yichehui.rocketmq.mq.producer.SendResultDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PushEnumController {
@Autowired
private Producer producer;
@GetMapping("/send/{id}")
public SendResultDetail queryEnumList(@PathVariable Long id) {
ProduceMessage message = ProduceMessage.fromString("wwwww", "", "" + id);
message.setDelayTimeLevelTime(1);
return producer.send(message);
}
}
(五)广播模式
广播模式先启动消费端后,任何实例都会被消费到
消费者只会监听启动之后收到的消息
(1)application.yml
ych:
mq:
rocket:
group-id: CONSUMER-GROUP #消费组
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #注册中心
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
message-model: BROADCASTING #广播模式
(2)消息生产者
import com.yichehui.rocketmq.mq.producer.ProduceMessage;
import com.yichehui.rocketmq.mq.producer.Producer;
import com.yichehui.rocketmq.mq.producer.SendResultDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PushEnumController {
@Autowired
private Producer producer;
@GetMapping("/send/{id}")
public SendResultDetail queryEnumList(@PathVariable Long id) {
ProduceMessage message = ProduceMessage.fromString("wwwww", "", "" + id);
return producer.send(message);
}
}
(3)消息消费者
import com.yichehui.rocketmq.mq.consumer.ConsumeMessage;
import com.yichehui.rocketmq.mq.consumer.MessageListener;
import org.springframework.stereotype.Component;
@Component
public class RocketmqMessageListener implements MessageListener {
@Override
public String getId() {
return "";
}
@Override
public String getTopic() {
return "wwwww";
}
@Override
public String getTag() {
return "";
}
@Override
public void process(ConsumeMessage message) {
System.out.println(message.getValueAsString());
}
}
应用场景:一个或多个数据源,一个或多个消费组,一个或多个消息类型(普通消息/顺序消息/事务消息/广播消息)下,生产或消费一个或者多个Topic
(六)多数据源
id为数据源,此处模拟两个数据源,rocket-source-1为数据源1,发送事务消息。rocket-source-2为数据源2,发送顺序消息。
(1)application.yml
ych:
mq:
rocket:
producers:
producer-list: #生产者
- id: rocket-source-1 #数据源1
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
scope: dev #逻辑隔离
group-id: CONSUMER-1 #消费者组
ts: true #事务消息
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #注册中心
- id: rocket-source-2 #数据源2
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
scope: dev #逻辑隔离
group-id: CONSUMER-2 #消费者组
ordered: true #顺序消息
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #注册中心
consumers: #消费者
consumer-list:
- id: rocket-source-1 #数据源1
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
scope: dev #逻辑隔离
group-id: CONSUMER-1 #消费者组
ts: true #事务消息
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #注册中心
- id: rocket-source-2 #数据源2
access-key: rocketmqak #秘钥ak
secret-key: rocketmqsk #秘钥sk
scope: dev #逻辑隔离
group-id: CONSUMER-2 #消费者组
ordered: true #顺序消息
namesrv-addr: 10.168.4.141:9876;10.168.4.143:9876 #注册中心
(2)生产者
Producer producer = producerAssist.getProducerById(“rocket-source-1”) 代表此处使用rocket-source-1的数据源,将会发送事务消息
import com.yichehui.rocketmq.mq.producer.ProduceMessage;
import com.yichehui.rocketmq.mq.producer.Producer;
import com.yichehui.rocketmq.mq.producer.ProducerAssist;
import com.yichehui.rocketmq.mq.producer.SendResultDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class PushEnumController {
@Autowired
private ProducerAssist producerAssist;
@GetMapping("/send1")
public SendResultDetail send1() {
Producer producer = producerAssist.getProducerById("rocket-source-1");
ProduceMessage message = ProduceMessage.fromString("rocket-source-1-topic", "", "hello-rocket-source-1");
return producer.send(message);
}
@GetMapping("/send2")
public SendResultDetail send2() {
Producer producer = producerAssist.getProducerById("rocket-source-2");
ProduceMessage message = ProduceMessage.fromString("rocket-source-2-topic", "", "hello-rocket-source-2");
message.setShardingKey(1);
return producer.send(message);
}
}
(3) 第一个数据源消费
如果想消费rocket-source-1的数据源getId里 return "rocket-source-1"即可
@Override
public String getId() {
return “rocket-source-1”;
}
import com.yichehui.rocketmq.mq.consumer.ConsumeMessage;
import com.yichehui.rocketmq.mq.consumer.MessageListener;
import org.springframework.stereotype.Component;
/**
* 第一个数据源消费
*/
@Component
public class RocketmqMessageListener implements MessageListener {
@Override
public String getId() {
return "rocket-source-1";
}
@Override
public String getTopic() {
return "rocket-source-1-topic";
}
@Override
public String getTag() {
return "";
}
@Override
public void process(ConsumeMessage message) {
System.out.println("topic: => " + message.getTopic());
System.out.println("message: => " + message.getValueAsString());
}
}
(4) 第二个数据源消费
import com.yichehui.rocketmq.mq.consumer.ConsumeMessage;
import com.yichehui.rocketmq.mq.consumer.MessageListener;
import org.springframework.stereotype.Component;
/**
* 第二个数据源消费
*/
@Component
public class RocketmqMessageListener2 implements MessageListener {
@Override
public String getId() {
return "rocket-source-2";
}
@Override
public String getTopic() {
return "rocket-source-2-topic";
}
@Override
public String getTag() {
return "";
}
@Override
public void process(ConsumeMessage message) {
System.out.println("topic: => " + message.getTopic());
System.out.println("message: => " + message.getValueAsString());
}
}