RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

目录


消息存储

消息存储方式

非持久化

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

  1. 消息生成者发送消息到 MQ

  2. MQ 返回 ACK(Acknowledge Character)给生产者

  3. MQ push 消息给对应的消费者

  4. 消息消费者返回 ACK 给 MQ


持久化

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

  1. 消息生成者发送消息到 MQ

  2. MQ 收到消息,将消息进行持久化,存储该消息

  3. MQ 返回 ACK 给生产者

  4. MQ push 消息给对应的消费者

  5. 消息消费者返回 ACK 给 MQ

  6. MQ 删除消息

注意:

①第 5 步 MQ 在指定时间内接到消息消费者返回 ACK,MQ 认定消息消费成功,执行 6 。

②第 5 步 MQ 在指定时间内未接到消息消费者返回 ACK,MQ 认定消息消费失败,重新执行 4、5、6 。


消息存储介质

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

数据库

  • 实现:ActiveMQ

  • 缺点:数据库瓶颈将成为 MQ 瓶颈

文件系统

  • 实现:RocketMQ/Kafka/RabbitMQ

  • 解决方案:采用消息刷盘机制进行数据存储

  • 缺点:硬盘损坏的问题无法避免


消息存储与读写方式

SSD(Solid State Disk):固态硬盘

  • 随机写(100 KB/s)

  • 顺序写(600 MB/s):1秒1部电影


Linux 系统发送数据的方式

  • “零拷贝”技术
    • 数据传输由传统的 4 次复制简化成 3 次复制,减少 1 次复制过程
    • Java 语言中使用 MappedByteBuffer 类实现了该技术
    • 要求:预留存储空间,用于保存数据(1G 存储空间起步)

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性


消息存储结构

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

如图所示,MQ 数据存储区域包含如下内容:

  • 消息数据存储区域
    • topic
    • queueId
    • message
  • 消费逻辑队列
    • minOffset
    • maxOffset
    • consumerOffset
  • 索引
    • key 索引
    • 创建时间索引
    • ……

刷盘机制

同步刷盘

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

  1. 生产者发送消息到 MQ,MQ 接到消息数据

  2. MQ 挂起生产者发送消息的线程

  3. MQ 将消息数据写入内存

  4. 内存数据写入硬盘

  5. 磁盘存储后返回 SUCCESS

  6. MQ 恢复挂起的生产者线程

  7. 发送 ACK 到生产者


异步刷盘

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

  1. 生产者发送消息到 MQ,MQ 接到消息数据

  2. MQ 将消息数据写入内存

  3. 发送 ACK 到生产者


小结

  • 同步刷盘:安全性高,效率低,速度慢(适用于对数据安全要求较高的业务)
  • 异步刷盘:安全性低,效率高,速度快(适用于对数据处理速度要求较高的业务)
# 刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH

高可用

高可用实现

nameserver

  • 无状态 + 全服务器注册

消息服务器

  • 主从架构(2M-2S)

消息生产

  • 生产者将相同的 topic 绑定到多个 group 组,保证即使 broker master 挂掉,其他 master 仍可正常进行消息接收。

消息消费

  • RocketMQ 自身会根据 broker master 的压力确认是否由 master 承担消息读取的功能,当 master 繁忙时候,自动切换由 slave 承担数据读取的工作。

主从复制

同步复制

  • master 接到消息后,先复制到 slave,然后反馈给生产者写操作成功
  • 优点:数据安全,不丢数据,出现故障容易恢复
  • 缺点:影响数据吞吐量,整体性能低

异步复制

  • master 接到消息后,立即返回给生产者写操作成功,当消息达到一定量后再异步复制到slave
  • 优点:数据吞吐量大,操作延迟低,性能高
  • 缺点:数据不安全,会出现数据丢失的现象,一旦 master 出现故障,从上次数据同步到故障时间的数据将丢失

配置方式

#Broker 的角色
#- ASYNC_MASTER 异步复制Master
#- SYNC_MASTER 同步双写Master
#- SLAVE
brokerRole=SYNC_MASTER

负载均衡

Producer 负载均衡:

  • 内部实现了不同 broker 集群中对同一 topic 对应消息队列的负载均衡

Consumer 两种负载均衡策略

  • 平均分配
    RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性

  • 循环平均分配
    RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性


消息重试

当消息消费后未正常返回消费成功的信息将启动消息重试机制

两种消息重试机制:

  • 顺序消息重试

  • 无序消息重试


顺序消息重试

  • 当消费者消费消息失败后,RocketMQ 会自动进行消息重试(每次间隔时间为 1 秒)。
  • 注意:应用会出现消息消费被阻塞的情况,因此,要对顺序消息的消费情况进行监控,避免阻塞现象的发生。

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性


无序消息重试

  • 无序消息包括普通消息、定时消息、延时消息、事务消息。
  • 无序消息重试仅适用于负载均衡(集群)模型下的消息消费,不适用于广播模式下的消息消费。
  • 为保障无序消息的消费,MQ 设定了合理的消息重试间隔时长。

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性


死信队列

概念

  • 当消息消费重试到达了指定次数(默认 16 次)后,MQ 将无法被正常消费的消息称为死信消息(Dead-Letter Message)。

  • 死信消息不会被直接抛弃,而是保存到了一个全新的队列中,该队列称为死信队列(Dead-Letter Queue)。

死信队列的特征

  • 归属某一个组(Gourp Id),而不归属 Topic,也不归属消费者。
  • 一个死信队列中可以包含同一个组下的多个 Topic 中的死信消息。
  • 死信队列不会进行默认初始化,当第一个死信出现后,此队列首次初始化。

死信队列中的消息的特征

  • 不会被再次重复消费。
  • 死信队列中的消息有效期为 3 天,达到时限后将被清除。

死信处理

  • 在监控平台中,通过查找死信,获取死信的 messageId,然后通过 id 对死信进行精准消费。

消息幂等

消息重复消费

消息重复消费原因

  • 生产者发送了重复的消息
    • 网络闪断
    • 生产者宕机
  • 消息服务器投递了重复的消息
    • 网络闪断
  • 动态的负载均衡过程
    • 网络闪断/抖动
    • broker重启
    • 订阅方应用重启(消费者)
    • 客户端扩容
    • 客户端缩容

RocketMQ 原理:消息存储、高可用、消息重试、消息幂等性


消息幂等

对同一条消息,无论消费多少次,结果保持一致,称为消息幂等性

解决方案

  1. 使用业务 id 作为消息的 key 。

  2. 在消费消息时,客户端对 key 做判定,未使用过放行,使用过抛弃。

  • 注意:messageId 由 RocketMQ 产生,messageId 并不具有唯一性,不能作用幂等判定条件。

常见的幂等方法示例

  • 新增(不幂等):insert into order values(……)
  • 查询(幂等)
  • 删除(幂等):delete from 表 where id=1
  • 修改(不幂等):update account set balance = balance+100 where no=1
  • 修改(幂等):update account set balance = 100 where no=1
上一篇:Docker 安装 RocketMq(单机)


下一篇:Linux系统下安装rocketmq