写在前面:
1.消息中间件的发展:
第一代以ActiveMQ为代表,遵循JMS(java消息服务)规范
第二代以RabbitMQ为代表是一个有Erlang语言开发的AMQP(高级消息队列协议)的开源实现
第三代以kafka为代表,是一代高吞吐、高可用的消息中间件,以及RocketMQ
RocketMQ的特点:
1.RocketMQ 是一款分布式、队列模型的消息中间件,具有以下特点:
2.能够保证严格的消息顺序
3.提供丰富的消息拉取模式
4.高效的订阅者水平扩展能力
5.实时的消息订阅机制
6.亿级消息堆积能力
7.分布式高可用的部署架构,满足至少一次消息传递语义
8.提供 docker 镜像用于隔离测试和云集群部署
9.提供配置、指标和监控等功能丰富的 Dashboard
选用理由:
a.强调集群无单点,可扩展,任意一点高可用,水平可扩展。
b.海量消息堆积能力,消息堆积后,写入低延迟。
c.支持上万个队列
d.消息失败重试机制
e.消息可查询
f.开源社区活跃
g.成熟度(经过双十一考验)
RocketMQ物理部署结构:
rocketMQ几个概念:
producer:消息生产者,生产者的作用就是将消息发送到 MQ,生产者本身既可以产生消息,如读取文本信息等。也可以对外提供接口,由外部应用来调用接口,再由生产者将收到的消息发送到 MQ
producer group: 生产者组,简单来说就是多个发送同一类消息的生产者称之为一个生产者组。在这里可以不用关心,只要知道有这么一个概念即可,Producer实例可以是多机器、单机器多进程、单进程中的多对象。Producer可以发送多个Topic。处理分布式事务时,也需要Producer集群提高可靠性
consumer : 消息消费者,简单来说,消费 MQ 上的消息的应用程序就是消费者,至于消息是否进行逻辑处理,还是直接存储到数据库等取决于业务需要
consumer group : 消费者组,和生产者类似,消费同一类消息的多个 consumer 实例组成一个消费者组.Consumer实例 的集合。Consumer 实例可以是多机器、但机器多进程、单进程中的多对象。同一个Group中的实例,在集群模式下,以均摊的方式消费;在广播模式下,每个实例都全部消费。
Topic : Topic 是一种消息的逻辑分类,比如说你有订单类的消息,也有库存类的消息,那么就需要进行分类,一个是订单 Topic 存放订单相关的消息,一个是库存 Topic 存储库存相关的消息
Message : Message 是消息的载体。一个 Message 必须指定 topic,相当于寄信的地址。Message 还有一个可选的 tag 设置,以便消费端可以基于 tag 进行过滤消息。也可以添加额外的键值对,例如你需要一个业务 key 来查找 broker 上的消息,方便在开发过程中诊断问题
Tag : 标签可以被认为是对 Topic 进一步细化。一般在相同业务模块中通过引入标签来标记不同用途的消息
Broker : Broker 是 RocketMQ 系统的主要角色,其实就是前面一直说的 MQ。Broker 接收来自生产者的消息,储存以及为消费者拉取消息的请求做好准备
Name Server : Name Server 为 producer 和 consumer 提供路由信息
Push Consumer : 应用通常向Consumer对象注册一个Listener接口,一旦收到消息,Consumer对象立刻回调Listener接口方法。所以,所谓Push指的是客户端内部的回调机制,并不是与服务端之间的机制
Pull Consumer : 应用通常主动调用Consumer从服务端拉消息,然后处理。这用的就是短轮询方式了,在不同情况下,与长轮询各有优点
1,linux安装
官网介绍很详细:
http://rocketmq.apache.org/docs/quick-start/
注意:1,一般的启动失败是因为内存不够导致的,需要修改runserver.sh与runbroker.sh.修改地方如下:
runserv.sh
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"
runbroker.sh
JAVA_OPT="${JAVA_OPT} -server -Xms256m -Xmx256m -Xmn128m"
2,broker启动的时候需要指定broker的外网ip,启动方式如下:
nohup sh bin/mqbroker -n 172.19.211.119:9876 -c conf/broker.properties &
broker.properties:
#进入rocketmq根目录
cd incubator-rocketmq/distribution/target/apache-rocketmq
#编写配置文件,并写好配置
echo "brokerIP1=10.19.73.64的外网IP" > broker.properties
2,本地demo
2.1 pom.xml
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.3.0</version>
</dependency>
2.2 producer
2.2.1 同步调用:
package com.equaker.demo.test.mq;
import org.apache.rocketmq.client.exception.MQClientException;
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;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Mq_Producer_Test {
public static void main(String[] args) throws MQClientException, InterruptedException {
Sync_Producer();
}
/**
* 同步发送
*/
public static void Sync_Producer() throws MQClientException, InterruptedException {
//声明并初始化一个producer
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("172.26.5.160:9876");
producer.setSendMsgTimeout(6000);
//调用start()方法启动一个producer实例
producer.start();
//发送10条消息到Topic为TopicTest,tag为TagA,消息内容为“Hello RocketMQ”拼接上i的值
for (int i = 0; i < 2; i++) {
try {
Message msg = new Message("TopicTest",// topic
"TagA",// tag
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)// body
);
//调用producer的send()方法发送消息
//这里调用的是同步的方式,所以会有返回结果
SendResult sendResult = producer.send(msg);
//打印返回结果,可以看到消息发送的状态以及一些相关信息
System.out.println(sendResult);
} catch (Exception e) {
e.printStackTrace();
Thread.sleep(1000);
}
}
//发送完消息之后,调用shutdown()方法关闭producer
producer.shutdown();
}
}
2.2.2 异步调用
package com.equaker.demo.test.mq;
import org.apache.rocketmq.client.exception.MQClientException;
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;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Mq_Producer_Test {
public static void main(String[] args) throws MQClientException, InterruptedException {
Sync_Producer();
}
/**
* 异步发送
*/
public static void Async_Producer() throws MQClientException, InterruptedException {
//声明并初始化一个producer
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("172.26.5.160:9876");
producer.setSendMsgTimeout(6000);
//调用start()方法启动一个producer实例
producer.start();
int messageCount = 5;
// 主线程阻塞器
final CountDownLatch countDownLatch = new CountDownLatch(messageCount);
//发送10条消息到Topic为TopicTest,tag为TagA,消息内容为“Hello RocketMQ”拼接上i的值
for (int i = 0; i < messageCount; i++) {
try {
Message msg = new Message("TopicTest",// topic
"TagA",// tag
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)// body
);
producer.send(msg, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("success: " + sendResult);
countDownLatch.countDown();
}
@Override
public void onException(Throwable throwable) {
System.out.println("error: " + throwable);
countDownLatch.countDown();
}
});
} catch (Exception e) {
e.printStackTrace();
Thread.sleep(1000);
}
}
countDownLatch.await(10, TimeUnit.SECONDS);
//发送完消息之后,调用shutdown()方法关闭producer
producer.shutdown();
}
}
注意:
可能会报错:
1 org.apache.rocketmq.client.exception.MQClientException: No route info of this topic, topic-2
See http://rocketmq.apache.org/docs/faq/ for further details. Exception org.apache.rocketmq.client.exception.MQClientException: No route info of this topic, topic-2
See http://rocketmq.apache.org/docs/faq/ for further details.
主要是因为rocketMQ异步发送,采用任务模式,及新线程,任务尚未完成就被producer.shutdown();这里我们采用CountDownLatch解决。
2.2.3 单向发送数据
单向传输用于要求中等可靠性的情况,例如日志收集。
适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。
只发送消息,不等待服务器响应,只发送请求不等待应答。此方式发送消息的过程耗时非常短,一般在微秒级别。
package org.equaker.cache;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
/**
* 单向发送消息-RocketMQ
*
* @author EQuaker
*
*/
public class OnewayProducer_RocketMQ {
public static void main(String[] args) throws Exception {
// Instantiate with a producer group name.
DefaultMQProducer producer = new DefaultMQProducer("group3");
// Specify name server addresses.
producer.setNamesrvAddr("外网ip:9876");
// Launch the instance.
producer.start();
for (int i = 0; i < 10; i++) {
// Create a message instance, specifying topic, tag and message body.
Message msg = new Message("topic-3" /* Topic */, "TagA" /* Tag */,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
// Call send message to deliver message to one of brokers.
producer.sendOneway(msg);
}
// Shut down once the producer instance is not longer in use.
producer.shutdown();
}
}
2.3 消费者
package org.equaker.cache;
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.message.MessageQueue;
public class Consumer_RocketMQ {
public static void main(String[] args) throws Exception{
// Instantiate with specified consumer group name.
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consume1");
// Specify name server addresses.
consumer.setNamesrvAddr("外网ip:9876");
//默认集群消费模式
consumer.setMessageModel(MessageModel.CLUSTERING);
// Subscribe one more more topics to consume.
consumer.subscribe("topic-3", "*");
// Register callback to execute on arrival of messages fetched from brokers.
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);
MessageQueue messageQueue = context.getMessageQueue();
System.out.println("broker name: "+messageQueue.getBrokerName());
System.out.println("topic name: "+messageQueue.getTopic());
System.out.println("msgs length: "+msgs.size());
for(MessageExt msg : msgs) {
System.out.println(new String(msg.getBody()));
}
System.out.println("*******************");
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//Launch the consumer instance.
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
3.顺序消费
RocketMQ使用FIFO顺序提供有序消息。主要是在生产者端使用MessageQueueSelector实现。
package com.equaker.demo.test.mq;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Mq_Producer_Test {
public static void main(String[] args) throws MQClientException, InterruptedException, UnsupportedEncodingException, RemotingException, MQBrokerException {
//Async_Producer();
//Sync_Producer();
//OneWay_Producer();
Order_Producer();
}
public static void Order_Producer() throws MQClientException, UnsupportedEncodingException, RemotingException, InterruptedException, MQBrokerException {
//声明并初始化一个producer
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("172.26.5.160:9876");
producer.setSendMsgTimeout(6000);
//调用start()方法启动一个producer实例
producer.start();
String[] tags = new String[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
for (int i = 0; i < 10; i++) {
int orderId = i % 10;
//Create a message instance, specifying topic, tag and message body.
Message msg = new Message("TopicTest", tags[i % tags.length], "KEY" + i,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(msg, new MessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
Integer id = (Integer) arg;
int index = id % mqs.size();
return mqs.get(index);
}
}, orderId);
System.out.printf("%s%n", sendResult);
}
//server shutdown
producer.shutdown();
}
}
4.广播消费
主要是在消费者端,设置为广播模式。默认为集群模式。
package com.equaker.demo.test.mq;
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.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import java.util.List;
public class Mq_Consumer_Test {
public static void main(String[] args) throws MQClientException {
//声明并初始化一个consumer
//需要一个consumer group名字作为构造方法的参数,这里为consumer1
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer1");
//同样也要设置NameServer地址
consumer.setNamesrvAddr("172.26.5.160:9876");
//这里设置的是一个consumer的消费策略
//CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,即跳过历史消息
//CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
//CONSUME_FROM_TIMESTAMP 从某个时间点开始消费,和setConsumeTimestamp()配合使用,默认是半个小时以前
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
//设置为广播模式,默认集群消费模式
consumer.setMessageModel(MessageModel.BROADCASTING);
//设置consumer所订阅的Topic和Tag,*代表全部的Tag
consumer.subscribe("TopicTest", "*");
//设置一个Listener,主要进行消息的逻辑处理
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.println(Thread.currentThread().getName() + " Receive New Messages: " + msgs);
MessageExt ext = msgs.get(0);
System.out.println(new String(ext.getBody()));
//返回消费状态
//CONSUME_SUCCESS 消费成功
//RECONSUME_LATER 消费失败,需要稍后重新消费
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//调用start()方法启动consumer
consumer.start();
System.out.println("Consumer Started.");
}
}
5. 延迟消费
消息被消耗比存储时间晚。主要是在生产者方的消息体设置延迟信息。
messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h(我们使用第三级 即延迟10s)
package com.equaker.demo.test.mq;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Mq_Producer_Test {
public static void main(String[] args) throws MQClientException, InterruptedException, UnsupportedEncodingException, RemotingException, MQBrokerException {
//Async_Producer();
//Sync_Producer();
//OneWay_Producer();
Order_Producer();
}
public static void Schedule_Producer() throws Exception {
//声明并初始化一个producer
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("172.26.5.160:9876");
producer.setSendMsgTimeout(6000);
//调用start()方法启动一个producer实例
producer.start();
Message message = new Message("TopicTest", ("Hello scheduled message " + 1).getBytes());
// This message will be delivered to consumer 10 seconds later.
message.setDelayTimeLevel(3);
// Send the message
producer.send(message);
System.out.println("send...");
producer.shutdown();
}
}
6.批量生产
批量发送消息可提高传递小消息的性能。
同一批次的消息应具有:相同的主题,相同的waitStoreMsgOK,并且不支持计划。
此外,一批邮件的总大小不得超过1MiB。
package com.equaker.demo.test.mq;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Mq_Producer_Test {
public static void main(String[] args) throws MQClientException, InterruptedException, UnsupportedEncodingException, RemotingException, MQBrokerException {
//Async_Producer();
//Sync_Producer();
//OneWay_Producer();
Order_Producer();
}
public static void Batch_Producer() throws Exception {
//声明并初始化一个producer
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("172.26.5.160:9876");
producer.setSendMsgTimeout(6000);
//调用start()方法启动一个producer实例
producer.start();
Message message1 = new Message("TopicTest", ("Hello scheduled message " + 1).getBytes());
Message message2 = new Message("TopicTest", ("Hello scheduled message " + 2).getBytes());
Message message3 = new Message("TopicTest", ("Hello scheduled message " + 3).getBytes());
Message message4 = new Message("TopicTest", ("Hello scheduled message " + 4).getBytes());
producer.send(Arrays.asList(message1, message2, message3, message4));
producer.shutdown();
}
}
7.过滤消费
通常在订阅通道的时候,我们可以指定tag,进行消息过滤。例如: consumer.subscribe("TopicTest", "tagA || tagB || tagC");
这里面的弊端是一个消息只有一个tag,如果我们想消费的消息来自不同的tag,就有点麻烦。这里我们使用RocketMq Sql。
7.1,过滤消费-生产者
生产者通过Message.putUserProperty设置变量信息。
package com.equaker.demo.test.mq;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.MessageQueueSelector;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class Mq_Producer_Test {
public static void main(String[] args) throws MQClientException, InterruptedException, UnsupportedEncodingException, RemotingException, MQBrokerException {
//Async_Producer();
//Sync_Producer();
//OneWay_Producer();
Filter_Producer();
}
public static void Filter_Producer() throws Exception {
//声明并初始化一个producer
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("172.26.5.160:9876");
producer.setSendMsgTimeout(6000);
//调用start()方法启动一个producer实例
producer.start();
Message message1 = new Message("TopicTest", ("Hello scheduled message " + 1).getBytes());
message1.putUserProperty("a", "25");
producer.send(message1);
producer.shutdown();
}
}
7.1,过滤消费-消费者
消费者通过MessageSelector.bySql 过滤。
package com.equaker.demo.test.mq;
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.client.exception.MQClientException;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import java.util.List;
public class Mq_Consumer_Test {
public static void main(String[] args) throws MQClientException {
//Common_Consumer();
Filter_Consumer();
}
public static void Filter_Consumer() throws MQClientException {
//声明并初始化一个consumer
//需要一个consumer group名字作为构造方法的参数,这里为consumer1
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer1");
//同样也要设置NameServer地址
consumer.setNamesrvAddr("172.26.5.160:9876");
//这里设置的是一个consumer的消费策略
//CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,即跳过历史消息
//CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
//CONSUME_FROM_TIMESTAMP 从某个时间点开始消费,和setConsumeTimestamp()配合使用,默认是半个小时以前
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
//默认集群消费模式
consumer.setMessageModel(MessageModel.CLUSTERING);
//设置consumer所订阅的Topic和Tag,过滤a属性在20-30之间
consumer.subscribe("TopicTest", MessageSelector.bySql("a between 20 and 30"));
//设置一个Listener,主要进行消息的逻辑处理
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.println(Thread.currentThread().getName() + " Receive New Messages: " + msgs);
MessageExt ext = msgs.get(0);
System.out.println(new String(ext.getBody()));
//返回消费状态
//CONSUME_SUCCESS 消费成功
//RECONSUME_LATER 消费失败,需要稍后重新消费
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//调用start()方法启动consumer
consumer.start();
System.out.println("Consumer Started.");
}
}
8,事务消息
rocketMq的事务消息是一大特性,我们放在下一章《分布式事务与RocketMq 事务消息》和分布式事务一块说。