目录
1、收发消息
1、启动nameserver和broker之后(为了可视化方便还可以启动console)
2、maven依赖
<dependencies>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.1.0-incubating</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-common</artifactId>
<version>4.1.0-incubating</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.36.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.2</version>
</dependency>
</dependencies>
3、生产者
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
public class ProducerMain {
public static void main(String[] args) {
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("127.0.0.1:9876");
producer.setVipChannelEnabled(false);
//为避免程序启动的时候报错,添加此代码,可以让rocketMq自动创建topickey
producer.setCreateTopicKey("AUTO_CREATE_TOPIC_KEY");
try {
producer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
try {
Message message = new Message("TopicTest", "Tag1",
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(message);
System.out.println(sendResult.toString());
} catch (Exception e) {
e.printStackTrace();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
producer.shutdown();
}
}
4、消费者
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 java.util.List;
public class ConsumerMain {
public static void main(String[] args) {
//设置消费者组
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("CID_LRW_DEV_SUBS");
consumer.setVipChannelEnabled(false);
consumer.setNamesrvAddr("127.0.0.1:9876");
//设置消费者端消息拉取策略,表示从哪里开始消费
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
//设置消费者拉取消息的策略,*表示消费该topic下的所有消息,也可以指定tag进行消息过滤
try {
consumer.subscribe("TopicTest", "*");
} catch (MQClientException e) {
e.printStackTrace();
}
//消费者端启动消息监听,一旦生产者发送消息被监听到,就打印消息,和rabbitmq中的handlerDelivery类似
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for (MessageExt messageExt : msgs) {
System.out.println(messageExt.toString());
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//调用start()方法启动consumer
try {
consumer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
System.out.println("Consumer Started....");
}
}
5、控制台
因为在生产者使用完之后会调用shutdown,所以在控制台是查询不到当前生产组的生产者内容;
6、报错
org.apache.rocketmq.client.exception.MQClientException: No route info of this ***
命令行手动创建Topic就好了
>mqadmin updateTopic -n localhost:9876 -b localhost:10911 -t TopicTest
7、DefaultMQPullConsumer
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.impl.consumer.PullResultExt;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.remoting.exception.RemotingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class PullConsumer {
private static final Map<MessageQueue, Long> offsetTable = new HashMap<MessageQueue, Long>();
public static void main(String[] args) {
DefaultMQPullConsumer consumer = new DefaultMQPullConsumer("pullConsumer");
consumer.setNamesrvAddr("127.0.0.1:9876");
try {
consumer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
try {
Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("TopicTest");
for(MessageQueue mq:mqs) {
System.out.println("Consume from the queue: " + mq);
// long offset = consumer.fetchConsumeOffset(mq, true);
// PullResultExt pullResult =(PullResultExt)consumer.pull(mq, null, getMessageQueueOffset(mq), 32);
//消息未到达默认是阻塞10秒,private long consumerPullTimeoutMillis = 1000 * 10;
PullResultExt pullResult = null;
try {
pullResult = (PullResultExt)consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32);
} catch (RemotingException e) {
e.printStackTrace();
} catch (MQBrokerException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
putMessageQueueOffset(mq, pullResult.getNextBeginOffset());
switch (pullResult.getPullStatus()) {
case FOUND:
List<MessageExt> messageExtList = pullResult.getMsgFoundList();
for (MessageExt m : messageExtList) {
System.out.println(new String(m.getBody()));
}
break;
case NO_MATCHED_MSG:
break;
case NO_NEW_MSG:
break ;
case OFFSET_ILLEGAL:
break;
default:
break;
}
}
} catch (MQClientException e) {
e.printStackTrace();
}
}
private static void putMessageQueueOffset(MessageQueue mq, long offset) {
offsetTable.put(mq, offset);
}
private static long getMessageQueueOffset(MessageQueue mq) {
Long offset = offsetTable.get(mq);
if (offset != null)
return offset;
return 0;
}
}
2、顺序消息
顺序消费分为全局顺序和局部顺序,全局顺序就只有一个orderId,局部顺序就是多个orderId(同一个orderId内保证顺序)
Producer
//需要一个producer group名字作为构造方法的参数,这里为producer1
DefaultMQProducer producer = new DefaultMQProducer("producer1");
//设置NameServer地址,此处应改为实际NameServer地址,多个地址之间用;分隔
//NameServer的地址必须有,但是也可以通过环境变量的方式设置,不一定非得写死在代码里
producer.setNamesrvAddr("127.0.0.1:9876;127.0.0.1:12345");
producer.setVipChannelEnabled(false);
//为避免程序启动的时候报错,添加此代码,可以让rocketMq自动创建topickey
producer.setCreateTopicKey("TopicTest");
try {
producer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
try {
Message message = new Message("TopicTest", "Order", "20200311",
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(message, new MessageQueueSelector() {
public MessageQueue select(List<MessageQueue> list, Message message, Object o) {
Integer id = (Integer) o;
int index = id % list.size();
return list.get(index);
}
}, 1);
System.out.println(sendResult.toString());
} catch (Exception e) {
e.printStackTrace();
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
producer.shutdown();
consumer
//设置消费者组
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("consumer1");
consumer.setVipChannelEnabled(false);
consumer.setNamesrvAddr("127.0.0.1:9876;127.0.0.1:12345");
//设置消费者端消息拉取策略,表示从哪里开始消费
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
//设置消费者拉取消息的策略,*表示消费该topic下的所有消息,也可以指定tag进行消息过滤
try {
consumer.subscribe("TopicTest", "*");
} catch (MQClientException e) {
e.printStackTrace();
}
//消费者端启动消息监听,一旦生产者发送消息被监听到,就打印消息,和rabbitmq中的handlerDelivery类似
consumer.registerMessageListener(new MessageListenerOrderly() {
public ConsumeOrderlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
for (MessageExt messageExt : list) {
System.out.println(new String(messageExt.getBody()));
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
//调用start()方法启动consumer
try {
consumer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
System.out.println("Consumer Started....");
3、修改nameserver端口
start mqnamesrv.cmd -c nameserver.properties
启动breoker:
start mqbroker.cmd -n 127.0.0.1:12345 autoCreateTopicEnable=true
4、rocketmq-console打包
去掉test
5、集群部署
nameserver集群:有自己的独立配置(端口不同即可),参考3
broker集群:这里举例最简单的master无slave模式,修改响应的配置文件即可
所属集群名字
brokerClusterName=DefaultCluster
broker名字,他的slave也叫broker-a
brokerName=broker-a
0 表示 Master,>0 表示 Slave
brokerId=0
删除文件时间点,默认凌晨 4点
deleteWhen=04
文件保留时间,默认 48 小时
fileReservedTime=48
Broker的角色,ASYNC_MASTER异步复制,SYNC_MASTER 同步双写,SLAVE从机
brokerRole=ASYNC_MASTER
刷盘方式,ASYNC_FLUSH异步刷盘,SYNC_FLUSH同步刷盘
flushDiskType=ASYNC_FLUSH
Broker 对外服务的监听端口(如果是同一台机器部署集群,跨度要大一点。配置10911后10912默认也被占用)
listenPort=10911
存储路径
storePathRootDir=/data/rocketmq/store/rootdir-a-m
commitLog 存储路径
storePathCommitLog=/data/rocketmq/store/commitlog-a-m
nameServer地址,分号分割
namesrvAddr=127.0.0.1:12345;127.0.0.1:9876
是否允许Broker自动创建Topic,建议线下开启,线上关闭
autoCreateTopicEnable=true
检测物理文件磁盘空间
diskMaxUsedSpaceRatio=88
消费队列存储路径存储路径
storePathConsumeQueue=/usr/local/rocketmq/store/broker-a/consumequeue
消息索引存储路径
storePathIndex=/usr/local/rocketmq/store/broker-a/index
checkpoint 文件存储路径
storeCheckpoint=/usr/local/rocketmq/store/checkpoint
abort 文件存储路径
abortFile=/usr/local/rocketmq/store/abort
限制的消息大小
maxMessageSize=65536
发消息线程池数量
sendMessageThreadPoolNums=128
拉消息线程池数量
pullMessageThreadPoolNums=128
commitLog每个文件的大小默认1G
mapedFileSizeCommitLog=1073741824
ConsumeQueue每个文件默认存30W条,根据业务情况调整
mapedFileSizeConsumeQueue=300000
broker指定配置文件:
start mqbroker.cmd -c ../conf/2m-noslave/broker-b.properties
6、路径配置
broker的存储路径参考4
日志路径修改一下即可
rocket-console的日志同理修改项目的
7、一些疑问
rocketmq-console启动后会占用C盘的空间(至少3g),为啥?什么占用的,在哪设置
生产消息时候指定的生产者组,在rocketmq-console生产者中却检索不到,为啥?