RocketMQ系列1:基础介绍

★消息队列16篇

1 认识RocketMQ

RocketMQ是一款基于Java开发的分布式消息中间件,它以其高性能、高可靠性、高实时性以及分布式特性而广受好评。

它支持事务消息、顺序消息、批量消息、定时消息、消息回溯等。互联网场景中经常使用RocketMQ进行消息路由、订阅发布、异步解耦、流量削减峰等操作,来缓解系统的压力。

2 三种常见的消息中间件比较

特性 RabbitMQ RocketMQ Kafka
开发语言 erlang java scala
单机吞吐量 1w+ 10w+ 10w+
时效性 us级 ms级 ms级以内
可用性 高(主从架构) 非常高(分布式架构) 非常高(分布式架构)
消息可靠性 基本不丢 参数化配置和持久化:基本不丢 参数化配置和持久化:基本不丢
功能特性 基于erlang开发,所以并发能力很强,性能极其好,延时很低;管理界面较丰富 MQ功能比较完备,扩展性佳 只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广。
生态 开源、稳定、社区活跃度高 阿里开源,交给Apache,社区活跃度低 Apache开发,开源、高吞吐量、社区活跃度高

技术选型决策参考:

(1)中小型软件,建议选RabbitMQ, 中小型软件数据量没那么大,选消息中间件,应首选功能比较完备的,所以kafka排除。

不考虑rocketmq的原因是,rocketmq是阿里出品,如果阿里放弃维护rocketmq,中小型公司一般抽不出人来进行rocketmq的定制化开发,因此不推荐。

(2)大型软件公司,根据具体使用在rocketMq和kafka之间二选一。一方面,大型软件公司,具备足够的资金搭建分布式环境,也具备足够大的数据量。

针对rocketMQ,大型软件公司也可以抽出人手对rocketMQ进行定制化开发,毕竟有能力改JAVA源码的人,还是相当多的。

至于kafka,根据业务场景选择,如果有日志采集功能,肯定是首选kafka了。具体该选哪个,看使用场景。引入MQ之后,必然导致系统可用性降低,复杂性增大。

3 消息中间件使用场景

1. 解耦: 比如说系统A会交给系统B去处理一些事情,但是A不想直接跟B有关联,避免耦合太强,就可以通过在A,B中间加入消息队列,A将要任务的事情交给消息队列 ,B订阅消息队列来执行任务。

这种场景很常见,比如A是订单系统,B是库存系统,可以通过消息队列把削减库存的工作交予B系统去处理。如果A系统同时想让B、C、D...多个系统处理问题的时候,这种优势就更加明显了。

2. 有序性: 先进先出原理,先来先处理,比如一个系统处理某件事需要很长一段时间,但是在处理这件事情时候,有其他人也发出了请求,可以把请求放在消息队里,一个一个来处理。

对数据的顺序性和一致性有强需求的业务,比如同一张银行卡同时被多个入口使用,需要保证入账出账的顺序性,避免出现数据不一致。

3. 消息路由/数据分发: 按照不同的规则,将队列中消息发送到不同的其他队列中

通过消息队列将不同染色的请求发送到不同的服务去操作。这样达成了流量按照业务拆分的目的。

4、异步处理: 处理一项任务的时候,有3个步骤A、B、C,需要先完成A操作, 然后做B、C 操作。任务执行成功与否强依赖A的结果,但不依赖B、C 的结果。

如果我们使用串行的执行方式,那处理任务的周期就会变长,系统的整体吞吐能力也会降低(在同一个系统中做异步其实也是比较大的开销),所以使用消息队列是比较好的办法。

登录操作就是典型的场景:A:执行登录并得到结果、B:记录登录日志、C:将用户信息和Token写入缓存。 执行完A就可以从登录页跳到首页了,B、C让服务慢慢去消化,不阻塞当前操作。

5、削峰: 将峰值期间的操作削减,比如A同学的整个操作流程包含12个步骤,后续的11个步骤是不需要强关注结果的数据,可以放在消息队列中。

4 MQ的概念、结构和原理

4.1 构成说明

RocketMQ主要有四大核心组成部分:NameServer、Broker、Producer以及Consumer四部分。这些角色通常以集群的方式存在,RocketMQ 基于纯Java开发,具有高吞吐量、高可用性、适合大规模分布式系统应用的特点。

  • RockerMQ想要启动,首先需要启动 NameServer,再启动 Brober 主机
  • Broker 会向 NameServer 注册对应的路由和服务
  • Producer会进行路的发现,向NameServer请求Broker路由信息,进行消息的发送
  • Consumer要连通NameServer,获取到相关的路由信息,方便我们进行消息的订阅
  • Broker 主要负责消息的存储,不管是生产消息还是订阅消息,消息的来源都是 Broker,
  • 消息的发送(Producer)只会发到主节点,然后Broker会进行消息的同步,同步到从节点,作为消费者(Consumer)也只会优先从Master节点,获取消息,进行消费
  • Broker主节点不可用或者非常繁忙,会选择从节点进行消费

1. Producer:

负责生产消息,一般由业务系统负责。生产者通过调用API将消息发送到指定的Topic(主题)中。

2. Broker:

消息存储中心,负责接收来自Producer的消息并存储,同时Consumer也从这里取得消息。Broker还存储与消息相关的元数据,包括消费者组、消费进度偏移量、队列信息等。每个Broker可以存储多个Topic的消息,每个Topic的消息也可以分片存储于不同的Broker。在实际部署中,Broker对应一台服务器,并分为Master与Slave两种类型,Master负责读写,Slave只负责读,以此实现数据的备份和负载均衡。

3. Consumer:

负责消费消息,一般由后台系统负责。消费者通过订阅Topic来获取消息,并根据业务逻辑进行处理。消费者可以以集群消费或广播消费的方式消费消息。

4. NameServer:

充当路由消息的提供者,负责保存Broker的元数据信息,并供Producer和Consumer查询。NameServer被设计成几乎无状态的,可以横向扩展,节点之间无通信。

4.2 基础概念

4.2.1 Group(分组)

在RocketMQ中,Group功能是其核心特性之一。Group主要分为发送端Group和消费端Group。

  • 发送端Group:允许将多个发送者(Producer)组织成一个发送者组。通过发送端Group,可以实现对消息的批量处理和负载均衡,提高系统性能和可靠性。
  • 消费端Group:RocketMQ允许消费者同时订阅多个主题(Topic),这些消费者可以被组织成一个或多个消费组。消费组内的消费者可以共同分担消息的消费任务,实现负载均衡和容错。当某个消费者出现故障时,其他消费者可以接管其消费任务,确保消息被及时处理。同时,消费组还支持消息过滤和顺序消费等高级特性。

4.2.2 Topic(主题)

用来区分消息的种类,表示一类消息的逻辑名字,消息的逻辑管理单位,无论生产还是消费消息,都需要执行Topic。比如一个Topic专门用于用户订单消息发送,一个Topic专门用于扣减或增加积分的。

  • 一个发送者可以发送消息给一个或者多个Topic
  • 一个消息接受者可以订阅一个或多个Topic消息

4.2.3 Message Queue(消息队列)

MessageQueue是RocketMQ中用于存储和传输消息的数据结构。每个MessageQueue都有一个唯一标识符,由Topic名称和队列编号组成。MessageQueue具有以下特点:

  • 唯一标识:确保每个MessageQueue都可以被唯一地识别和定位。
  • 消息顺序性:对于同一个MessageQueue中的消息,RocketMQ保证其消费的顺序性,即先进先出(FIFO)。
  • 负载均衡:RocketMQ通过动态调整消息分配策略,将消息均匀地分布到所有的MessageQueue中,实现负载均衡,避免某个MessageQueue过载而其他MessageQueue空闲的情况。
  • 高可用性:RocketMQ支持将多个Broker节点组成集群,每个MessageQueue可以在不同的Broker节点上进行主从复制,提供高可用性和数据冗余。即使某个Broker节点出现故障,其他节点也可以继续提供服务,确保消息的可靠传输。

4.2.4 Tag(标签)

Tag是RocketMQ中用于对消息进行分类和过滤的标记。生产者可以在发送消息时指定Tag,消费者可以根据Tag来过滤和订阅消息。Tag的使用可以使得消息的管理和消费更加灵活和高效。例如,一个电商系统可能会根据商品的类别(如服装、电子产品等)来设置不同的Tag,消费者可以根据这些Tag来订阅和处理特定类别的消息。

4.2.5 Offset(偏移量)

Offset在RocketMQ中用于标识消费者在消息队列中的位置。每个消费者都会维护一个Offset,以便知道下一次从哪里开始消费。Offset的使用可以确保消息不丢失、避免消息重复消费以及支持消息的顺序消费。

  • Message queue 是无限长的数组。一条消息进来下标就会涨 1,而这个数组的下标就是 offset。
  • 确保消息不丢失:通过持久化Offset,即使在消费者宕机后重启,也能从上次消费的位置继续消费,保证消息至少被消费一次。
  • 避免消息重复消费:消费者在成功处理消息后更新Offset,确保每条消息只被消费一次。
  • 支持消息顺序消费:对于顺序消息,通过维护Offset可以保证消息的顺序消费。

5 程序实现

5.1 Java中引入和实现RocketMQ

  1. 引入依赖

    在Java项目中,通常通过Maven或Gradle等构建工具来引入RocketMQ的客户端依赖。以Maven为例,可以在pom.xml文件中添加以下依赖:

    xml 复制代码
    <dependency>
        <groupId>org.apache.rocketmq</groupId>
        <artifactId>rocketmq-client</artifactId>
        <version>最新版本号(5.3.1)</version>
    </dependency>
  2. 实现生产者

    在Java中,通过创建DefaultMQProducer对象来实现消息的生产者。生产者需要设置NameServer地址,并调用start()方法初始化。然后,可以创建Message对象并设置主题、标签和消息内容,最后调用send()方法发送消息。

    java 复制代码
    public class Producer {
        public static void main(String[] args) throws Exception {
            // 创建一个消息生产者,并设置消息生产者组
            DefaultMQProducer producer = new DefaultMQProducer("your_producer_group");
            // 指定NameServer地址
            producer.setNamesrvAddr("your_nameserver_address");
            // 初始化Producer
            producer.start();
    
            // 创建消息对象,并设置主题、标签和消息内容
            Message msg = new Message("your_topic", "your_tag", "Hello RocketMQ".getBytes());
            // 发送消息并获取发送结果
            SendResult sendResult = producer.send(msg);
            System.out.printf("%s%n", sendResult);
    
            // 关闭生产者实例
            producer.shutdown();
        }
    }
  3. 实现消费者

    在Java中,通过创建DefaultMQPushConsumer对象来实现消息的消费者。消费者需要设置NameServer地址和消费组名称,并调用subscribe()方法订阅主题和标签。然后,注册消息监听器来处理接收到的消息。

    java 复制代码
    public class Consumer {
        public static void main(String[] args) throws Exception {
            // 创建一个消息消费者,并设置消息消费者组
            DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("your_consumer_group");
            // 指定NameServer地址
            consumer.setNamesrvAddr("your_nameserver_address");
            // 订阅指定Topic下的所有消息
            consumer.subscribe("your_topic", "*");
    
            // 注册消息监听器
            consumer.registerMessageListener(new MessageListenerConcurrently() {
                @Override
                public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
                    for (MessageExt msg : msgs) {
                        System.out.printf("接收到消息: %s%n", new String(msg.getBody()));
                    }
                    return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
                }
            });
    
            // 启动消费者实例
            consumer.start();
        }
    }

6 总结

本文只是了解下RocketMQ的基本原理和实现,在后面的章节中,我们会带来RocketMQ的完整解读。

相关推荐
小马爱打代码6 小时前
面试题-RocketMQ的基本架构、支持的消息模式、如何保证消息的可靠传输
架构·rocketmq
莱特昂11 小时前
K8S环境下验证RocketMQ扩缩容
kubernetes·rocketmq·java-rocketmq
小奏技术15 小时前
kafka如何获取topic一天的消息量
后端·消息队列
Wang's Blog2 天前
RocketMQ: 保证消息的可靠性投递
rocketmq
青春逝如流水5 天前
RocketMQ rocketmq-tools管理主题
rocketmq·rocketmq-tools
xidianjiapei0016 天前
Kafka和NATS等消息队列系统如何保证精确一次Exactly-Once语义
分布式·kafka·消息队列·精确一次·nats·exactly-once
sg_knight6 天前
RabbitMQ的预取值详解
java·分布式·微服务·消息队列·rabbitmq
qq_171538857 天前
探索 RocketMQ:企业级消息中间件的选择与应用
rocketmq