RocketMQ

本文介绍了消息中间件的作用,如异步处理和应用解耦,重点讲解了RocketMQ的架构、角色以及在下单场景中的应用。对比了常见消息中间件的特点,并提供了发送同步/异步消息及消费消息的方法示例。

什么是消息中间件


        消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。对于消息中间件,常见的角色大致也就有Producer(生产者)、Consumer(消费者)例如:寄快递

消息中间件使用场景


异步处理

场景说明:用户注册后,需要发注册邮件和注册短信

传统的做法有两种

a.串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信,以上三个任务全部完成后,返回给客户端

 b.并行方式:将注册信息写入数据库成功后,发送注册邮件的同时发送注册短信,以上三个任务完成后,返回给客户端;与串行的差别是并行的方式可以提高处理的时间

引入消息队列,改造后的架构如下: 

        按照以上约定,用户的响应时间相当于是注册信息写入数据库的时间,也就是50毫秒。注册邮件,发送短信写入消息队列后,直接返回,因此写入消息队列的速度很快,基本可以忽略,因此架构改变后,系统的吞吐量比串行提高了3倍,比并行提高了2倍。

应用解耦

场景说明:用户下单后,订单系统需要通知库存系统,传统的做法是订单系统调用库存系统的接口

订单系统:假如在下单时库存系统不能正常使用,也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了,实现订单系统与库存系统的应用解耦 。

常见消息中间件比较

特性MQActiveMQRabbitMQRocketMQKafka
生产者消费者模式支持支持支持支持
发布订阅模式支持支持支持支持
请求回应模式支持支持不支持不支持
Api完备性
多语言支持支持支持java支持
单机吞吐量万级万级万级十万级
消息延迟微秒级毫秒级毫秒级
可用性高(主从)高(主从)非常高(分布式)非常高(分布式)
消息丢失理论上不会丢失理论上不会丢失
文档的完备性较高
提供快速入门
社区活跃度
商业支持商业云商业云

RocketMQ

        RocketMQ是阿里巴巴开源的分布式消息中间件,现在是Apache的一个顶级项目。在阿里内部使用非常广泛。

如上图所示,整体可以分成4个角色,分别是:NameServer,Broker,Producer,Consumer Broker(邮递员)

  • Broker是RocketMQ的核心,负责消息的接收,存储,投递等功能

NameServer(邮局)

  • 消息队列的协调者,Broker向它注册路由信息,同时Producer和Consumer向其获取路由信息

Producer(寄件人)

  • 消息的生产者,需要从NameServer获取Broker信息,然后与Broker建立连接,向Broker发送消息

Consumer(收件人)

  • 消息的消费者,需要从NameServer获取Broker信息,然后与Broker建立连接,从Broker获取消息

Topic(地区)

  • 用来区分不同类型的消息,发送和接收消息前都需要先创建Topic,针对Topic来发送和接收消息

Message Queue(邮件)

  • 为了提高性能和吞吐量,引入了Message Queue,一个Topic可以设置一个或多个Message Queue,这样消息就可以并行往各个Message Queue发送消息,消费者也可以并行的从多个 Message Queue读取消息

Message

  • Message 是消息的载体。

消息发送和接收演示


发送同步消息

这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。

消息发送步骤:

  1. 创建消息生产者, 指定生产者所属的组名
  2. 指定Nameserver地址
  3. 启动生产者
  4. 创建消息对象,指定主题、标签和消息体
  5. 发送消息
  6. 关闭生产者
    //发送消息
    public class RocketMQSendTest {
        public static void main(String[] args) throws Exception {
            //1. 创建消息生产者, 指定生产者所属的组名
            DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");
            //2. 指定Nameserver地址
            producer.setNamesrvAddr("192.168.109.131:9876");
            //3. 启动生产者
            producer.start();
            //4. 创建消息对象,指定主题、标签和消息体
            Message msg = new Message("myTopic", "myTag", ("RocketMQ
                    Message").getBytes());
            //5. 发送消息
            SendResult sendResult = producer.send(msg);
            System.out.println(sendResult);
            //6. 关闭生产者
            producer.shutdown();
        }
    }

接收消息消息接收步骤:

  1. 创建消息消费者, 指定消费者所属的组名

  2. 指定Nameserver地址

  3. 指定消费者订阅的主题和标签

  4. 设置回调函数,编写处理消息的方法

  5. 启动消息消费者

​
//接收消息
public class RocketMQReceiveTest {
    public static void main(String[] args) throws MQClientException {
        //1. 创建消息消费者, 指定消费者所属的组名
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("myconsumergroup");
        //2. 指定Nameserver地址
        consumer.setNamesrvAddr("192.168.109.131:9876");
        //3. 指定消费者订阅的主题和标签
        consumer.subscribe("myTopic", "*");
        //4. 设置回调函数,编写处理消息的方法
        consumer.registerMessageListener(new MessageListenerConcurrently() {
            @Override
            public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt>
                                                                    msgs, ConsumeConcurrentlyContext context) {
                System.out.println("Receive New Messages: " + msgs);
                //返回消费状态
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            }
        });
        //5. 启动消息消费者
        consumer.start();
        System.out.println("Consumer Started.");
    }
}

​

发送异步消息

异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。

    //1. 创建消息生产者, 指定生产者所属的组名
    DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");
    //2. 指定Nameserver地址
    producer.setNamesrvAddr("127.0.0.1:9876");
    //3. 启动生产者
    producer.start();
    for (int i = 0;i<10;i++){
        //4. 创建消息对象,指定主题、标签和消息体
        Message msg = new Message("myTopic", "myTag2", ("防疫政策修改
        ~~~").getBytes());
        //5. 发送消息
        producer.send(msg, new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        System.out.println("发送成功:"+sendResult);
                    }
                    @Override
                    public void onException(Throwable e) {
                        System.out.println("发送异常:"+e);
                    }
                }
        );
        TimeUnit.SECONDS.sleep(3);
    }
    //6. 关闭生产者
    producer.shutdown();

单向发送消息

这种方式主要用在不特别关心发送结果的场景,例如日志发送。

//1. 创建消息生产者, 指定生产者所属的组名
DefaultMQProducer producer = new DefaultMQProducer("myproducer-group");
//2. 指定Nameserver地址
producer.setNamesrvAddr("127.0.0.1:9876");
//3. 启动生产者
producer.start();
for (int i = 0;i<10;i++){
        //4. 创建消息对象,指定主题、标签和消息体
        Message msg = new Message("myTopic", "myTag3", ("防疫政策修改
        ~~~").getBytes());
        //5. 发送消息
        // 发送单向消息,没有任何返回结果
        producer.sendOneway(msg);
        TimeUnit.SECONDS.sleep(3);
    }
//6. 关闭生产者
producer.shutdown();

消费消息

1. 负载均衡模式(默认方式)

消费者采用负载均衡方式消费消息,多个消费者共同消费队列消息,每个消费者处理的消息不同

2. 广播模式

消费者采用广播的方式消费消息,每个消费者消费的消息都是相同的

使用场景


接下来我们模拟一种场景: 下单成功之后,向下单用户发送短信

 订单微服务发送消息

rocketmq:
    name-server: 127.0.0.1:9876 #rocketMQ服务的地址
    producer:
        group: shop-order #生产者组
    @RestController
    @Slf4j
    public class OrderController2 {
        @Autowired
        private OrderService orderService;
        @Autowired
        private ProductService productService;
        @Autowired
        private RocketMQTemplate rocketMQTemplate;
        //准备买1件商品
        @GetMapping("/order/prod/{pid}")
        public Order order(@PathVariable("pid") Integer pid) {
            //通过fegin调用商品微服务
            Product product = productService.findByPid(pid);
            if (product == null){
                Order order = new Order();
                order.setPname("下单失败");
                return order;
            }
            Order order = new Order();
            order.setUid(1);
            order.setUsername("测试用户");
            order.setPid(product.getPid());
            order.setPname(product.getPname());
            order.setPprice(product.getPprice());
            order.setNumber(1);
            orderService.save(order);
            //下单成功之后,将消息放到mq中
            rocketMQTemplate.convertAndSend("order-topic", order);
            return order;
    }
}

用户微服务订阅消息

rocketmq:
    name-server: 127.0.0.1:9876
    //发送短信的服务
    @Slf4j
    @Service
    @RocketMQMessageListener(consumerGroup = "shop-user", topic = "order-topic")
    public class SmsService implements RocketMQListener<Order> {
        @Override
        public void onMessage(Order order) {
            log.info("收到一个订单信息{},接下来发送短信", JSON.toJSONString(order));
        }
    }

### RocketMQ 消息队列使用指南与最新版本下载 RocketMQ 是一款高性能、高可靠的分布式消息中间件,广泛应用于大规模数据处理和高并发场景中。它支持多种消息类型,包括普通消息、顺序消息、事务消息等,并提供了灵活的消息过滤机制和强大的消息堆积能力。 在使用 RocketMQ 时,首先需要根据业务需求选择合适的消息类型和通信模式。例如,生产者可以通过 `DefaultMQProducer` 类发送消息,而消费者则通过 `DefaultMQPushConsumer` 类订阅并消费消息。此外,RocketMQ 支持广播和集群两种消费模式,适用于不同的应用场景[^3]。 以下是一个简单的 RocketMQ 生产者代码示例: ```java import org.apache.rocketmq.client.exception.MQClientException; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message; public class Producer { public static void main(String[] args) throws MQClientException, InterruptedException { // 实例化一个生产者组 DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName"); // 设置NameServer地址 producer.setNamesrvAddr("localhost:9876"); // 启动生产者实例 producer.start(); for (int i = 0; i < 10; i++) { try { Message msg = new Message("TopicTest", "TagA", "OrderID188".getBytes()); producer.send(msg); } catch (Exception e) { e.printStackTrace(); } } // 关闭生产者实例 producer.shutdown(); } } ``` 对于消费者的实现,可以参考如下代码片段: ```java import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.listener.*; import org.apache.rocketmq.common.message.MessageExt; public class Consumer { public static void main(String[] args) throws MQClientException { // 实例化消费者组 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName"); // 设置NameServer地址 consumer.setNamesrvAddr("localhost:9876"); // 订阅主题及标签 consumer.subscribe("TopicTest", "*"); // 注册监听器处理消息 consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> { for (MessageExt msg : msgs) { System.out.println("收到消息:" + new String(msg.getBody())); } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; }); // 启动消费者 consumer.start(); System.out.println("消费者已启动"); } } ``` 关于 RocketMQ 的安装与配置,可以从官方网站或 GitHub 仓库获取最新的源码或二进制文件。当前最新稳定版本为 **4.9.4**(截至2023年),可以通过访问 [RocketMQ GitHub Releases 页面](https://github.com/apache/rocketmq/releases) 下载所需的版本。安装完成后,还需配置 NameServer 和 Broker 服务以构建完整的消息队列环境[^1]。 为了更好地管理和监控 RocketMQ 集群,推荐安装 RocketMQ 控制台(RocketMQ Dashboard)。该图形界面工具可以帮助开发者直观地查看队列状态、管理主题以及跟踪消息轨迹。控制台的安装通常涉及克隆项目仓库、修改配置文件中的 NameServer 地址,并运行应用服务器(如 Tomcat)来部署 WAR 文件[^1]。 最后,在实际开发过程中,建议将 RocketMQ 的操作封装成独立的服务组件,以便于维护和扩展。例如,在 ASP.NET Core 应用程序中,可以通过依赖注入的方式创建 RocketMQ 服务类,从而实现更优雅的消息处理逻辑[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值