文章目录
pom文件添加依赖配置
<dependencies>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.6.1</version>
</dependency>
</dependencies>
简单demo
阻塞方式
Producer
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
public class Producer {
public static void main(String[] args) throws Exception {
DefaultMQProducer producer =new DefaultMQProducer("first");
//设置nameServer地址
producer.setNamesrvAddr("192.168.100.121:9876");
producer.start();
//发送topic 信息
Message msg1 = new Message("myTopic","first 第一条".getBytes());
Message msg2 = new Message("myTopic","first 第二条".getBytes());
Message msg3 = new Message("myTopic","first 第三条".getBytes());
//同步发送消息
SendResult sendResult1 = producer.send(msg1);
SendResult sendResult2 = producer.send(msg2);
SendResult sendResult3 = producer.send(msg3);
System.out.println(sendResult1);
System.out.println(sendResult2);
System.out.println(sendResult3);
producer.shutdown();
System.out.println("shut down");
}
}
SendResult [sendStatus=SEND_OK, msgId=C0A86477000001F6DC6132685A070000, offsetMsgId=C0A8647900002A9F00000000006ADA3B, messageQueue=MessageQueue [topic=myTopic, brokerName=localhost.localdomain, queueId=3], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=C0A86477000001F6DC6132685A9A0001, offsetMsgId=C0A8647900002A9F00000000006ADADD, messageQueue=MessageQueue [topic=myTopic, brokerName=localhost.localdomain, queueId=0], queueOffset=0]
SendResult [sendStatus=SEND_OK, msgId=C0A86477000001F6DC6132685A9F0002, offsetMsgId=C0A8647900002A9F00000000006ADB7F, messageQueue=MessageQueue [topic=myTopic, brokerName=localhost.localdomain, queueId=1], queueOffset=0]
shut down
Consumer
import java.util.List;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
public class Consumer {
public static void main(String[] args)throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("firstConsumer");
consumer.setNamesrvAddr("192.168.100.121:9876");
// 每个consumer 关注一个topic
// topic 关注的消息的地址
// 过滤器 * 表示不过滤
consumer.subscribe("myTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()));;
}
// 默认情况下 这条消息只会被 一个consumer 消费到 点对点
// message 状态修改
// ack
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.setMessageModel(MessageModel.CLUSTERING);
consumer.start();
System.out.println("Consumer 01 start...");
}
}
异步发送
AsyProducer.java
package oliver.simple;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
public class AsyProducer {
public static void main(String[] args) throws Exception{
DefaultMQProducer producer =new DefaultMQProducer("firstProducer");
//设置nameServer地址
producer.setNamesrvAddr("192.168.100.121:9876");
producer.start();
//发送topic 信息
Message msg1 = new Message("myTopic","first 第三条".getBytes());
//异步可靠发送消息//不用等着回馈,采用监听的方式
producer.send(msg1, new SendCallback() {
public void onSuccess(SendResult sendResult) {
// ack 确认机制
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
public void onException(Throwable throwable) {
System.out.println("抛出的异常-->"+throwable);
}
});
}
}
直接发送,有去,但不确认发送成功
SendOneWayProducer.java
package oliver.simple;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.exception.RemotingException;
public class SendOneWayProducer {
public static void main(String[] args) throws MQClientException, RemotingException, InterruptedException {
DefaultMQProducer producer =new DefaultMQProducer("firstProducer");
//设置nameServer地址
producer.setNamesrvAddr("192.168.100.121:9876");
producer.start();
//发送topic 信息
Message msg1 = new Message("myTopic","first 第一条".getBytes());
//单向消息,不确定是否发送成功,没监听
producer.sendOneway(msg1);
producer.shutdown();
System.out.println("shut down");
}
}
tag过滤发送及接收
TagProducer.java
package oliver.simple;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
public class TagProducer {
public static void main(String[] args) throws Exception{
DefaultMQProducer producer =new DefaultMQProducer("firstProducer");
//设置nameServer地址
producer.setNamesrvAddr("192.168.100.121:9876");
producer.start();
//发送topic 信息
//tag一般是做过滤的作用,key一般是跟业务做关联
Message msg1 = new Message("myTopic","tag-a","key-a","first 第三条".getBytes());
//异步可靠发送消息//不用等着回馈,采用监听的方式
producer.send(msg1, new SendCallback() {
public void onSuccess(SendResult sendResult) {
System.out.println(sendResult);
}
public void onException(Throwable throwable) {
System.out.println("抛出的异常-->"+throwable);
}
});
}
}
TagConsumer.java
package oliver.simple;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import java.util.List;
public class TagConsumer {
public static void main(String[] args)throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("firstConsumer");
consumer.setNamesrvAddr("192.168.100.121:9876");
// 每个consumer 关注一个topic
// topic 关注的消息的地址
// 过滤器 * 表示不过滤
consumer.subscribe("myTopic","tag-a");
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()));;
}
// 默认情况下 这条消息只会被 一个consumer 消费到 点对点
// message 状态修改
// ack
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.setMessageModel(MessageModel.BROADCASTING);
consumer.start();
System.out.println("Consumer tag 02 start...");
}
}
sql过滤接收
这里注意,broker的配置要更改
去到conf的配置文件里
在broker.conf
中添加配置
enablePropertyFilter=true
启动broker 加载指定配置文件
../bin/mqbroker -n 192.168.100.121:9876 -c broker.conf
SqlProducer.java
package oliver.simple;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
public class SqlProducer {
public static void main(String[] args)throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("xoxogp");
// 设置nameserver地址
producer.setNamesrvAddr("192.168.100.121:9876");
producer.start();
for (int i = 1; i <= 100; i++) {
Message message = new Message("myTopic003", ("xxooxx:" + i ).getBytes());
message.putUserProperty("age", String.valueOf(i));
SendResult send = producer.send(message);
System.out.println(send);
}
producer.shutdown();
System.out.println("已经停机");
}
}
SqlComsumer.java
package oliver.simple;
import java.util.List;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.MessageSelector;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
public class SqlComsumer {
public static void main(String[] args)throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("xxoo0TAG-B");
consumer.setNamesrvAddr("192.168.100.121:9876");
MessageSelector messageSelector = MessageSelector.bySql("age >= 18 and age <= 28");
consumer.subscribe("myTopic003",messageSelector );
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()));;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.setMessageModel(MessageModel.CLUSTERING);
consumer.start();
System.out.println("Consumer sql-filter start...");
}
}
发送延迟设置
RocketMQ使用messageDelayLevel可以设置延迟投递
默认配置为
messageDelayLevel 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
配置
在broker.conf
中添加配置
messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
这个配置项配置了从1级开始,各级延时的时间,可以修改这个指定级别的延时时间;
时间单位支持:s、m、h、d,分别表示秒、分、时、天;
使用
发送消息时设置
message.setDelayTimeLevel(1);
保证顺序发送,且顺序消费
队列先天支持FIFO模型,单一生产和消费者下只要保证使用MessageListenerOrderly
监听器即可
顺序消费表示消息消费的顺序同生产者为每个消息队列发送的顺序一致,所以如果正在处理全局顺序是强制性的场景,需要确保使用的主题只有一个消息队列。
并行消费不再保证消息顺序,消费的最大并行数量受每个消费者客户端指定的线程池限制。
那么只要顺序的发送,再保证一个线程只去消费一个队列上的消息,那么他就是有序的。
跟普通消息相比,顺序消息的使用需要在producer的send()方法中添加MessageQueueSelector接口的实现类,并重写select选择使用的队列,因为顺序消息局部顺序,需要将所有消息指定发送到同一队列中。
保证有序参与因素
- FIFO
- 队列内保证有序
- 消费线程
ProducerSelectQueue.java
发送到固定query里面
package oliver;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import java.util.List;
public class ProducerSelectQueue {
public static void main(String[] args)throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("pgp01");
producer.setNamesrvAddr("192.168.100.121:9876");
producer.start();
for (int i = 0; i < 20; i++) {
Message message = new Message("xxoo007", ("hi!" + i).getBytes());
producer.send(
// 要发的那条消息
message,
// queue 选择器 ,向 topic中的哪个queue去写消息
new MessageQueueSelector() {
// 手动 选择一个queue
public MessageQueue select(
// 当前topic 里面包含的所有queue
List<MessageQueue> mqs
,
// 具体要发的那条消息
Message msg
// 对应到 send() 里的 args
, Object arg) {
// TODO Auto-generated method stub
// 向固定的一个queue里写消息
MessageQueue queue = mqs.get(0);
// 选好的queue
return queue;
}
},
// 自定义参数
0, 2000);
}
// producer.shutdown();
System.out.println("已经停机");
}
}
ComsumerSelectQueue.java
接收,线程数设置为1,代码注释为开启多个线程
package oliver;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeOrderlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerOrderly;
import org.apache.rocketmq.common.message.MessageExt;
import java.util.List;
public class ComsumerSelectQueue {
public static void main(String[] args)throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("g02");
consumer.setNamesrvAddr("192.168.100.121:9876");
consumer.subscribe("xxoo007", "*");
/**
*
*
*
*
* MessageListenerConcurrently 并发消费 / 开多个线程
*
*
*/
// consumer.registerMessageListener(new MessageListenerConcurrently() {
//
// public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
//
// for (MessageExt msg : msgs) {
//
// System.out.println(new String(msg.getBody()));;
// }
// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
// }
// });
/*
*
* MessageListenerOrderly 顺序消费 ,对一个queue 开启一个线程,多个queue 开多个线程
*
*
*/
//
// 最大开启消费线程数
int consumeThreadMax=1;
consumer.setConsumeThreadMax(consumeThreadMax);
// 最小线程数
int consumeThreadMin=1;
consumer.setConsumeThreadMin(consumeThreadMin);
consumer.registerMessageListener(new MessageListenerOrderly() {
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
for (MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()) + " Thread:" + Thread.currentThread().getName());;
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
consumer.start();
System.out.println("Consumer g02 start...");
}
}
事务发送(这里要另外写一篇)
TrancationProducer.java
package oliver.transaction;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionListener;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageExt;
public class TrancationProducer {
public static void main(String[] args) throws Exception{
TransactionMQProducer producer = new TransactionMQProducer("transactionProducerGroup");
producer.setNamesrvAddr("192.168.100.121:9876");
//回调
producer.setTransactionListener(new TransactionListener() {
public LocalTransactionState executeLocalTransaction(Message message, Object o) {
//执行本地事务
/*a();
b();*/
System.out.println("===============executeLocalTransaction=========");
System.out.println("msg->"+new String(message.getBody()));
return LocalTransactionState.UNKNOW;
// return LocalTransactionState.COMMIT_MESSAGE;
}
public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
//broker端回调
System.out.println("===============checkLocalTransaction=========");
System.out.println("msg->"+new String(messageExt.getBody()));
return LocalTransactionState.UNKNOW;
// return LocalTransactionState.ROLLBACK_MESSAGE;
}
});
producer.start();
producer.sendMessageInTransaction(new Message("transactionProducerTopic","test transaction".getBytes()),null);
System.out.println("=============test transaction end");
}
}
分布式系统中的事务可以使用TCC(Try、Confirm、Cancel)、2pc来解决分布式系统中的消息原子性
RocketMQ 4.3+提供分布事务功能,通过 RocketMQ 事务消息能达到分布式事务的最终一致
RocketMQ实现方式
Half Message: 预处理消息,当broker收到此类消息后,会存储到RMQ_SYS_TRANS_HALF_TOPIC的消息消费队列中
检查事务状态: Broker会开启一个定时任务,消费RMQ_SYS_TRANS_HALF_TOPIC队列中的消息,每次执行任务会向消息发送者确认事务执行状态(提交、回滚、未知),如果是未知,等待下一次回调。
超时: 如果超过回查次数,默认回滚消息
TransactionListener的两个方法
executeLocalTransaction
半消息发送成功触发此方法来执行本地事务
checkLocalTransaction
broker将发送检查消息来检查事务状态,并将调用此方法来获取本地事务状态
本地事务执行状态
LocalTransactionState.COMMIT_MESSAGE
执行事务成功,确认提交
LocalTransactionState.ROLLBACK_MESSAGE
回滚消息,broker端会删除半消息
LocalTransactionState.UNKNOW
暂时为未知状态,等待broker回查