学习RocketMQ,先写一个Demo演示一下看看效果。

一、服务端部署

  因为只是简单的为了演示效果,服务端仅部署单Master模式 —— 一个Name Server节点,一个Broker节点。主要有以下步骤。

    1. 下载RocketMQ源码、编译(也可以网上下载编译好的文件),这里使用最新的4.4.0版本,下载好之后放在Linux上通过一下命令解压缩、编译。

      unzip rocketmq-all-4.4.-source-release.zip
      cd rocketmq-all-4.4./
      mvn -Prelease-all -DskipTests clean install –U
    2. 编译之后到distribution/target/apache-rocketmq目录,后续所有操作都是在该路径下。
      cd distribution/target/apache-rocketmq
    3. 启动Name Server,查看日志确认启动成功。
      nohup sh bin/mqnamesrv &
      tail -f ~/logs/rocketmqlogs/namesrv.log
    4. 启动Broker,查看日志确认启动成功。
      nohup sh bin/mqbroker -n localhost: &
      tail -f ~/logs/rocketmqlogs/broker.log

  Name Server和Broker都成功启动,服务器就部署完成了。更详细的参考官方文档手册,里面还包含在服务器上运行Producer、Customer示例,这里主要是在项目中使用。

  官网手册戳这里:Quick Start

二、客户端搭建:Spring Boot项目中使用

  客户端分为消息生产者和消息消费者,这里通过日志打印输出查看效果,为了看起来更清晰,我新建了两个模块分别作为消息生产者和消息消费者。

  1. 添加依赖,在两个模块的pom文件中添加以下配置。

    <dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.4.0</version>
    </dependency>
  2. 配置生产者模块。
    • application.yml文件中增加用来初始化producer的相关配置,这里只配了一部分,更详细的配置参数可以查看官方文档。

      # RocketMQ生产者
      rocketmq:
      producer:
      # Producer组名,多个Producer如果属于一个应用,发送同样的消息,则应该将它们归为同一组。默认DEFAULT_PRODUCER
      producerGroup: ${spring.application.name}
      # namesrv地址
      namesrvAddr: 192.168.101.213:9876
      # 客户端限制的消息大小,超过报错,同时服务端也会限制,需要跟服务端配合使用。默认4MB
      maxMessageSize: 4096
      # 发送消息超时时间,单位毫秒。默认10000
      sendMsgTimeout: 5000
      # 如果消息发送失败,最大重试次数,该参数只对同步发送模式起作用。默认2
      retryTimesWhenSendFailed: 2
      # 消息Body超过多大开始压缩(Consumer收到消息会自动解压缩),单位字节。默认4096
      compressMsgBodyOverHowmuch: 4096
      # 在发送消息时,自动创建服务器不存在的topic,需要指定Key,该Key可用于配置发送消息所在topic的默认路由。
      createTopicKey: XIAO_LIU
    • 新增producer配置类,系统启动时读取yml文件的配置信息初始化producer。集群模式下,如果在同一个jvm中,要往多个的MQ集群发送消息,则需要创建多个的producer并设置不同的instanceName,默认不需要设置该参数。
      @Configuration
      public class ProducerConfiguration {
      private static final Logger LOGGER = LoggerFactory.getLogger(ProducerConfiguration.class); /**
      * Producer组名,多个Producer如果属于一个应用,发送同样的消息,则应该将它们归为同一组。默认DEFAULT_PRODUCER
      */
      @Value("${rocketmq.producer.producerGroup}")
      private String producerGroup;
      /**
      * namesrv地址
      */
      @Value("${rocketmq.producer.namesrvAddr}")
      private String namesrvAddr;
      /**
      * 客户端限制的消息大小,超过报错,同时服务端也会限制,需要跟服务端配合使用。默认4MB
      */
      @Value("${rocketmq.producer.maxMessageSize}")
      private Integer maxMessageSize;
      /**
      * 发送消息超时时间,单位毫秒。默认10000
      */
      @Value("${rocketmq.producer.sendMsgTimeout}")
      private Integer sendMsgTimeout;
      /**
      * 如果消息发送失败,最大重试次数,该参数只对同步发送模式起作用。默认2
      */
      @Value("${rocketmq.producer.retryTimesWhenSendFailed}")
      private Integer retryTimesWhenSendFailed;
      /**
      * 消息Body超过多大开始压缩(Consumer收到消息会自动解压缩),单位字节。默认4096
      */
      @Value("${rocketmq.producer.compressMsgBodyOverHowmuch}")
      private Integer compressMsgBodyOverHowmuch;
      /**
      * 在发送消息时,自动创建服务器不存在的topic,需要指定Key,该Key可用于配置发送消息所在topic的默认路由。
      */
      @Value("${rocketmq.producer.createTopicKey}")
      private String createTopicKey; @Bean
      public DefaultMQProducer getRocketMQProducer() { DefaultMQProducer producer = new DefaultMQProducer(this.producerGroup);
      producer.setNamesrvAddr(this.namesrvAddr);
      producer.setCreateTopicKey(this.createTopicKey); if (this.maxMessageSize != null) {
      producer.setMaxMessageSize(this.maxMessageSize);
      }
      if (this.sendMsgTimeout != null) {
      producer.setSendMsgTimeout(this.sendMsgTimeout);
      }
      if (this.retryTimesWhenSendFailed != null) {
      producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
      }
      if (this.compressMsgBodyOverHowmuch != null) {
      producer.setCompressMsgBodyOverHowmuch(this.compressMsgBodyOverHowmuch);
      }
      if (Strings.isNotBlank(this.createTopicKey)) {
      producer.setCreateTopicKey(this.createTopicKey);
      } try {
      producer.start(); LOGGER.info("Producer Started : producerGroup:[{}], namesrvAddr:[{}]"
      , this.producerGroup, this.namesrvAddr);
      } catch (MQClientException e) {
      LOGGER.error("Producer Start Failed : {}", e.getMessage(), e);
      }
      return producer;
      } }
    • 使用producer实例向MQ发送消息。
      @RunWith(SpringRunner.class)
      @SpringBootTest
      public class ProducerServiceApplicationTests {
      private static final Logger LOGGER = LoggerFactory.getLogger(ProducerServiceApplicationTests.class);
      @Autowired
      private DefaultMQProducer defaultMQProducer; @Test
      public void send() throws MQClientException, RemotingException, MQBrokerException, InterruptedException, UnsupportedEncodingException {
      for (int i = 0; i < 100; i++) {
      User user = new User();
      user.setUsername("用户" + i);
      user.setPassword("密码" + i);
      user.setSex(i % 2);
      user.setBirthday(new Date());
      Message message = new Message("user-topic", "user-tag", JSON.toJSONString(user).getBytes(RemotingHelper.DEFAULT_CHARSET));
      SendResult sendResult = defaultMQProducer.send(message);
      LOGGER.info(sendResult.toString());
      }
      }
      }
  3. 配置消费者模块。
    • application.yml文件中增加用来初始化consumer的相关配置,同样参数这里只配了一部分,更详细的配置参数可以查看官方文档。

      # RocketMQ消费者
      rocketmq:
      consumer:
      # Consumer组名,多个Consumer如果属于一个应用,订阅同样的消息,且消费逻辑一致,则应该将它们归为同一组。默认DEFAULT_CONSUMER
      consumerGroup: ${spring.application.name}
      # namesrv地址
      namesrvAddr: 192.168.101.213:9876
      # 消费线程池最大线程数。默认10
      consumeThreadMin: 10
      # 消费线程池最大线程数。默认20
      consumeThreadMax: 20
      # 批量消费,一次消费多少条消息。默认1
      consumeMessageBatchMaxSize: 1
      # 批量拉消息,一次最多拉多少条。默认32
      pullBatchSize: 32
      # 订阅的主题
      topics: user-topic
    • 新增consumer配置。
      @Configuration
      public class ConsumerConfiguration {
      private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerConfiguration.class); @Value("${rocketmq.consumer.consumerGroup}")
      private String consumerGroup;
      @Value("${rocketmq.consumer.namesrvAddr}")
      private String namesrvAddr;
      @Value("${rocketmq.consumer.consumeThreadMin}")
      private int consumeThreadMin;
      @Value("${rocketmq.consumer.consumeThreadMax}")
      private int consumeThreadMax;
      @Value("${rocketmq.consumer.consumeMessageBatchMaxSize}")
      private int consumeMessageBatchMaxSize;
      @Value("${rocketmq.consumer.pullBatchSize}")
      private int pullBatchSize;
      @Value("${rocketmq.consumer.topics}")
      private String topics; private final ConsumeMsgListener consumeMsgListener; @Autowired
      public ConsumerConfiguration(final ConsumeMsgListener consumeMsgListener) {
      this.consumeMsgListener = consumeMsgListener;
      } @Bean
      public DefaultMQPushConsumer getRocketMQConsumer() {
      DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(consumerGroup);
      consumer.setNamesrvAddr(namesrvAddr);
      consumer.setConsumeThreadMin(consumeThreadMin);
      consumer.setConsumeThreadMax(consumeThreadMax);
      consumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
      consumer.setPullBatchSize(pullBatchSize);
      consumer.registerMessageListener(consumeMsgListener); try {
      /**
      * 设置消费者订阅的主题和tag。subExpression参数为*表示订阅该主题下所有tag,
      * 如果需要订阅该主题下的指定tag,subExpression设置为对应tag名称,多个tag以||分割,例如"tag1 || tag2 || tag3"
      */
      consumer.subscribe(topics, "*");
      consumer.start(); LOGGER.info("Consumer Started : consumerGroup:{}, topics:{}, namesrvAddr:{}", consumerGroup, topics, namesrvAddr);
      } catch (Exception e) {
      LOGGER.error("Consumer Start Failed : consumerGroup:{}, topics:{}, namesrvAddr:{}", consumerGroup, topics, namesrvAddr, e);
      e.printStackTrace();
      }
      return consumer;
      }
      }
    • 新增消息监听器,监听到新消息后,执行对应的业务逻辑。

      @Component
      public class ConsumeMsgListener implements MessageListenerConcurrently {
      private static final Logger LOGGER = LoggerFactory.getLogger(ConsumeMsgListener.class); @Override
      public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
      if (CollectionUtils.isEmpty(msgs)) {
      LOGGER.info("Msgs is Empty.");
      return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
      }
      for (MessageExt msg : msgs) {
      try {
      if ("user-topic".equals(msg.getTopic())) {
      LOGGER.info("{} Receive New Messages: {}", Thread.currentThread().getName(), new String(msg.getBody()));
      // do something
      }
      } catch (Exception e) {
      if (msg.getReconsumeTimes() == 3) {
      // 超过3次不再重试
      LOGGER.error("Msg Consume Failed.");
      return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
      } else {
      // 重试
      return ConsumeConcurrentlyStatus.RECONSUME_LATER;
      }
      }
      } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
      }
      }
三、效果
  1. 运行生产者测试代码。系统启动时初始化Producer,然后执行测试代码,往MQ中发送消息。效果如下:
  2. 启动消费者服务。系统启动时先初始化Customer。此时1.已经往MQ中发送了一些消息,监听器监听到MQ中有消息,随即马上消费消息。
四、总结

  Demo很简单,但是里面还有很多东西需要慢慢研究。

  代码可以戳这里:spring-cloud-learn

RocketMQ入门案例的更多相关文章

  1. RocketMQ入门到入土(二)事务消息&顺序消息

    接上一篇:RocketMQ入门到入土(一)新手也能看懂的原理和实战! 一.事务消息的由来 1.案例 引用官方的购物案例: 小明购买一个100元的东西,账户扣款100元的同时需要保证在下游的积分系统给小 ...

  2. SpringMVC入门案例及请求流程图(关于处理器或视图解析器或处理器映射器等的初步配置)

    SpringMVC简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 Spring结构图 Spr ...

  3. SpringMvc核心流程以及入门案例的搭建

    1.什么是SpringMvc Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面.Spring 框架提供了构建 Web 应用程序的全功能 M ...

  4. Struts2第一个入门案例

      一.如何获取Struts2,以及Struts2资源包的目录结构的了解    Struts的官方地址为http://struts.apache.org 在他的主页当中,我们可以通过左侧的Apache ...

  5. MyBatis入门案例、增删改查

    一.MyBatis入门案例: ①:引入jar包 ②:创建实体类 Dept,并进行封装 ③ 在Src下创建大配置mybatis-config.xml <?xml version="1.0 ...

  6. Hibernate入门案例及增删改查

    一.Hibernate入门案例剖析: ①创建实体类Student 并重写toString方法 public class Student { private Integer sid; private I ...

  7. Quartz应用实践入门案例二(基于java工程)

    在web应用程序中添加定时任务,Quartz的简单介绍可以参看博文<Quartz应用实践入门案例一(基于Web应用)> .其实一旦学会了如何应用开源框架就应该很容易将这中框架应用与自己的任 ...

  8. Quartz应用实践入门案例一(基于Web环境)

    Quartz是一个完全由java编写的开源作业调度框架,正是因为这个框架整合了许多额外的功能,所以在使用上就显得相当容易.只是需要简单的配置一下就能轻松的使用任务调度了.在Quartz中,真正执行的j ...

  9. MyBatis入门案例 增删改查

    一.MyBatis入门案例: ①:引入jar包 ②:创建实体类 Dept,并进行封装 ③ 在Src下创建大配置mybatis-config.xml <?xml version="1.0 ...

随机推荐

  1. 小程序跳转tabbar页面

    如果在app.json 配置tabbar 的时候配置了 跳转的页面的链接: 在其余的子页面,设置用navigator 进行跳转会发现 在tabbar 设置过的页面无法进行跳转,这时需要在navigat ...

  2. mui框架下拉刷新和上拉刷新

    当初写的时候,是用的谷歌浏览器测试的,都可以正常刷新,下载到手机上面,在ios是可以刷新的,在安卓上面就刷新不了,就是拉不动,后来慢慢排除不是HTML的原因,是上下拉代码有问题,刚开始看的时候也没问题 ...

  3. 《Linux就该这么学》第十六天课程

    今天笔记有点少就不发了,分享一下第23章 使用OpenLDAP部署目录服务很实用 下面是DHCP动态管理地址,如需深入学习请前往 https://www.linuxprobe.com/chapter- ...

  4. Eclipse搭建SSH框架(Struts2+Spring+Hibernate)

    见识少的我经过一天多的研究才知道,在MyEclipse中搭好的框架的配置文件和jar包是通用的.接下来——亮剑! 工具:Eclipse+Tomcat+Mysql 一.先在Eclipse中配置好Tomc ...

  5. c++中二级指针的使用场景

    二级指针的使用场景如下: 1.主要用来为指针变量分配内存空间: void GetMemory(char **p) { *p = ]; } 函数调用方式: char *str = NULL; GetMe ...

  6. Office Web addin 踩坑计:替换后台网站为MVC框架时遇到的问题

    Office Web Addin 模板程序的后台本质上是一个网站,你在调试的时候可以发现它的进程是一个32位的IE进程 所以可以把它替换成Asp.net的网站. 替换方法: 1.点击WordRevie ...

  7. 读书笔记二 How Does the Internet work?

    原文链接:  https://web.stanford.edu/class/msande91si/www-spr04/readings/week1/InternetWhitepaper.htm 先写写 ...

  8. 'An instance 0x155e74a0 of class UIWebView was deallocated while key value observers were still registered with it.

    在iOS和html混编的时候,当用iOS原生的navigation导航pop回去的时候,出现 *** Terminating app due to uncaught exception 'NSInte ...

  9. C++的学习心得

    由于我们大一就学习的c++,跳过了c语言,VB的学习,在很多方面我们掌握的并不是特别好,在这几种语言中,几乎有时候会产生混淆,通过做大量的c++的题目感觉在题目中应用的最多的就是数组.指针.对类的应用 ...

  10. 背水一战 Windows 10 (114) - 后台任务: 后台任务的 Demo(与 app 不同进程), 后台任务的 Demo(与 app 相同进程)

    [源码下载] 背水一战 Windows 10 (114) - 后台任务: 后台任务的 Demo(与 app 不同进程), 后台任务的 Demo(与 app 相同进程) 作者:webabcd 介绍背水一 ...