RocketMQ实践

一、RocketMQ简介

1、开源的分布式消息中间件
2、可以支持亿级消息堆积,而且在堆积了这么多消息后依然保持写入低延迟。
3、RocketMQ 核心的四大组件:Name Server、Broker、Producer、Consumer

二、本地搭建

1、下载rocket
https://www.apache.org/dyn/closer.cgi?path=rocketmq/4.2.0/rocketmq-all-4.2.0-source-release.zip
2、解压。 rocketmq是个mvn工程
3、进入到项目下

cd rocketmq-all-4.2.0
4、安装
mvn -Prelease-all -DskipTests clean install -U
5、启动
备注:记得配置JAVA_HOME啊!!!
5.1启动nameserver
cd到bin目录下 cd rocketmq-all-4.2.0/distribution/target/apache-rocketmq/bin
执行启动命令 sh mqnamesrv
启动成功日志:
OpenJDK 64-Bit Server VM warning: Using the DefNew young collector with the CMS collector is deprecated and will likely be removed in a future release
OpenJDK 64-Bit Server VM warning: UseCMSCompactAtFullCollection is deprecated and will likely be removed in a future release.
OpenJDK 64-Bit Server VM warning: Cannot open file /dev/shm/rmq_srv_gc.log due to No such file or directory

The Name Server boot success. serializeType=JSON

5.2启动broker
[如果不加autoCreateTopicEnable=true,broker会启动成功,但不会注册到你启动的nameserver上,produce消息时候会报:No route info of this topic]

sh mqbroker -n localhost:9876 autoCreateTopicEnable=true
小插曲:如何查看broker日志,日志路径 Users/xxx/logs/rocketmqlogs/broker.log
注册&启动成功日志
Set user specified name server address: localhost:9876
2020-05-18 14:59:19 INFO PullRequestHoldService - PullRequestHoldService service started
2020-05-18 14:59:19 INFO main - register broker to name server localhost:9876 OK
2020-05-18 14:59:19 INFO main - The broker[xxxxMacBook-Pro.local, 192.168.3.86:10911] boot success. serializeType=JSON and name server is localhost:9876
在这里插入图片描述
仅仅启动成功日志
PullRequestHoldService - PullRequestHoldService service started
2020-05-18 14:54:02 INFO main - The broker[xxxxMacBook-Pro.local, 192.168.3.86:10911] boot success. serializeType=JSON
在这里插入图片描述
如何查看你的broker有没注册成功
sh mqadmin clusterList -n localhost:9876
在这里插入图片描述
6、关闭
sh mqshutdown namesrv
sh mqshutdown broker

三、 生产者和消费者开发

开发代码实现生产者生产消息,消费者消费消息的功能
1、消息生产者开发
记得加上下行代码,关闭vip通道,不然可能会连不上nameserver
producer.setVipChannelEnabled(false);
http://www.daleizhou.tech/posts/rocketmq-remoting.html
https://my.oschina.net/bingoding/blog/685079

package com.liu.mq;

import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Author: beauty
 * @Date: 2020/5/6 11:15 上午
 */
public class SpringProducer {
    final static Logger logger = LoggerFactory.getLogger(SpringProducer.class);

    private String producerGroupName;

    private String nameServerAddr;

    private DefaultMQProducer producer;

    public SpringProducer(String producerGroupName, String nameServerAddr) {
        this.producerGroupName = producerGroupName;
        this.nameServerAddr = nameServerAddr;
    }

    public void init() throws Exception {
        logger.info("开始启动消息生产者服务...");

        //创建一个消息生产者,并设置一个消息生产者组
        producer = new DefaultMQProducer(producerGroupName);
        //指定 NameServer 地址
        producer.setNamesrvAddr(nameServerAddr);
        producer.setVipChannelEnabled(false);
        //初始化 SpringProducer,整个应用生命周期内只需要初始化一次
        producer.start();

        logger.info("消息生产者服务启动成功.");
    }

    public void destroy() {
        logger.info("开始关闭消息生产者服务...");

        producer.shutdown();

        logger.info("消息生产者服务已关闭.");
    }

    public DefaultMQProducer getProducer() {
        return producer;
    }

}

2、消息消费者

package com.liu.mq;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @Author: beauty
 * @Date: 2020/5/6 1:53 下午
 */
public class SpringConsumer {
    final static Logger logger = LoggerFactory.getLogger("SpringConsumer");

    private String consumerGroupName;

    private String nameServerAddr;

    private String topicName;

    private DefaultMQPushConsumer consumer;

    private MessageListenerConcurrently messageListener;

    public SpringConsumer(String consumerGroupName, String nameServerAddr, String topicName, MessageListenerConcurrently messageListener) {
        this.consumerGroupName = consumerGroupName;
        this.nameServerAddr = nameServerAddr;
        this.topicName = topicName;
        this.messageListener = messageListener;
    }


    public void init() throws Exception {
        logger.info("开始启动消息消费者服务...");

        //创建一个消息消费者,并设置一个消息消费者组
        consumer = new DefaultMQPushConsumer(consumerGroupName);
        //指定 NameServer 地址
        consumer.setNamesrvAddr(nameServerAddr);
        //设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);

        //订阅指定 Topic 下的所有消息
        consumer.subscribe(topicName, "*");

        //注册消息监听器
        consumer.registerMessageListener(messageListener);

        // 消费者对象在使用之前必须要调用 start 初始化
        consumer.start();

        logger.info("消息消费者服务启动成功.");
    }

    public void destroy(){
        logger.info("开始关闭消息消费者服务...");

        consumer.shutdown();

        logger.info("消息消费者服务已关闭.");
    }

    public DefaultMQPushConsumer getConsumer() {
        return consumer;
    }
}

3、消息监听器在接收到消息后执行具体的处理逻辑

package com.liu.mq;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.util.List;


/**
 * @Author: beauty
 * @Date: 2020/5/6 1:57 下午
 */
public class MessageListener implements MessageListenerConcurrently{
    final static Logger logger = LoggerFactory.getLogger("MessageListener");
    public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
        if (list != null) {
            for (MessageExt ext : list) {
                try {
                    logger.info("监听到消息 : " + new String(ext.getBody(), "UTF-8"));
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
        }
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
    }
}

4、生产者的xml配置
(因为你启的是本地的mq,所以nameserverAddr是本地地址,如果你想做单测,往公司的nameserver上发消息,需要问下开发你们公司的nameserver地址)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

    <bean id="producer" class="com.liu.mq.SpringProducer" init-method="init" destroy-method="destroy">
        <constructor-arg name="nameServerAddr" value="localhost:9876"/>
        <constructor-arg name="producerGroupName" value="MARKET-PRODUCER-GROUPNAME-NOTIFY"/>
    </bean>

</beans>

5、消费者的xml文件配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

    <bean id="messageListener" class="com.liu.mq.MessageListener" />

    <bean id="consumer" class="com.liu.mq.SpringConsumer" init-method="init" destroy-method="destroy">
        <constructor-arg name="nameServerAddr" value="localhost:9876"/>
        <constructor-arg name="consumerGroupName" value="spring_consumer_group"/>
        <constructor-arg name="topicName" value="spring-rocketMQ-topic" />
        <constructor-arg name="messageListener" ref="messageListener" />
    </bean>

</beans>

四、 调试

1、生产者单测

package com.liu.sptest.mq;

import com.liu.mq.SpringProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.apache.rocketmq.remoting.common.RemotingHelper;

public class SpringLocalProducerTest {

    private ApplicationContext container;

    @Before
    public void setup() {
        container = new ClassPathXmlApplicationContext("classpath:spring-producer.xml");
    }

    @Test
    public void sendMessage() throws Exception {
        SpringProducer producer = container.getBean(SpringProducer.class);

        for (int i = 0; i < 20; i++) {
            //创建一条消息对象,指定其主题、标签和消息内容
            Message msg = new Message(
                    "spring-rocketMQ-topic",
                    null,
                    ("Spring RocketMQ demo " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* 消息内容 */
            );

            //发送消息并返回结果
            SendResult sendResult = producer.getProducer().send(msg);

            System.out.printf("%s%n", sendResult);
        }
    }

}

2、消费者单测

package com.liu.sptest.mq;


import com.liu.mq.SpringConsumer;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Author: beauty
 * @Date: 2020/5/6 2:48 下午
 */
public class SpringConsumerTest {

    private ApplicationContext container;

    @Before
    public void setup() {
        container = new ClassPathXmlApplicationContext("classpath:spring-consumer.xml");
    }

    @Test
    public void consume() throws Exception {
        SpringConsumer consumer = container.getBean(SpringConsumer.class);

        Thread.sleep(200 * 1000);

        consumer.destroy();
    }
}

3、生产者单测执行结果

在这里插入图片描述
4、消费者单测结果

在这里插入图片描述

五、RocketMQ应用

例如你要用mq模拟消息测试用
可以直接把nameserver改成你们公司的,topic和tag和开发确认,直接用producer就可以发消息了,公司的应用就会消费你的mq
在平台也可以查到mq
在这里插入图片描述
参考资料来源:
https://blog.csdn.net/chenaima1314/article/details/79403113
https://my.oschina.net/bingoding/blog/685079
https://blog.csdn.net/wd2014610/article/details/79867322
https://juejin.im/post/5af02571f265da0b9e64fcfd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值