前言

RocketMQ 是阿里巴巴在 2012 年开源的分布式消息中间件,目前已经捐赠给 Apache 软件基金会,并于 2017 年 9 月 25 日成为 Apache 的顶级项目。

作为经历过多次阿里巴巴双十一这种“超级工程”的洗礼并有稳定出色表现的国产中间件,以其高性能、低延时和高可靠等特性近年来已经也被越来越多的国内企业使用。


一、初识 RocketMQ

2011 年初,Linkin 开源了 Kafka 这个优秀的消息中间件,淘宝中间件团队在对 Kafka 做过充分 Review 之后,被 Kafka 无限消息堆积、高效的持久化速度等优点吸引了。

美中不足的的是,Kafka 主要定位于日志传输,对于使用在淘宝交易、订单、充值等场景下还有诸多特性不满足。所以,阿里的中间件团队重新用 Java 语言编写了 RocketMQ ,定位于全场景的可靠消息传输。

目前 RocketMQ 在阿里集团的应用生态里被广泛应用于订单、交易、充值、物流、消息推送、日志处理, binglog 分发等场景。

RocketMQ 对比 Kafka,虽然设计的思想上有借鉴,但在架构上做了减法,在功能上做了加法:

  • 去掉 Zookeeper,使用 NameServer 来管理 Broker 集群,通信更方便;
  • 有延时队列和死信队列,开箱即用,减化代码逻辑实现。

1.1基本模型

RocketMQ 主要由 Producer、Broker、Consumer 三部分组成。其中,Producer 负责生产消息,Consumer 负责消费消息,Broker 负责存储消息。

基本模型

而 Broker 在实际部署过程中对应的是一台服务器,每个 Broker 可以存储多个 Topic 的消息,每个Topic 的消息也可以分片存储于不同的 Broker。Message Queue 用于存储消息的物理地址,每个 Topic 中的消息地址都会存储在多个 Message Queue 中。

ConsumerGroup 由多个Consumer 实例构成。


二、基本概念

以下的基本概念是理解和掌握 RocketMQ 最基础的概念,也是最重要的概念。现在不理解没有关系,先记住有个印象,后续使用的时候,兴许能帮助你豁然开朗。

2.1Producer

消息生产者(Producer)负责生产消息,一般由业务系统负责生产消息。

一个消息生产者会把业务应用系统里产生的消息(封装好的消息体)发送到 Broker 服务器。RocketMQ 提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。其中,同步和异步方式均需要 Broker 返回确认信息(即Ack),单向发送不需要。

2.2Consumer

消息消费者(Consumer)负责消费消息,一般是由下游的系统负责异步消费。

一个消息消费者会从 Broker 服务器默认主动拉取(Pull 模式)消息,并将其提供给应用程序。从用户应用的角度而言提供了两种消费形式:拉取式消费(默认 Pull 模式)、推动式消费。

2.3Topic

主题(Topic)表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是 RocketMQ 进行消息订阅的基本单位。

2.4Tag

标签(Tag)为消息设置的标志,用于同一 Topic 下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务的功能模块在同一主题下设置不同的标签。标签能够有效地保持代码的清晰度和连贯性,并优化 RocketMQ 提供的查询系统。消费者可以根据 Tag 实现对不同子主题的不同消费逻辑,实现更好的扩展性。

2.5Message

消息(Message)是系统所传输信息的物理载体、生产和消费数据的最小单位,每条消息必须属于某一个主题。RocketMQ 中的每条消息都拥有唯一的 Message ID 作为标识,且可以携带具有业务标识的 Key。系统提供了通过 Message ID 和 Key 查询消息的功能。

2.6Broker

代理服务器(Broker)是消息中转角色,负责存储消息、转发消息。代理服务器在 RocketMQ 系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。

2.7Pull Consumer

拉取式消费(Pull Consumer)是 Consumer 消费的一种类型,也是默认的类型。下游应用系统通常主动调用 Consumer 的拉消息方法从 Broke r服务器拉消息,即主动权由下游应用控制。一旦获取了批量消息,应用就会启动消费过程。

2.8Producer Group

生产者组(Producer Group)是同一类 Producer 的集合,这类 Producer 发送同一类消息且发送逻辑一致。如果发送的是事务消息且原始生产者在发送之后崩溃,则 Broker 服务器会联系同一生产者组的其他生产者实例重试提交或回溯消费。

2.9Consumer Group

消费者组(Consumer Group)是同一类 Consumer 的集合,这类 Consumer 通常消费同一类消息且消费逻辑一致。消费者组使得在消息过程中实现负载均衡和提高容错变得非常容易。要注意的是,消费者组的每个消费者实例必须订阅完全相同的 Topic。RocketMQ 支持两种消息模式:集群消费(Clustering)和广播消费(Broadcasting)。

2.10Ordered Message

顺序消息分为普通顺序消费(Normal Ordered Message)和严格顺序消息(Strictly Ordered Message)。

普通顺序消费(Normal Ordered Message)下的消费者通过同一个消息队列(Message Queue) 收到的消息是有顺序的,不同消息队列收到的消息则可能是无顺序的。

而在严格顺序消息(Strictly Ordered Message)模式下,消费者收到的所有消息均是严格有序的。


三、高级特性

3.1消息顺序

消息有序指的是一类消息消费时,能按照发送的顺序来消费,RocketMQ 可以严格的保证消息有序。

例如:一个订单产生了三条消息分别是订单创建、订单付款、订单完成。消费时要按照这个顺序消费才能有意义,但是同时订单之间是可以并行消费的。

顺序消息分为全局顺序消息与分区顺序消息,全局顺序是指某个 Topic 下的所有消息都要保证顺序,部分顺序消息只要保证每一组消息被顺序消费即可。

  • 全局顺序

    • 对于指定的一个 Topic,所有消息按照严格的先进先出(FIFO)的顺序进行发布和消费。

    • 适用场景:性能要求不高,所有的消息严格按照 FIFO 原则进行消息发布和消费的场景。

  • 分区顺序

    • 对于指定的一个 Topic,所有消息根据 sharding key 进行区块分区。 同一个分区内的消息按照严格的 FIFO 顺序进行发布和消费。 Sharding key 是顺序消息中用来区分不同分区的关键字段,和普通消息的 Key 是完全不同的概念。

    • 适用场景:性能要求高,以 sharding key 作为分区字段,在同一个区块中严格的按照 FIFO 原则进行消息发布和消费的场景。

3.2消息可靠性

RocketMQ 支持消息的高可靠,以下是影响消息可靠性的 6 种情况:

  1. Broker 非正常关闭
  2. Broker 异常 Crash
  3. OS Crash
  4. 机器掉电,但是能立即恢复供电情况
  5. 机器无法开机(可能是 cpu、主板、内存等关键设备损坏)
  6. 磁盘设备损坏

其中上述的1、2、3、4 这四种情况都属于硬件资源可立即恢复的情况,RocketMQ 在这四种情况下能保证消息不丢失,或者丢失少量数据(取决于刷盘方式是同步还是异步)。

而5、6这两点属于单点故障,无法恢复,一旦发生,在此单点上的消息会全部丢失。

RocketMQ 在这两种情况下,通过异步复制可保证 99% 的消息不丢失,但是仍然会有极少量的消息可能丢失。通过同步双写技术可以完全避免单点,同步双写势必会影响性能,适合对消息可靠性要求极高的场合,例如与订单、支付等相关的应用。注:RocketMQ 从 3.0 版本开始支持同步双写。

3.3延时队列

延迟队列是指消息发送到 Broker 后,不会立即被消费,等待特定时间后才会投递给真正的 Topic。

Broker 有配置项 messageDelayLevel,默认值为:1s、5s、10s、30s、1min、2min、3min、4min、5min、6min、7min、8min、9min、10min、20min、30min、1h、2h 这 18 个 level。

也可以配置自定义 messageDelayLevel ,注意:messageDelayLevel 是 Broker 的属性,不属于某个 Topic。

发消息时,设置 delayLevel 等级即可:msg.setDelayLevel(level)。level 有以下 3 种情况:

  • level == 0,消息为非延迟消息
  • 1<=level<=maxLevel,消息延迟特定时间,例如 level==1,延迟1s
  • level > maxLevel,则 level== maxLevel,例如 level==20,延迟 2h

定时消息会暂存在名为 SCHEDULE_TOPIC_XXXX 的 Topic 中,并根据 delayTimeLevel 存入特定的 queue,queueId = delayTimeLevel – 1,即一个 queue 只存相同延迟的消息,保证具有相同发送延迟的消息能够顺序消费。Broker 会调度地消费 SCHEDULE_TOPIC_XXXX,将消息写入真实的 Topic。

需要注意的是,定时消息会在第一次写入和调度写入真实 Topic 时都会计数,因此发送数量、TPS 都会变高,对性能可能会有一定影响。

3.4消息重试

Consumer 消费消息失败后,可以提供一种重试机制,令消息再消费一次。Consumer 消费消息失败通常可以认为有以下几种情况:

  • 由于消息本身的原因

    • 例如反序列化失败,消息数据本身无法处理(例如话费充值,当前消息的手机号被注销,无法充值)等。
    • 这种错误通常需要跳过这条消息,再消费其它消息,而这条失败的消息即使立刻重试消费,99% 也不成功,所以最好提供一种定时重试机制,即过 10 秒后再重试。
  • 由于依赖的下游应用服务不可用
    • 例如数据库连接不可用,系统网络故障等。
    • 遇到这种错误,即使跳过当前失败的消息,消费其他消息同样也会报错。这种情况建议应用 sleep 30s,再消费下一条消息,这样可以减轻 Broker 重试消息的压力。

RocketMQ 会为每个消费组都设置一个 Topic 名称为:%RETRY%+consumerGroup 的重试队列。这里需要注意的是:这个 Topic 的重试队列是针对消费组,而不是针对每个 Topic 设置的,用于暂时保存因为各种异常而导致 Consumer 端无法消费的消息。

考虑到异常恢复起来需要一些时间,会为重试队列设置多个重试级别,每个重试级别都有与之对应的重新投递延时,重试次数越多投递延时就越大。

RocketMQ 对于重试消息的处理是先保存至 Topic 名称为:SCHEDULE_TOPIC_XXXX 的延迟队列中,后台定时任务按照对应的时间进行 Delay 后重新保存至 %RETRY%+consumerGroup 的重试队列中。

3.5死信队列

死信队列用于处理无法被正常消费的消息。

当一条消息初次消费失败,消息队列会自动进行消息重试。达到最大重试次数后,若消费依然失败,则表明消费者在正常情况下无法正确地消费该消息,此时,消息队列不会立刻将消息丢弃,而是将其发送到该消费者对应的特殊队列中。

RocketMQ 将这种正常情况下无法被消费的消息称为死信消息(Dead-Letter Message),将存储死信消息的特殊队列称为死信队列(Dead-Letter Queue)。

在 RocketMQ 中,可以通过使用 consol e控制台对死信队列中的消息进行重发来使得消费者实例再次进行消费。


四、文章小结

到这里关于消息队列 RocketMQ 的基本结构就分享完了,其实本文主要还是介绍一些基本的概念,后续笔者还会分享一些在正真项目中的实践,尽请期待。

最后,如果文章有不足和错误,还请大家指正。或者你有其它想说的,也欢迎大家在评论区里交流!

参考文档:

https://github.com/apache/rocketmq/blob/master/docs/cn/concept.md

https://github.com/apache/rocketmq/blob/master/docs/cn/features.md

【主流技术】聊一聊消息队列 RocketMQ 的基本结构与概念的更多相关文章

  1. 多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

    1.引言 对于即时通讯网来说,所有的技术文章和资料都在围绕即时通讯这个技术方向进行整理和分享,这一次也不例外.对于即时通讯系统(包括IM.消息推送系统等)来说,MQ消息中件间是非常常见的基础软件,但市 ...

  2. 主流消息队列rocketMq,rabbitMq比对使用

    首先整理这个文章是因为我正好有机会实战了一下rocketmq,阿里巴巴的一个开源消息中间件.所以就与以往中rabbitmq进行小小的比较一下.这里主线的根据常见面试问题进行整理. 一.消息队列常用的场 ...

  3. 基于消息队列 RocketMQ 的大型分布式应用上云最佳实践

    作者|绍舒 审核&校对:岁月.佳佳 编辑&排版:雯燕 前言 消息队列是分布式互联网架构的重要基础设施,在以下场景都有着重要的应用: 应用解耦 削峰填谷 异步通知 分布式事务 大数据处理 ...

  4. 分布式消息队列RocketMQ(一)安装与启动

    分布式消息队列RocketMQ 一.RocketMQ简介 RocketMQ(火箭MQ) 出自于阿里,后开源给apache成为apache的顶级开源项目之一,顶住了淘宝10年的 双11压力 是电商产品的 ...

  5. 消息队列 RocketMQ4.x介绍和新概念讲解

    消息队列 RocketMQ4.x介绍和新概念讲解 Apache RocketMQ作为阿里开源的一款高性能.高吞吐量的分布式消息中间件 RocketMQ4.x特点 支持Broker和Consumer端消 ...

  6. 消息队列(Message Queue)基本概念(转)

    背景 之前做日志收集模块时,用到flume.另外也有的方案,集成kafaka来提升系统可扩展性,其中涉及到消息队列当时自己并不清楚为什么要使用消息队列.而在我自己提出的原始日志采集方案中不适用消息队列 ...

  7. 消息队列(Message Queue)基本概念

    背景 之前做日志收集模块时,用到flume.另外也有的方案,集成kafaka来提升系统可扩展性,其中涉及到消息队列当时自己并不清楚为什么要使用消息队列.而在我自己提出的原始日志采集方案中不适用消息队列 ...

  8. 分布式消息队列RocketMQ部署

    一.RocketMQ简介: RocketMQ是一款分布式.队列模型的消息中间件,具有以下特点: 1.支持严格的消息顺序: 2.支持Topic与Queue两种模式: 3.亿级消息堆积能力: 4.比较友好 ...

  9. 分布式消息队列RocketMQ与Kafka架构上的巨大差异

    分布式消息服务 Kafka 是一个高吞吐.高可用的消息中间件服务,适用于构建实时数据管道.流式数据处理.第三方解耦.流量削峰去谷等场景,具有大规模.高可靠.高并发访问.可扩展且完全托管的特点,是分布式 ...

  10. 分布式消息队列RocketMQ与Kafka架构上的巨大差异之1 -- 为什么RocketMQ要去除ZK依赖?

    我们知道,在早期的RocketMQ版本中,是有依赖ZK的.而现在的版本中,是去掉了对ZK的依赖,转而使用自己开发的NameSrv. 并且这个NameSrv是无状态的,你可以随意的部署多台,其代码也非常 ...

随机推荐

  1. [Java]线程生命周期与线程通信

    [版权声明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) https://www.cnblogs.com/cnb-yuchen/p/18162522 出自[进步*于辰的博客] 线程生命周期与 ...

  2. Java中HTTP下载文件——并解决跨域

    1.常用的需要设置的MIME类型 任何文件(二进制文件) application/octet-stream .doc application/msword .dot application/mswor ...

  3. SAP集成技术(十)混合集成平台

    混合集成平台hybrid integration platform (有时缩写为HIP)这个术语近年来被大量使用,但很多人可能不太清楚它的概念. 内容摘录自<SAP Interface Mana ...

  4. docker 安装 kafka+zookeeper,golang操作kafka

    目录 docker-compose.yml go操作kafka producer 消费者 consumer 消费者 结合gin框架操作kafka go-queue操作kafka 环境: centos8 ...

  5. Nginx 常用的基础配置(web前端相关方面)

    文章出处:https://juejin.cn/post/7196859948554715195 基础配置 user root; worker_processes 1; events { worker_ ...

  6. Advanced .Net Debugging 8:线程同步

    一.介绍 这是我的<Advanced .Net Debugging>这个系列的第八篇文章.这篇文章的内容是原书的第二部分的[调试实战]的第六章[同步].我们经常写一些多线程的应用程序,写的 ...

  7. 超详细!深入分析PPTP虚拟专用网搭建与抓包

    PPTP虚拟专用网搭建与抓包分析实验 实验目的:掌握PPP协议VPN的搭建,通过分析pptp建立,理解chap连接建立的过程 实验过程: 环境搭建 Windows 11系统 VMware虚拟机.kal ...

  8. cmder右键打开方式

    第一步: 新打开一个cmder窗口 第二步: 输入: Cmder.exe /register user 或 Cmder.exe /register all 第三步: 回车执行命令

  9. Flutter(六):Flutter_Boost接入现有原生工程(iOS+Android)

    本篇博客会介绍如何通过第三方插件Flutter_Boost实现接入原有工程. 如果不希望引入第三方插件,可以参考博客Flutter混合开发--接入现有原生工程(iOS+Android) 一.新建原生工 ...

  10. git push遇到的问题“Please make sure you have the correct access rights and the repository exists.”

    问题:今天在用idea往github推送代码的时候,出现了下面的报错 原因:是ssh key有问题,连接不上服务器 解决: 1.得重新在git设置一下身份的名字和邮箱 git config --glo ...