RocketMQ4.4.0
最近在做一个小项目的过程中使用了MQ消息队列。
选择哪种MQ我也纠结了很久,最后选择了阿里的开源项目RocketMQ,不过现在已经贡献给Apache社区了。
但是在使用的过程中也是踩了很多坑的,下面我会把我遇到的一些问题罗列出来。
问题多多,但是都是环境的问题,代码基本上都是一样的,所以出了问题首先检查的就是你的环境是否连接正确。
下面我把我的代码环境配置罗列一下:
import lombok.extern.slf4j.Slf4j;
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 org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* rocketMq 生产者包装
*
* @author zhengjf
* @version 1.0
* @date 2019/3/5
*/
@Service
@Slf4j
public class MqProducerService {
@Value("${rocketmq.name-server}")
private String namesrvAddr;
@Value("${rocketmq.producer.group}")
private String producerGroup;
private DefaultMQProducer producer;
/**
* DefaultMQProducer 普通消息生产者对象创建
*
* @return void
* @author zhengjf
* @date 2019/3/5
*/
@PostConstruct
public void initProducer() {
producer = new DefaultMQProducer(producerGroup);
producer.setNamesrvAddr(namesrvAddr);
producer.setRetryTimesWhenSendFailed(3);
producer.setVipChannelEnabled(false);
try {
producer.start();
log.info("[Producer 已启动]");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 普通消息 同步发送消息,只要不抛异常就是成功
*
* @param topic, tags, msg
* @return java.lang.String
* @author zhengjf
* @date 2019/3/5
*/
public SendResult send(String topic, String tags, String msg) throws Exception {
Message message = new Message(
// Message所属的Topic
topic,
// Message Tag,可理解为mail中的标签,对消息进行再归类,方便Consumer指定过滤条件在MQ服务器过滤
tags,
// Message Body,任何二进制形式的数据,MQ不做任何干预,需要Producer与Consumer协商好一致的序列化和反序列化方式
msg.getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult result = producer.send(message);
log.info("发送消息后返回:" + result.toString());
return result;
}
/**
* 延时发送
* RocketMQ目前指定的延时时间间隔有DelayTimeLevel 1s,5s,10s,30s,1m,2m,3m,4m,5m,6m,7m,8m,9m,10m,20m,30m,1h,2h,用等级来表示时间间隔。
*
* @param topic, tags, msg, delayTimeLevel 时间等级(30分钟是16)
* @return org.apache.rocketmq.client.producer.SendResult
* @author zhengjf
* @date 2019/3/5
*/
public SendResult sendDelayTime(String topic, String tags, String msg, int delayTimeLevel) throws Exception {
Message message = new Message(
// Message所属的Topic
topic,
// Message Tag,可理解为mail中的标签,对消息进行再归类,方便Consumer指定过滤条件在MQ服务器过滤
tags,
// Message Body,任何二进制形式的数据,MQ不做任何干预,需要Producer与Consumer协商好一致的序列化和反序列化方式
msg.getBytes(RemotingHelper.DEFAULT_CHARSET));
message.setDelayTimeLevel(delayTimeLevel);
SendResult result = producer.send(message);
log.info("发送消息后返回:" + result.toString());
return result;
}
/**
* 这里用到了这个mq的异步处理,类似ajax,可以得到发送到mq的情况,并做相应的处理
* 不过要注意的是这个是异步的
*
* @param topic, tags, msg
* @return void
* @author zhengjf
* @date 2019/3/5
*/
public String sendAsync(String topic, String tags, String msg) throws Exception {
Message message = new Message(
// Message所属的Topic
topic,
// Message Tag,可理解为Gmail中的标签,对消息进行再归类,方便Consumer指定过滤条件在MQ服务器过滤
tags,
// Message Body,任何二进制形式的数据,MQ不做任何干预,需要Producer与Consumer协商好一致的序列化和反序列化方式
msg.getBytes(RemotingHelper.DEFAULT_CHARSET));
producer.send(message, new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("传输成功。" + sendResult.toString());
}
@Override
public void onException(Throwable e) {
log.error("传输失败", e);
}
});
// 在callback返回之前。
log.info("send message async." + message.toString());
return message.toString();
}
@PreDestroy
public void shutDownProducer() {
if (producer != null) {
producer.shutdown();
}
}
}
import com.mjs.common.common.OrderStatusEnum;
import com.mjs.mojisishop.entity.OrderInfo;
import com.mjs.mojisishop.mapper.OrderInfoMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 监听MQ的主题消息,进行消费。可以监听多个
*
* @author zhengjf
* @version 1.0
* @date 2019/3/5
*/
@Component
@Slf4j
public class ConsumerListener {
@Value("${rocketmq.name-server}")
private String namesrvAddr;
@Value("${rocketmq.consumer.group}")
private String consumerGroup;
@Autowired
OrderInfoMapper orderInfoMapper;
@PostConstruct
public void defaultMQPushConsumer() throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroup);
consumer.setNamesrvAddr(namesrvAddr);
consumer.subscribe("order", "pay");
// 如果是第一次启动,从队列头部开始消费
// 如果不是第一次启动,从上次消费的位置继续消费
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
// 开启内部类实现监听
consumer.registerMessageListener((MessageListenerConcurrently) (list, context) -> {
try {
for (MessageExt messageExt : list) {
String messageBody = new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET);
log.info("消费者受到消息:[Consumer] msgID(" + messageExt.getMsgId() + ") msgBody : " + messageBody);
}
} catch (Exception e) {
e.printStackTrace();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
consumer.subscribe("test222", "pay");
consumer.registerMessageListener((MessageListenerConcurrently) (list, context) -> {
try {
for (MessageExt messageExt : list) {
String messageBody = new String(messageExt.getBody(), RemotingHelper.DEFAULT_CHARSET);
log.info("消费者受到消息:[Consumer] msgID(" + messageExt.getMsgId() + ") msgBody : " + messageBody);
}
} catch (Exception e) {
e.printStackTrace();
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
consumer.start();
log.info("[Consumer 已启动]");
}
}
就是这么简单的两个文件就可以了。
my mq.version 4.4.0
org.apache.rocketmq
rocketmq-client
${mq.version}
org.apache.rocketmq
rocketmq-common
${mq.version}
org.apache.rocketmq
rocketmq-remoting
${mq.version}
代码说完了就说以下我的环境配置。
首先我的mq放在阿里云服务器上
cd /home/tools/rocketmq-all-4.4.0-bin-release
关闭namesrv服务:
sh bin/mqshutdown namesrv
关闭broker服务 :
sh bin/mqshutdown broker
启动namesrv服务:
nohup sh bin/mqnamesrv &
启动broker服务:公网ip
nohup sh bin/mqbroker -c conf/broker.conf &
我的broker.conf 内容有修改,所以上面启动的时候没有指定nameserver地址
在默认的配置下面添加两项
公网ip啊。要不然本地的服务就连接不上mq服务器,没办法发送消费消息
#nameServer地址,分号分割
namesrvAddr = 57.111.156.132:9876
brokerIP1 = 57.111.156.132
还有一个要注意的就是如果你本地连接云服务器的mq,要把本地的防火墙还有云服务的防火墙关了。
如果要查看mq的日志,一般都放在/root/logs/rocketmqlogs中,这是我的日志路径,也可能不同用户不同地址
有broker.log、namesrv.log。。。。。。。