当前位置: 首页 > news >正文

分布式专题——41 RocketMQ集群高级特性

1 Dledger文件⼀致性协议

1.1 Deldger高可用集群的消息一致性问题

  • RocketMQ 提供两种集群机制,一是固定角色的主从集群,二是自行选主的 Dledger 集群。主从集群的消息同步过程相对简单,而 Dledger 高可用集群主节点是自行选举产生的,其文件同步更为复杂,消息数据需在整个集群内达成一致;

    在这里插入图片描述

  • 在 Server 集群中,数据写入到一个节点后,希望集群中任何一个节点都能读到该数据,此为分布式数据一致性问题

  • 这个问题实现起来会面临以下几个核心问题:

    • 服务稳定性问题:各个 Server 状态不稳定,随时可能宕机;
    • 网络抖动问题:Server 之间网络抖动会导致集群内某些请求丢失;
    • 网速问题:数据在 Server 间传输速度不一致,难以保证数据顺序。分布式场景需保证集群最终数据一致,而数据变化通常与操作顺序有关,因此需引入操作日志集并保证日志顺序;
    • 快速响应问题:要尽快向客户端给出写入操作的响应结果,且响应时间不能依赖集群中最慢的节点;
  • 所以,这个不起眼的问题,其实是IT界中一个非常有难度的问题。解决这样的问题,也有一系列的算法:

    • 弱一致性算法:如 DNS 系统、Gossip 协议,使用场景包括 Fabric 区块链、Cassandra、RedisCluster、Consul 等;

    • 强一致性算法:像 Basic-Paxos、Multi-Paxos(包括 Raft 系列,如 Nacos 的 Raft、Kafka 的 KRaft 以及 RocketMQ 的 Dledger)、ZAB(Zookeeper)。其中,RocketMQ 的 Dledger 集群基于 Raft 协议诞生;

  • RocketMQ 中的 Dledger 来自开源组织 OpenMessage,它是一个保证分布式日志一致性的小框架,RocketMQ 将其用于自身的日志文件同步场景。

1.2 Raft协议的基本流程

  • Raft 协议分 Election(选举)Log Replication(日志同步)两个阶段,也就是要解决集群中选举主节点以及集群内数据同步这两件事;
  • 动画演示地址:Raft。

1.2.1 Raft 算法基本工作流程

  • 客户端(Client)向服务端(Server)的共识模块(Consensus Module)发送请求;

  • 共识模块将客户端指令以条目(Entry)形式存入日志(Log),同时该指令也会被转发给集群其他节点,各节点将指令以 Entry 形式保存到自身 Log 中,此时 Entry 为未提交(uncommited)状态;

  • 当多数节点都保存了该 Entry 后,执行 Entry 中的操作,将其提交到状态机(State Machine),此时 Entry 变为已提交(commited)状态;

  • 最后向客户端返回响应;

其中,Log 日志是保存在 Server 上的操作日志,每个条目是 Entry,Entry 中的操作最终会落地到 State Machine;

Raft 算法核心是保证所有节点上的 Entry 顺序一致(而非保证 Entry 不丢失);

在这里插入图片描述

1.2.2 节点的三种状态

  • 基于上面的过程,Raft 协议为每个节点设定三种状态:Leader、Follower、Candidate

    • Leader

      • 由多数派选举产生
      • 向 Follower 节点发送心跳,Follower 收到心跳就不会竞选 Leader
      • 响应客户端请求,集群内所有数据变化都从 Leader 开始
      • 向 Follower 同步操作日志,实际实现中,有的产品会把发往 Follower 的请求转发到 Leader,有的则直接拒绝
    • Follower

      • 参与选举投票
      • 同步 Leader 上的数据
      • 接收 Leader 的心跳,若长期没收到心跳,就转为 Candidate 竞选 Leader
    • Candidate:没有 Leader 时,发起投票,竞选 Leader

    在这里插入图片描述

1.2.3 Term 任期概念

  • 为保证同一时刻集群最多只有一个主节点,防止脑裂问题,Raft 协议引入 Term 任期概念;

  • 时间被划分为多个任期,每个任期都以选举开始,选举成功后,由一名 Leader 管理集群直到任期结束;若选举失败,没有选出 Leader,就进入下一个任期,开始下一次选举;

    在这里插入图片描述

  • 从 CAP 理论的角度分析:Raft 优先保证 CP(一致性和分区容错性),放弃 A(可用性);与之对比,Eureka 保证 AP(可用性和分区容错性)。

1.2.4 节点状态变化过程

  1. 所有节点启动时都从 Follower 状态开始;

  2. 每个 Follower 设定选举过期时间(Election Timeout),持续等待 Leader 的心跳请求。若超过该时间,就转为 Candidate,向其他节点发起投票竞选 Leader。为防止所有节点同一时间过期,选举过期时间通常设为 150ms 到 300ms 间的随机值;

  3. Candidate 开始新任期选举,会投自己一票,然后向其他节点发起投票 RPC 请求,等待时长为 Election Timeout;

  4. 每个节点在每个任期内有一次投票资格,会响应 Candidate 的投票 RPC 请求,按规则投票并返回支持或不支持;

  5. Candidate 收到其他节点投票 RPC 响应后,会重置 Election Timeout 继续等待。一旦收到超过集群一半节点的投票同意结果,就转为 Leader 节点,并开始向其他节点发送心跳 RPC 请求确认 Leader 地位;

  6. 其他节点收到 Leader 心跳后,会转为 Follower 状态,Candidate 也会转为 Follower,等待从 Leader 同步日志。直到 Leader 节点心跳超时或服务宕机,再触发下一轮选举,进入下一个 Term 任期;

    在这里插入图片描述

1.3 Raft协议的基础实现机制拆解

在这里插入图片描述

1.3.1 数据结构

  • 所有节点都需要的信息

    • currentTerm:服务器当前的任期,用于标识不同的领导周期;

    • votedFor:当前任期内投票给了哪个节点,记录投票情况;

    • log[]:日志条目 Entry 的集合。每个 Entry 包含 Command(客户端指令)、term(该 Entry 所属任期)、idx(Entry 在日志中的偏移量),是数据同步的核心载体;

    • commitIndex:标记为已提交(commited)的 Entry 的索引,记录消息同步的进度,表明到该索引前的 Entry 都已成功提交;

    • lastApplied:已执行完 Command 的 Entry 索引,记录往状态机提交的进度,且满足 lastApplied <= commitIndex,用于保证提交到状态机的顺序和完整性;

  • Leader 上的特有参数

    • nextIndex[]:针对每个 Follower,记录给该 Follower 同步到了哪一条 Entry,用于跟踪与 Follower 的同步进度,确定下一次给该 Follower 发送 Entry 的起始位置;

    • matchIndex[]:针对每个 Follower,记录已经复制到该 Follower 的 Entry 索引,用于记录有哪些 Entry 发给了 Follower 且正在等待 Follower 确认。

1.3.2 RPC 请求

  • Raft 协议中最为核心的 RPC 请求有三个:Candidate 投票的 RPC 请求、Leader 发送的心跳请求、Leader 发送的日志同步请求。
1.3.2.1 投票请求
  • 主要请求参数
    • term:当前任期,用于确定投票所处的周期
    • candidateId:投票的候选人 ID,标识发起投票的节点
    • lastLogIndex:候选人的最后日志 Entry 索引,用于判断候选人日志的新旧程度
    • lastLogTerm:候选人最后日志条目的任期号,辅助判断候选人日志的新旧。前两个参数是必须的,后两个参数主要在主从发生切换时,用于找出最新的 Candidate
  • 主要响应参数
    • term:当前任期号,反馈响应时的任期情况
    • voteGranted:投票结果,表明是否支持当前 Candidate 当选为 Leader
1.3.2.2 Leader 发送的心跳请求与日志同步请求
  • 这两种请求其实可合并为一种,Follower 可通过是否带有日志条目来区分。心跳请求不带日志条目,用于维持 Leader 与 Follower 的连接,防止 Follower 因超时而发起新的选举;日志同步请求带日志条目,用于向 Follower 同步数据;

  • 主要请求参数

    • term:当前领导者的任期,确保请求在有效任期内
    • leaderId:当前领导者的 ID,标识发起请求的 Leader
    • entries[]:要同步的日志条目,心跳请求时该字段为空,同步消息请求时可支持批量同步
    • leaderCommit:领导者已知已提交的最高的日志条目的索引,让 Follower 知道新的条目要从哪里开始同步
    • 为安全起见,还建议将上一条 Entry 的 Index 以及 Term 发送过来,主要用于协助 Follower 定位 Entry,确保同步的准确性
  • 主要响应参数

    • term:当前任期,反馈响应时的任期
    • success:响应是否成功,表明 Follower 对请求的处理结果

1.4 RocketMQ中的Raft实现

1.4.1 每个节点的基础状态

  • io.openmessaging.storage.dledger.MemberState,核心属性包括:

    • selfId:节点自身的 ID
    • role:节点的角色(如 Candidate 等)
    • leaderId:Leader 节点的 ID
    • currentTerm:当前 Leader 的任期
    • currentVoteFor:当前任期内投票给的节点,一个任期内只能投一次票
    • ledgerEndIndex:当前节点最后一个 Entry 的索引
    • LedgerEndTerm:当前节点最后一个 Entry 的任期

    在这里插入图片描述

  • DledgerEntryPusher

    • 记录 Leader 的消息同步进度,其中 dispatcherMap 记录每个节点的同步状态,相当于 Raft 协议中的 nextIndex[]
    • pendingMap 记录待确认的消息,相当于 Raft 协议中的 matchIndex[]
    // io.openmessaging.storage.dledger.DLedgerEntryPusher 构造方法
    for (String peer : memberState.getPeerMap().keySet()) {if (!peer.equals(memberState.getSelfId())) {dispatcherMap.put(peer, new EntryDispatcher(peer, logger));}
    }// io.openmessaging.storage.dledger.DLedgerEntryPusher#EntryDispatcher
    // doAppendInner方法 记录每条消息的等待确认的时间
    PushEntryRequest request = buildPushRequest(entry, PushEntryRequest.Type.APPEND);
    CompletableFuture<PushEntryResponse> responseFuture = dLedgerRpcService.push(request);
    pendingMap.put(index, System.currentTimeMillis());
    

1.4.2 LogEntry 的设计

  • io.openmessaging.storage.dledger.entry.DLedgerEntry

    在这里插入图片描述

  • RocketMQ 中要传递的消息主要是 CommitLog,实际是 CommitLog 的子类 DLedgerCommitLog

  • Dledger 集群模式下记录的 CommitLog 日志和主从集群下的 CommitLog 日志不同,二者日志文件不通用,主从集群升级为 Dledger 集群时,日志文件无法直接迁移。

1.4.3 状态机

  • Dledger 保留 io.openmessaging.storage.dledger.statemachine.StateMachine 接口;
  • 状态机中记录 lastAppliedIndexCommitIndexlastAppliedIndex 封装在 io.openmessaging.storage.dledger.statemachine.StateMachineCaller 中,通过该类调度触发状态机的对应方法;
  • onCommited 方法里,记录 committedIndex 并封装成 Task 放到队列里排队执行;
  • 状态机只定义提交 Entry 的具体操作,具体实现逻辑由 RocketMQ 自行实现。

1.4.4 RPC 请求

  • 相关类位于 io.openmessaging.storage.dledger.protocol 包下,包含各种 RequestResponse 类,用于处理 Raft 协议中的选举、心跳、日志同步等 RPC 交互。若想了解每个请求的构建及参数流转,可自行分析源码;

    在这里插入图片描述

2 主从节点切换的高可用集群

  • RocketMQ 提供的 Dledger 虽增强了集群高可用性,但它将集群选举和同步日志功能整合在一起,且 Dledger 集群下的日志量比主从集群大很多,这会增加写日志的 IO 负担;

  • 在 RocketMQ 5.X 及以上大版本中,提供了 Controller 机制。该机制可利用 Raft 选举机制带来高可用特性,同时能使用 RocketMQ 原生的 CommitLog 日志,平衡了高可用性与 IO 负担等问题;

  • 架构组成

    • NameServer:作为命名服务,管理 Broker 等信息;

    • Controller:支持主从切换的组件,可独立部署或嵌入到 NameServer 中;

    • Broker(Master 和 Slave):Master 负责处理客户端请求等主要操作,Slave 作为备份,在主从切换时可接替 Master 工作;

    在这里插入图片描述

  • 部署与扩展

    • 具体部署方式可参考官网链接:主备自动切换模式部署 | RocketMQ;

    • 更注重引导理解 RocketMQ 思考问题的方式,若对 Controller 组件用法等细节感兴趣,可按之前读源码的思路去分析源码。

3 RocketMQ的BrokerContainer容器式运行机制

  • 在 RocketMQ 4.x 版本中,一个 Broker 对应一个进程。无论是主从部署还是 Dledger 形式部署,一个进程里只有一个 Broker 服务。且 Broker 分主从,Master 负责响应客户端请求,十分繁忙;Slave 一般只承担冷备或热备作用。这种节点角色不对等的情况,导致 RocketMQ 的服务器资源无法充分利用;

  • 为解决上述资源利用问题,在 RocketMQ 5.x 版本中,提供了 BrokerContainer 新模式。在一个 BrokerContainer 进程中可加入多个 Broker,这些 Broker 可以是 Master Broker、Slave Broker 或者 DledgerBroker。通过这种方式,能提高单个节点的资源利用率,还可通过各种形式的交叉部署实现节点之间的对等部署;

    在这里插入图片描述

  • BrokerContainer 部署与配置

    • 通过调用 bin/mqbrokercontainer 脚本启动,使用 -c 参数指定单独的配置文件;

      bin/mqbrokercontainer -c broker-container.conf
      
    • 配置文件具体的配置方式,可以参见RocketMQ给出的配置示例文件,即conf/container/目录下的配置;

      • 核心配置是通过 brokerConfigPaths 参数指定多个 Broker 的配置文件,将它们打包成一个 BrokerContainer 执行;
      • 同时,还可配置端口(如 listenPort=10811 用于接收 mqadmin 命令)、NameServer 地址(namesrvAddr 或通过 fetchNamesrvAddrByAddressServer 自动获取)等;
      # 配置端口,用于接收mqadmin命令
      listenPort=10811
      # 指定namesrv
      namesrvAddr=worker1:9876;worker2:9876;worker3:98767
      # 或指定自动获取namesrv
      fetchNamesrvAddrByAddressServer=false
      # 指定要向BrokerContainer内添加的brokerConfig路径,多个config间用“:”分隔;
      # 不指定则只启动BrokerConainer,具体broker可通过mqadmin工具添加
      brokerConfigPaths=/app/rocketmq/rocketmq-all-5.3.0-bin-release/conf/2m-2s-async/broker-b-s.properties:/app/rocketmq/rocketmq-all-5.3.0-bin-release/conf/2m-2s-async/broker-a.properties
      

4 RocketMQ的集群架构总结

  • RocketMQ 从 2022 年 9 月推出 5.x 大版本,相比 4.x 版本,向云原生方向迈进了一大步。除了 Controller 主从切换集群和 Container 容器化运行机制外,5.x 版本还新增了 Proxy 组件;

  • Proxy 组件:

    • 和 Controller 类似,可与 Broker 一起组合部署,也可单独部署;

    • 主要用于兼容多语言客户端。若使用 Java 客户端,则无需启动 Proxy;

    • 具体部署过程可参见官网:本地部署 RocketMQ | RocketMQ;

  • 整体架构组成

    • NameSrv:作为命名服务,管理 Broker 等相关信息,多个 NameSrv 可形成集群,保证服务的高可用性;

    • Controller:支持主从切换的组件,可独立部署或嵌入到 NameSrv 中,用于管理 Broker 的主从状态切换等,保障集群的高可用性;

    • Container:采用容器化运行机制的组件,一个 Container 进程中可加入多个 Broker(如 Master Broker、Slave Broker 等),提高单个节点资源利用率,实现节点对等部署;

    • Broker(Master 和 Slave):Master 负责处理客户端请求等主要操作,Slave 作为备份,在主从切换时可接替 Master 工作;

    • Proxy:位于 Producer 和 Consumer 与 Broker 之间,起到协议转换等作用,以兼容多语言客户端;

    • Producer/Consumer:Producer 负责发送消息,Consumer 负责消费消息,通过 Proxy 与 Broker 等组件交互;

    在这里插入图片描述

http://www.dtcms.com/a/473343.html

相关文章:

  • 自然语言处理分享系列-词语和短语的分布式表示及其组合性(一)
  • 从0到1实现鸿蒙智能设备状态监控:轻量级架构、分布式同步与MQTT实战全解析
  • RWKV架构讲解
  • Docker 镜像维护指南:从配置优化到 MySQL 实战运行
  • 电视盒子助手开心电视助手 v8.0 删除电视内置软件 电视远程控制ADB去除电视广告
  • 【完整源码+数据集+部署教程】 航拍杂草检测与分类系统源码和数据集:改进yolo11-RVB-EMA
  • My SQL--创建数据库、表
  • mysql高可用架构之MHA部署(三)——故障转移后邮件告警配置(保姆级)
  • 做酒的网站有哪些jsp获取网站域名
  • OpenCV(八):NumPy
  • 小微宝安网站建设有哪些做分析图用的网站
  • RabbitMQ 核心概念解析
  • 开发实战 - ego商城 - 2 nodejs搭建后端环境
  • 基于Java Swing的智能数据结构可视化系统 | 支持自然语言交互的AI算法助手
  • QQmusic sign值逆向实战 - Webpack打包分析
  • 城乡建设部网站首页网站建设公司应该怎么做推广
  • Linux环境下Hive4.0.1(最新版本)部署
  • dolphinscheduler之hivecli 任务
  • spark3访问低版本hive填坑记
  • 池化 (Pooling) 学习笔记
  • LeetCode160.相交链表【最通俗易懂版双指针】
  • Neo4j+Gephi制作社区检测染色图
  • 毕业设计代做网站机械工信部网站备案流程
  • aws ec服务器设置密码登录,ec服务器root登录 aws服务器初始化配置
  • Linux - 命令行参数与环境变量
  • 【高并发服务器】四、通用类型容器any
  • linux学习笔记(29)网络编程——服务器客户端 及多进程多线程服务器
  • 边缘服务器 FTP/TFTP 服务搭建与使用(Docker 方式)
  • VMware安装Kali-Linux
  • (6)数据中心、台式(塔式)服务器、机架式服务器、刀片式服务器