简单搭建一个RocketMQ服务(包括运维服务以及测试代码)
一、环境说明:Linux系统,JDK1.8,RocketMQ版本4.9.4
二、RocketMQ下载地址:https://archive.apache.org/dist/rocketmq/
三、RocketMQ安装
1、项目解压
unzip rocketmq-all-4.9.4-bin-release.zip
注意:如果提示unzip命令不存在,安装命令apt install unzip
2、修改启动配置(主要是修改默认内存设置,不然容易报错:insufficient memory)
对应目录下:/home/rocketmq-all-4.9.4-bin-release/bin
1)修改runserver.sh文件
2)修改runbroker.sh文件
3)修改tools.sh文件
3、修改broker.conf配置(目前我们只搭建一个master)
对应目录下:/home/rocketmq-all-4.9.4-bin-release/conf
namesrvAddr=(当前服务器IP):9876
brokerIP1=(当前服务器IP)
四、RocketMQ启动
在目录下/home/rocketmq-all-4.9.4-bin-release
1、nohup sh bin/mqnamesrv > logs/mqnamesrv.out &
如下表示启动成功
2、nohup sh bin/mqbroker -n (当前服务器IP):9876 -c ./conf/broker.conf >logs/broker.out &
如下表示启动成功
五、简单测试一下(官方案例)
export NAMESRV_ADDR=localhost:9876 sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer
注意:在目录下/home/rocketmq-all-4.9.4-bin-release
这里作为生产者生产1000条消息,运行完自动结束,之后运行下面代码:
sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer
这里作为消费者消费1000条消息。
六、关闭服务
是按照启动服务相反的来关闭的
在目录下/home/rocketmq-all-4.9.4-bin-release依次运行如下代码
sh bin/mqshutdown broker sh bin/mqshutdown namesrv
注意:有可能会在第五步测试的时候出现:service not available now, maybe disk full....
这是因为,RocketMQ有一个默认磁盘的使用率,超过这个使用率,这就报这个错。
解决方案:
1)删除磁盘中不必要的文件
2)在broker.conf中添加diskMaxUsedSpaceRatio=99
七、搭建运维服务(rocketmq-console)
1、下载开源的rocketmq-externals项目
https://github.com/apache/rocketmq-externals
找到rocketmq-console项目,修改application.properties文件
server.port=10003(随便哪个不常用的)
rocketmq.config.namesrvAddr=(和第四步中修改broker.conf的IP一致):9876
pom.xml文件中将<rocketmq.version>4.4.0-SNAPSHOT</rocketmq.version> 改成<rocketmq.version>4.4.0</rocketmq.version>
2、打包
mvn clean package -Dmaven.test.skip=true
最后在target文件夹中有个rocketmq-console-ng-1.0.0.jar
PS:
1)需要配置好maven的环境,不然会出现没有该命令
2)最好在rocketmq-console目录下的命令提示符中输入命令,用powershell窗口有报错
3)如果打包出现“You must specify a valid lifecycle phase or a goal in the format”,在pom.xml中的<build>添加<defaultGoal>compile</defaultGoal>
3、启动服务
nohup java -jar rocketmq-console-ng-1.0.0.jar >console.out &
4、控制台界面:
http://xxx.xxx.xxx.xxx:10003/index.html,可以切换语言
八、测试代码(简单的工具类方法)
maven加入jar包,需要与你上面下载的RocketMQ版本对应上
<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.9.4</version> </dependency> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-common</artifactId> <version>4.9.4</version> </dependency>
代码如下:
package com.sigma.common.rocketmq.utils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang3.StringUtils; import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.listener.*; 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.consumer.ConsumeFromWhere; import org.apache.rocketmq.common.message.Message; import org.apache.rocketmq.common.message.MessageExt; import org.apache.rocketmq.common.protocol.heartbeat.MessageModel; import org.apache.rocketmq.remoting.common.RemotingHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.List; public class RocketMqUtils { private static Logger logger = LoggerFactory.getLogger(RocketMqUtils.class); private String namesrvAddr;//rocketmq服务地址,多个用;号隔开 private String tags;//标识,这里为null,可以自行修改 private static final int timeout = 3000;//发送超时时长 public RocketMqUtils(String namesrvAddr) { this.namesrvAddr = namesrvAddr; } /** * 创建生产者对象 * * @return */ private DefaultMQProducer createMQProducer(String producerId) { //生产者的组名 DefaultMQProducer producer = new DefaultMQProducer(producerId); //指定NameServer地址,多个地址以 ; 隔开 producer.setNamesrvAddr(namesrvAddr); //发送消息超时时长设置 producer.setSendMsgTimeout(timeout); //发送失败,重试三次 producer.setRetryTimesWhenSendFailed(3); return producer; } /** * 发送MQ消息 * * @param producerId 生产者 * @param topic 主题 * @param msg 消息 * @param key * @return * @throws MQClientException * @throws Exception */ public SendResult sendMq(String producerId, String topic, String msg, String key) throws MQClientException, Exception { return this.sendMq(producerId, topic, msg, key, 0); } /** * @param producerId 生产者 * @param msg 消息 * @param delayTimeLevel 消息等级(延后发送),为0则立即发送,等级从1到10 * @return * @throws MQClientException * @throws Exception */ public SendResult sendMq(String producerId, String topic, String msg, String key, int delayTimeLevel) throws MQClientException, Exception { if (StringUtils.isEmpty(msg)) { throw new RuntimeException("send rocket topic<" + topic + "> mq message to List<String> is null ..."); } DefaultMQProducer producer = this.createMQProducer(producerId); //delayTimeLevel:定时消息等级,指定的时间后才能传递,不支持任意精度时间。按level等级划分,默认从level=1开始,如果level=0则不延时,具体如messageDelayLevel值 Message message = new Message(topic, tags, key, msg.getBytes(RemotingHelper.DEFAULT_CHARSET)); message.setDelayTimeLevel(delayTimeLevel); try { producer.start(); return producer.send(message); } catch (MQClientException mqce) { logger.error("send rocket topic<" + topic + "> rocketMq client error:", mqce); throw mqce; } catch (Exception e) { logger.error("send rocket topic<" + topic + "> rocketMq send msg error:", e); throw e; } finally { //关闭生产者 producer.shutdown(); } } /** * 创建消费对象 * * @param consumerId 消费者 * @param isBroadcasting 是否为广播消费模式 * @return * @throws MQClientException */ private DefaultMQPushConsumer createMqConsumer(String consumerId, String topic, boolean isBroadcasting) throws MQClientException { //消费者的组名 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerId); //指定NameServer地址,多个地址以 ; 隔开 consumer.setNamesrvAddr(namesrvAddr); //订阅PushTopic下Tag为push的消息 consumer.subscribe(topic, tags); //设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费 //如果非第一次启动,那么按照上次消费的位置继续消费 consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); //设置消费模式为广播模式,即每个消费者都能接收到所有消息 if (isBroadcasting) { consumer.setMessageModel(MessageModel.BROADCASTING); } return consumer; } /** * 监听MQ队列,拉取MQ消息并进行消费 * * @param consumerId 消费者 * @param headerInterface 回调方法 * @throws MQClientException * @throws Exception */ public void pullMq(String consumerId, String topic, HeaderInterface headerInterface) throws MQClientException, Exception { this.pullMq(consumerId, topic, headerInterface, false); } /** * 监听MQ队列,拉取MQ消息并进行消费(支持广播消费模式) * * @param consumerId 消费者 * @param topic 主题 * @param headerInterface 回调方法 * @param isBroadcasting 是否为广播消费模式 * @throws MQClientException * @throws Exception */ public void pullMq(String consumerId, String topic, HeaderInterface headerInterface, boolean isBroadcasting) throws MQClientException, Exception { //消费者的组名 DefaultMQPushConsumer consumer = this.createMqConsumer(consumerId, topic, isBroadcasting); try { consumer.registerMessageListener(this.setConcurrentlyConsumeMessage(headerInterface)); consumer.start(); } catch (Exception e) { logger.error("rocketMq pull msg error:", e); throw e; } finally { this.addShutdownHook(consumer); } } /** * 消费端默认消息 * * @param headerInterface * @return */ private MessageListenerConcurrently setConcurrentlyConsumeMessage(HeaderInterface headerInterface) { return (List<MessageExt> list, ConsumeConcurrentlyContext context) -> { try { for (MessageExt message : list) { headerInterface.execute(message); } } catch (Exception e) { logger.error("rocketMq consumer pull msg error:", e); //稍后再试 return ConsumeConcurrentlyStatus.RECONSUME_LATER; } //消费成功 return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }; } /** * 消费端顺序消息 * * @param headerInterface * @return */ private MessageListenerOrderly setOrderlyConsumeMessage(HeaderInterface headerInterface) { return (list, context) -> { try { for (MessageExt message : list) { headerInterface.execute(message); } } catch (Exception e) { logger.error("rocketMq consumer pull msg error:", e); //稍后再试 return ConsumeOrderlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT; } //消费成功 return ConsumeOrderlyStatus.SUCCESS; }; } /** * 函数式回调接口 */ @FunctionalInterface public interface HeaderInterface { void execute(MessageExt message) throws IOException; } /** * 注册虚拟机器关机钩子事件 * * @param consumer */ private void addShutdownHook(DefaultMQPushConsumer consumer) { Runtime.getRuntime().addShutdownHook(new Thread(() -> { logger.info("jvm shutdown hook: close rocketMq consumer server ..."); consumer.shutdown(); })); } public static void main(String[] args) throws Exception { /* RocketMqUtils pRocketMqUtils = new RocketMqUtils("xxx.xxx.xxx.xxx:9876"); //发送同步消息 JSONObject jsonObject = new JSONObject(); jsonObject.put("orderId", 12345); jsonObject.put("orderCode", "CODE12345"); jsonObject.put("buyUserId", 123); String key = "ORDERID_" + 12345 + "_" + 123; pRocketMqUtils.sendMq("cluster-test-group", "test-topic-04", jsonObject.toJSONString(), key);*/ RocketMqUtils cRocketMqUtils = new RocketMqUtils("xxx.xxx.xxx.xxx:9876"); cRocketMqUtils.pullMq("test-consumer-group", "test-topic-04", (message) -> { String messageBody = new String(message.getBody(), RemotingHelper.DEFAULT_CHARSET); JSONObject jsonObject = JSON.parseObject(messageBody); Integer orderId = jsonObject.getInteger("orderId"); Integer buyUserId = jsonObject.getInteger("buyUserId"); String orderCode = jsonObject.getString("orderCode"); System.out.println(orderId + "====" + buyUserId + "====" + orderCode); logger.info("消费响应:key : " + message.getKeys() + ", tag : " + message.getTags() + ", msgBody : " + messageBody);//输出消息内容 }); } }