RocketMQ

RocketMQ是一个消息中间件,提供应用解耦、流量削峰填谷等功能。其角色包括Producer、Consumer、Broker和Name Server。RocketMQ支持多种消费模式,如集群和广播模式,并具备高可用机制,如主从复制。消息存储采用顺序写入和零拷贝技术,保证高效。 RocketMQ还提供顺序消息、延迟消息、批量消息、过滤消息和事务消息等功能。在消息重复和消费一致性方面,RocketMQ有相应的处理策略。

 

Mq的优点:

  • 应用解耦
  • 流量的削峰填谷
  • 数据分发(将数据发送到多个系统)
  • 异步处理

Mq的缺点:

  • 系统可用性降低

使用mq后引用外部依赖增多,mq挂了将会影响应用的可用性

  • 系统复杂度提高

消息的重复消费、Exactly-Once问题、消息消费顺序问题、消息丢失问题

  • 一致性问题

多个系统同时处理消息,其中一个系统失败,整个系统一致性如何保证

常用MQ比较:

 

特性RabbitMqRocketMQKafka
开发语言ErlangJavaScala 和 Java
成熟度成熟比较成熟成熟的日志领域
时效性微秒级毫秒级毫秒级
社区活跃度
单机吞吐量5.9W/S,CPU资源消耗较高;消息持久化场景下在2.6w/s左右11.6w/s,RocketMQ 的消息写入内存后即返回ack,由单独的线程专门做刷盘的操作,所有的消息均是顺序写文件。(内存消耗相对较大)17.3w/s,这主要取决于它的队列模式保证了写磁盘的过程是线性IO。此时broker磁盘IO已达瓶颈。(cpu消耗相对较大)
topic数量对吞吐量的影响 topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降这是 RocketMQ的一大优势,在同等机器下,可以支撑大量的topictopic 从几十个到几百个的时候,吞吐量会大幅度下降所以在同等机器下,kafka 尽量保证 topic 数量不要过多。如果要支撑大规模topic,需要增加更多的机器资源
可用性高,基于主从架构实现高可用性非常高,分布式架构非常高,kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
消息可靠性以 broker 为中心,有消息的确认机制经过参数优化配置,可以做到0丢失经过参数优化配置,消息可以做到0丢失。以 consumer 为中心,无消息的确认机制
功能支持基于erlang开发,所以并发能力很强,性能极其好,延时很低MQ功能较为完善,还是分布式的,扩展性好功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准

RocketMQ角色:

  • Producer: 消息生产者
  • Consumer: 消息消费者
  • Broker: 消息存储中心,主要作用是接收来自 Producer 的消息并存储, Consumer 从这里取得消息。Broker上存储着多个topic的消息。
  • Name Server: 保存 Broker 相关 Topic 等元信息并给 Producer ,提供 Consumer 查找 Broker 信息。(类似于注册中心)

  • Topic: 区分不同的消息的类别;一个topic可以多个Producer生产,也可以多个Consumer消费。
  • Message Queue: Message是在每个Broker上以Queue的形式记录。同一个topic有多个队列存储消息,消息在队列里有序,不同队列的数据相对无序。
  • Tag:消息标签,用来进一步区分某个 Topic 下的消息分类,消息队列 RocketMQ 允许消费者按照 Tag 对消息进行过滤,确保消费者最终只消费到他关注的消息类型。

集群特点:

  • Name Server:
    • 几乎无状态,多个节点之间无需同步。
  • Broker加入时向每一个NameServer都发送注册信息,每个Broker定时发送topic信息
  • Broker:
    • 区分主从,一主对应多从,一从对应一主。主节点既可消费数据,也可生产数据,从节点只能让Consumer消费数据。
  • 主从节点通过指定相同的BrokerName,不同的BrokerID,BrokerID为0就是主节点,非0就是从节点。
  • 与所有的NameServer保持长连接,定时向NameServer发送心跳与topic信息。
  • 当Broker挂掉;NameServer会根据心跳超时主动关闭连接,一旦连接断开,会更新Topic与队列的对应关系,但不会通知生产者和消费者。
  • 一个Topic分布在多个Broker上,一个Broker可以配置多个Topic,它们是多对多的关系。
  • 如果某个Topic消息量很大,应该给它多配置几个Queue,并且尽量多分布在不同Broker上,减轻某个Broker的压力。
  • Salve定时从Master同步数据,如果Master宕机,则Slave提供消费服务,但是不能写入消息,此过程对应用透明,由RocketMQ内部解决。
  • Producer:
    • 通过与NameServer中的某一节点(随机选择)建立长连接,定期从NameServer获取Topic的信息,并与提供信息的Topic的主节点建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。
  • 单个Producer和一台NameServer保持长连接,如果该NameServer挂掉,生产者会自动连接下一个NameServer,直到有可用连接为止,并能自动重连。
  • 单个生产者和该生产者关联的所有broker保持长连接。
  • 与Master定时发送心跳
  • Consumer:
    • 通过与NameServer中的某一节点(随机选择)建立长连接,定期从NameServer获取Topic的信息。
  • 如果该NameServer挂掉,消费者会自动连接下一个NameServer,直到有可用连接为止,并能自动重连。
  • 单个消费者和该消费者关联的所有broker保持长连接。
  • Consumer会向Broker发送心跳信息,心跳信息中包含了当前消费者的订阅信息。

消费模式:

  • 集群模式:
    • 同一消费者组内默认集群模式,即同一消费者组内的多个消费者竞争消费数据,ack确认由broker完成
  • 广播模式:
    • 同一消费者组内的所有消费者均可消费对应topic的所有数据,不存在竞争消费。偏移量控制由消费者控制

拉取模式:

消息类型:

  • 顺序消息:
    • rocketMq的消息存储在队列中,数据先进先出,但一个topic对应多个queue,每个queue一个队列存储,对于多queue的数据,只能保证局部有序,即同一queue数据先进先出,全局有序性无法保证。若需要全局有序,可考虑一个topic只有一个queue。
  • 部分数据需要有序消费时,可以考虑将此部分消息发送到同一queue队列中,消费时即可保证此部分数据消费顺序。例如同一订单的创建、付款、完成需要被顺序消费,可以考虑根据订单id进行hash计算得到对应的queue,将同一订单的数据发送到同一queue中。使用MessageQueueSelector,消费时,同一queue由一个线程进行消费,使用MessageListenerOrderly
  • 延时消息:
    • 延迟消息是指生产者发送消息发送消息后,不能立刻被消费者消费,需要等待指定的时间后才可以被消费。

  • 步骤说明如下:
  1. producer要将一个延迟消息发送到某个Topic中
  2. Broker判断这是一个延迟消息后,将其通过临时存储进行暂存。
  3. Broker内部通过一个延迟服务(delay service)检查消息是否到期,将到期的消息投递到目标Topic中。这个的延迟服务名字为delay service,不同消息中间件的延迟服务模块名称可能不同。
  4. 消费者消费目标topic中的延迟投递的消息
  • 开源RocketMQ支持延迟消息,但是不支持秒级精度。默认支持18个level的延迟消息,这是通过broker端的messageDelayLevel配置项确定的(框架已实现指定时间的延迟队列,详情参考文档:https://doc.bytedance.net/docs/1019/1257/19589/),messageDelayLevel如下:

 messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

  • 批量消息:
    • 一次性将多条消息发送到mq中(发送消息时传递一个list)
  • 过滤消息:
    • Broker的消息过滤可以帮助保证消费端只消费所需要的消息。
  • 以天猫交易平台为例,订单消息和支付消息属于不同业务类型的消息,分别创建 Topic_Order 和 Topic_Pay,其中订单消息根据商品品类以不同的 Tag 再进行细分,列如电器类、男装类、女装类、化妆品类等被各个不同的系统所接收。
  • 总的来说,针对消息分类,您可以选择创建多个 Topic,或者在同一个 Topic 下创建多个 Tag。但通常情况下,不同的 Topic 之间的消息没有必然的联系,而 Tag 则用来区分同一个 Topic 下相互关联的消息,例如全集和子集的关系、流程先后的关系。
  • sql语法过滤,RocketMq支持通过sql语法来过滤消费的数据,订阅消息时使用MessageSelector.bySql()指定筛选条件
  • 事务消息:
    • 事务消息的发布主要分为两个部分:正常事务消息的发布与提交、事务消息的补偿流程
  • 正常事务消息发布
    • 发送消息(half消息)
  • 服务端响应消息写入结果
  • 根据写入结果执行本地事务(如果写入失败,此时half消息对consumer不可见,本地逻辑不执行)
  • 根据本地事务状态执行commit或者rollback(只有commit后的消息才会对consumer可见)
  • 事务补偿(用于解决消息Commit/Rollback失败或者超时的情况)
    • 对没有Commit/Rollback的事务消息(pending状态的消息),从服务端发起一次回查
  • Producer收到回查消息,检查消息对应的本地事务状态
  • 根据本地事务状态,重新发起Commit/Rollback

消息存储:

消息的传输流程如图所示:

  • 消息的存储与发送:
    • 消息存储:采用顺序写的方式将消息写入磁盘,保证了消息存储速度。
  • 消息发送:采用零拷贝技术,提高消息存盘和发送的速度。(一次只能发送1.5-2G的文件到用户态的虚拟内存)
  • 消息存储结构:
    • RocketMq的消息存储是由ConsumerQueue和CommitLog配合完成的
  • CommitLog:存储消息的元数据
  • ConsumerQueue:存储了消息在CommitLog中的索引值。存放了某个Topic下面的所有消息在CommitLog中的位置。每个topic下的每个queue都有一个对应的consumeQueue文件。key为单调递增的整数。ConsumerQueue和MessageQueue是一一对应的
  • IndexFile:
    • 消息索引文件,主要存储的是key和offset的对应关系。为了满足根据某些关键字查询消息的功能,保证查询速度。一个broker对应一组index文件,同样是写完一个文件去写下一个。
  • rocketMq提供了根据消息msgID、消息key来查询消息的功能,对应的msgID以及生产者指定的消息key就会被索引,其中msgID是创建消息时自动生成的索引,肯定有的。消息key是producer发送消息前指定的,可以设置一组key,每个key都会被索引,不设置就没有。
  • 综上所述,当Broker新建一条消息时,会在commitLog中插入一条消息正文;后台线程ReputMessageService在consumeQueue中插入一条索引数据,key为消费位点,内容为消息在commitLog文件的位置信息;在index中插入一条或多条索引数据,key为msgId或者指定的消息key,value为消息在commitLog文件的位置信息。之后消息可以用于消费了。

  • 刷盘机制:
    • 同步刷盘:在返回写成功状态时,消息已经被写入磁盘。
  • 异步刷盘:在返回写成功状态时,数据只是被写入内存,由另外的线程将数据从内存写到磁盘上。

高可用机制:

  • 同步(主从复制):slave主动建立TCP连接,然后每隔 5s 向master上报 commitLog 文件最大偏移量并拉取还未同步的消息;master收到请求,解析偏移量,返回未同步的消息;slave收到消息,更新自己的commitLog,更新偏移量,准备下次申请同步;向master上报此次同步进度。
  • 读写分离:消息只能写入master,读取消息既可以从master也可以从slave。根据master的消息堆积量来决定向master/slave拉取消息。当前消息堆积量大于物理内存的 40 %,则将 suggestPullingFromSlave 设置为 true,且slaveReadEnable=true时,设置 suggestWhichBrokerId 为slave 的 broker ID。当消费者收到拉取响应回来的数据后,会将下次建议拉取的 brokerID 缓存起来(pullFromWhichNodeTable)。下次拉取消息可以从中取出 brokerId。
  • 消费进度同步:集群消费时,消息消费进度是保存在broker的;广播消费时,消息进度保存在consumer本地。集群消费需要做broker的消费进度同步。无论消息消费者是从master拉的消息还是从slave拉取的消息,在向Broker反馈消息消费进度时,优先向master汇报,除非master挂了。消息消费进度的同步是单向的,slave开启一个定时任务,定时从master同步消息消费进度。

    • master挂了,拉取消息只能从slave,master重启后消息进度是旧的?consumer在消费时,本地也会保存消费进度。在集群模式下,也会有缓存。consumer向master/slave拉取消息时,首先就会更新消息进度。如果consumer内存中存在消息消费进度时,broker会更新消息消费进度,所以重启后,master可以更新进度。

负载均衡:

  • 生产者负载均衡:每个实例在发送消息时,默认会轮询所有的messageQueue发送消息,以达到让所有的消息均匀的落在不同的queue中。
  • 消费者负载均衡:每个queue只能分配给一个消费者,因此消费者的数量应小于queue的数量
    • 常见负载均衡策略:AllocateMessageQueueAveragely平均算法,默认策略;

  • AllocateMessageQueueAveragelyByCircle:环形平均算法;所有消费者围成一个环,然后循环这个环分配队列。

  • AllocateMessageQueueByConfig:根据配置负载均衡算法;
  • AllocateMessageQueueConsistentHash:一致性哈希负载均衡算法。

消息重试与死信队列:

  • 顺序消息的重试:对于顺序消息,当消费者消费失败后,消息队列会自动的进行消息重试,这时,应用会出现消息消费被阻塞的情况。因此在使用顺序消息时,务必保证应用能够及时监控并处理消费失败的情况。
  • 无序消息的重试:通过返回状态实现重试。广播方式不提供重试特性,消费失败后,失败消息不再重试,继续消费新消息。
  • 默认允许每条消息最多重试16次,16次后会将消息放入死信队列。有效期为3天,3天后会被删除
  • 死信队列:一个死信队列对应一个GroupID,如果一个Group没有产生死信消息,则不会创建死信队列。一个死信队列包含了一个Group所有的死信消息,无论该消息属于哪个topic。

消息重复:

  • 发送消息时重复:
    • 当一条消息从客户端成功发送到服务端,并完成持久化,但因为网络抖动或者客户端宕机,导致服务端对客户端应答失败,客户端认为消息发送失败并重新发送消息,此时客户端会受到两条相同的数据。
  • 投递时消息重复:
    • 消息消费场景下,消息已投递到消费者并完成业务处理,当客户端给服务端反馈应答网络异常,为保证至少一次消费,服务端在网络恢复后会再次将之前的消息投递到消费者,消费者会收到两条相同的消息。
  • 负载均衡时消息重复:
    • Broker或客户端重启、扩容或者缩容时,会发生Rebalance,此时消费者可能会消费到重复的数据。

参考文档:

https://cloud.tencent.com/developer/article/1581368

https://xie.infoq.cn/article/fba37afd9bda31fb10eec651f

### 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、付费专栏及课程。

余额充值