高可用:如何实现消息队列的 HA?

2023-12-19

管理学上有一个木桶理论,一只水桶能装多少水取决于它最短的那块木板,这个理论推广到分布式系统的可用性上,就是系统整体的可用性取决于系统中最容易出现故障,或者性能最低的组件。系统中的各个组件都要进行高可用设计,防止单点故障,消息队列也不例外,本文一起来看一下消息中间件的高可用设计。

消息队列高可用手段

一般来说,分布式系统的高可用依赖副本技术,副本的引入,使得分布式系统可以更好地进行扩展,当出现某个节点宕机时,由于副本的存在,也能够快速地进行替换,提升系统整体可靠性,防止数据丢失。

消息队列如何实现高可用的问题,如果出现在面试中,一般是作为一个相对开放的话题,你可以根据自己对分布式系统的了解,围绕副本、集群、一致性等和面试官展开讨论。消息队列在系统中承担了数据存储和数据传输的两种功能,所以消息队列的高可用设计,也比数据库、文件索引等持久性存储要复杂。

下面的内容,我以 Apache Kafka 为例,简单介绍一下消息队列的高可用设计。

Kafka 的副本机制

Kafka 的高可用实现主要依赖副本机制,我把 Kakfa 的高可用,拆分成几个小问题来讲解,一来是为了更好地理解,二来很多细节问题也可能出现在面试中,方便你更好地掌握。

Broker 和 Partition 的关系

在分析副本机制之前,先来看一下 Broker 和 Partition 之间的关系。Broker 在英文中是代理、经纪人的意思,对应到 Kafka 集群中,是一个 Kafka 服务器节点,Kafka 集群由多个 Broker 组成,也就是对应多个 Kafka 节点。

image (14).png

Kafka 是典型的发布订阅模式,存在 Topic 的概念,一个 Broker 可以容纳多个 Topic,也就是一台服务器可以传输多个 Topic 数据。

不过 Topic 是一个逻辑概念,和物理上如何存储无关,Kafka 为了实现可扩展性,将一个 Topic 分散到多个 Partition 中,这里的 Partition 就是一个物理概念,对应的是具体某个 Broker 上的磁盘文件。

从 Partition 的角度,Kafka 保证消息在 Partition 内部有序,所以 Partition 是一段连续的存储,不能跨多个 Broker 存在,如果是在同一个 Broker 上,也不能挂载到多个磁盘。从 Broker 的角度,一个 Broker 可以有多个 Topic,对应多个 Partition。

除此之外,Partition 还可以细分为一个或者多个 Segment,也就是数据块,每个 Segment 都对应一个 index 索引文件,以及一个 log 数据文件。对 Partition 的进一步拆分,使得 Kafka 对 分区的管理更加灵活。

Replication 之间如何同步数据

基于 Kafka 的系统设计,你可以思考一下,如果没有副本,那么当某个 Kafka Broker 挂掉,或者某台服务器宕机(可能部署了多个 Broker),存储在其上的消息就不能被正常消费,导致系统可用性降低,或者出现数据丢失,这不符合分布式高可用的要求,出现单点故障,也不满足 Kafka 数据传输持久性和投递语义的设计目标。

Kafka 中有一个配置参数 replication-factor(副本因子),可以调整对应分区下副本的数量,注意副本因子数包含原来的 Partition,如果需要有 2 个副本,则要配置为 3。

假设现在有一个订单的 Topic,配置分区数为 3,如果配置 replication-factor 为 3,那么对应的有三个分区,每个分区都有 3 个副本,在有多个副本的情况下,不同副本之间如何分工呢?

每个分区下配置多个副本,多个副本之间为了协调,就必须有一定的同步机制。Kafka 中同一个分区下的不同副本,有不同的角色关系,分为 Leader Replication 和 Follower Replication。Leader 负责处理所有 Producer、Consumer 的请求,进行读写处理,Follower 作为数据备份,不处理来自客户端的请求。

Follower 不接受读写请求,那么数据来自哪里呢?它会通过 Fetch Request 方式,拉取 Leader 副本的数据进行同步。

image (15).png

Fetch 这个词一般用于批量拉取场景,比如使用 Git 进行版本管理的 fetch 命令,在 Kafka 中,会为数据同步开辟一个单独的线程,称为 ReplicaFetcherThread,该线程会主动从 Leader 批量拉取数据,这样可以高性能的实现数据同步。

Replication 分配有哪些约定

Kafka 中分区副本数的配置,既要考虑提高系统可用性,又要尽量减少机器资源浪费。

一方面,为了更好地做负载均衡,Kafka 会将所有的 Partition 均匀地分配到整个集群上;另一方面,为了提高 Kafka 的系统容错能力,一个 Partition 的副本,也要分散到不同的 Broker 上,否则就去了副本的意义。

一般来说,为了尽可能地提升服务的可用性和容错率,Kafka 的分区和副本分配遵循如下的原则:

一个 Topic 的 Partition 数量大于 Broker 的数量,使 Partition 尽量均匀分配到整个集群上;
同一个分区,所有的副本要尽量均匀分配到集群中的多台 Broker 上,尽可能保证同一个 分区下的主从副本,分配到不同的 Broker 上。

Leader Replication 如何选举

一旦牵扯到数据同步,就必然会有 Leader 节点宕机以后重新选择的问题。引入 Replication 机制之后,同一个 Partition 可能会有多个副本,如果Leader挂掉,需要在这些副本之间选出一个 新的Leader。

Kafka 数据同步中有一个 ISR(In-Sync Replicas,副本同步队列)的概念,Leader 节点在返回 ACK 响应时,会关注 ISR 中节点的同步状态,所以这个队列里的所有副本,都和 Leader 保持一致。

Kafka 的 ISR 依赖 ZooKeeper 进行管理,ISR 副本同步队列中的节点,拥有优先选举的权利,因为 ISR 里的节点和 Leader 保持一致,如果必须满足一致性,只有 ISR 里的成员才能被选为 Leader。

如果某个 Broker 挂掉,Kafka 会从 ISR 列表中选择一个分区作为新的 Leader 副本。如果 ISR 列表是空的,这时候有两个策略,一个是直接抛出 NoReplicaOnlineException 异常,保证一致性;另外一个是从其他副本中选择一个作为 Leader,则可能会丢失数据,具体需要根据业务场景进行配置。

所有的副本都挂了怎么办

现在考虑一个极端情况,如果一个分区下的所有副本都挂掉了,那如何处理呢?在这种情况下,Kafka 需要等待某个副本恢复服务,具体可以有两种方案:

  • 等待 ISR 中的某个副本恢复正常,作为新的 Leader;

  • 等待任一个 副本恢复正常,作为新的 Leader。

在第二种方案下,由于选择的 Leader 节点可能不是来自 ISR,所以可能会存在数据丢失,不能保证已经包含全部 Commit 的信息;如果选择第一种方案,会保证数据不丢失,但是如果全部的 ISR 节点都彻底宕机,系统就无法对外提供服务了,对应的分区会彻底不可用。

方案一优先保证数据一致性,方案二优先保证服务可用性,在实际配置中,可以根据不同的业务场景选择不同的方案。

总结

本文分享了消息队列高可用相关的知识,并且针对 Kafka 的高可用实现,进行了简单的分析。

实际上,Kafka 添加副本机制之后,需要解决的细节问题有很多。举个例子,我们在第 29 课时讲过消息投递的不同语义,比如 At Most Once、At Least Once 等,当添加了 Partition 之后,Kafka 需要保持投递语义的完整,那么在生产者进行投递时,因为要考虑不同副本的状态,Leader 节点如何进行 ACK 呢?很明显,如果 Leader 节点等待所有的 Follower 节点同步后才返回 ACK,系统整体的性能和吞吐量会大幅降低,这也是 Kafka 引入 ISR 副本分层管理的原因之一。

除了 Kafka 以外,RocketMQ、RabbitMQ 等消息队列又是怎么实现高可用的呢?感兴趣的同学可以了解一下,欢迎留言分享。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高可用:如何实现消息队列的 HA? 的相关文章

  • 在java中轮询Http服务器(重复发送http get请求)

    当对其进行 REST 调用时 我的 Web 服务器会发送一些信息 我想不断轮询该服务器 间隔5秒后重复发送HTTP GET请求 以检查返回的信息是否有任何变化 做到这一点最有效的方法是什么 您能提供一些代码示例吗 请注意 我只想开发客户端代
  • Netbeans 8.1 Gnome 3 GTK+ UI 字体和选项卡高度

    我刚刚在运行 GNOME 3 桌面的 Ubuntu 16 04 上安装了 NetBeans 8 1 如果可能的话 我想继续使用 IDE 的 GTK 外观和感觉 但 UI 上的字体 尤其是选项卡中的字体 太小且重叠 我尝试添加 fontsiz
  • TreeMap 删除所有大于某个键的键

    在项目中 我需要删除键值大于某个键的所有对象 键类型为Date 如果重要的话 据我所知TreeMapJava中实现的是红黑树 它是一种二叉搜索树 所以我应该得到O n 删除子树时 但除了制作尾部视图并一一删除之外 我找不到任何方法可以做到这
  • java.lang.ClassNotFoundException:javax.mail.MessagingException

    我想使用 eclipse 将电子邮件从我的 gmail 帐户发送到另一个邮件帐户 我使用 apache tomcat 7 0 34 作为我的 Web 服务器 并使用端口 8080 作为 apache 服务器 HTTP 1 1 并使用 JRE
  • 如何在 JavaFX 中连接可观察列表?

    我所说的串联是指获得一个新列表 该列表侦听所有串联部分的更改 方法的目的是什么FXCollections concat ObservableList
  • 如何在 JPQL 或 HQL 中进行限制查询?

    在 Hibernate 3 中 有没有办法在 HQL 中执行相当于以下 MySQL 限制的操作 select from a table order by a table column desc limit 0 20 如果可能的话 我不想使用
  • Android中如何使用JNI获取设备ID?

    我想从 c 获取 IMEIJNI 我使用下面的代码 但是遇到了未能获取的错误cls 它总是返回NULL 我检查了环境和上下文 它们都没有问题 为什么我不能得到Context班级 我在网上搜索了一下 有人说我们应该使用java lang Ob
  • Jframe 内有 2 个 Jdialogs 的 setModal 问题

    当我设置第一个选项时 我遇到了问题JDialog模态 第二个非模态 这是我正在尝试实现的功能 单击 测试对话框 按钮 一个JDialog有名字自定义对话框 主要的将会打开 如果单击 是 选项自定义对话框主 其他JDialog named 自
  • 将巨大的模式编译成Java

    有两个主要工具提供了将 XSD 模式编译为 Java 的方法 xmlbeans 和 JAXB 问题是 XSD 模式确实很大 30MB 的 XML 文件 大部分模式在我的项目中没有使用 所以我可以注释掉大部分代码 但这不是一个好的解决方案 目
  • 在 Java 中如何找出哪个对象打开了文件?

    我需要找出答案哪个对象在我的 Java 应用程序中打开了一个文件 这是为了调试 因此欢迎使用工具或实用程序 如果发现哪个对象太具体了 这class也会很有帮助 这可能很棘手 您可以从使用分析器开始 例如VisualVM http visua
  • 如何在 Spring 中使 @PropertyResource 优先于任何其他 application.properties ?

    我正在尝试在类路径之外添加外部配置属性资源 它应该覆盖任何现有的属性 但以下方法不起作用 SpringBootApplication PropertySource d app properties public class MyClass
  • Android 无法解析日期异常

    当尝试解析发送到我的 Android 客户端的日期字符串时 我得到一个无法解析的日期 这是例外 java text ParseException 无法解析的日期 2018 09 18T00 00 00Z 位于 偏移量 19 在 java t
  • 在Java中运行bat文件并等待

    您可能会认为从 Java 启动 bat 文件是一项简单的任务 但事实并非如此 我有一个 bat 文件 它对从文本文件读取的值循环执行一些 sql 命令 它或多或少是这样的 FOR F x in CD listOfThings txt do
  • Java继承,扩展类如何影响实际类

    我正在查看 Sun 认证学习指南 其中有一段描述了最终修饰符 它说 如果程序员可以自由地扩展我们所知的 String 类文明 它可能会崩溃 他什么意思 如果可以扩展 String 类 我是否不会有一个名为 MyString 的类继承所有 S
  • 在 Java 中获取并存储子进程的输出

    我正在做一些需要我开始子处理 命令提示符 并在其上执行一些命令的事情 我需要从子进程获取输出并将其存储在文件或字符串中 这是我到目前为止所做的 但它不起作用 public static void main String args try R
  • 将 JavaFX FXML 对象分组在一起

    非常具有描述性和信息性的答案将从我这里获得价值 50 声望的赏金 我正在 JavaFX 中开发一个应用程序 对于视图 我使用 FXML
  • Hibernate 本机查询 - char(3) 列

    我在 Oracle 中有一个表 其中列 SC CUR CODE 是 CHAR 3 当我做 Query q2 em createNativeQuery select sc cur code sc amount from sector cost
  • Java 正则表达式中的逻辑 AND

    是否可以在 Java Regex 中实现逻辑 AND 如果答案是肯定的 那么如何实现呢 正则表达式中的逻辑 AND 由一系列堆叠的先行断言组成 例如 foo bar glarch 将匹配包含所有三个 foo bar 和 glarch 的任何
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似
  • Spring RESTful控制器方法改进建议

    我是 Spring REST 和 Hibernate 的新手 也就是说 我尝试组合一个企业级控制器方法 我计划将其用作未来开发的模式 您认为可以通过哪些方法来改进 我确信有很多 RequestMapping value user metho

随机推荐

  • 【老生谈算法】matlab实现基于粒子群算法的PID控制器优化设计——粒子群算法

    Matlab实现基于粒子群算法的PID控制器优化设计 1 文档下载 本算法已经整理成文档如下 有需要的朋友可以点击进行下载 说明 文档 点击下载 本算法文档 老生谈算法 matlab实现基于粒子群算法的PID控制器优化设计 doc 更多ma
  • android 将服务设置为前台服务

    NotificationChannel channel new NotificationChannel id com xxx xx XxxService NotificationManager IMPORTANCE NONE channel
  • 【LeetCode刷题笔记】位运算

    231 2 的幂 解题思路 1 除法 不断循环判断 如果能被 2 整除 就不断除以 2 直到不能被 2 整除为止 最后结果如果是 1
  • HONEYWELL 05701-A-0511 框架模块

    HONEYWELL 05701 A 0511 框架模块 HONEYWELL 05701 A 0511 框架模块 产品详情 框架模块通常是一种用于构建更大型 更复杂系统的组件 在自动化和控制系统中 框架模块可能用于提供某些基础结构或功能 以支
  • 德思特EMC RICI测试方案助您对抗电磁设备干扰!

    来源 德思特测试测量 德思特方案丨德思特EMC RICI测试方案助您对抗电磁设备干扰 原文链接 https mp weixin qq com s D8wdQr reaFG yppT8nzkw 欢迎关注虹科 为您提供最新资讯 方案背景 电磁或
  • 企业电子招标采购系统源码Spring Cloud + Spring Boot + 前后端分离 + 二次开发

    项目说明 随着公司的快速发展 企业人员和经营规模不断壮大 公司对内部招采管理的提升提出了更高的要求 在企业里建立一个公平 公开 公正的采购环境 最大限度控制采购成本至关重要 符合国家电子招投标法律法规及相关规范 以及审计监督要求 通过电子化
  • 消息队列选型:Kafka 如何实现高性能?

    在分布式消息模块中 我将对消息队列中应用最广泛的 Kafka 和 RocketMQ 进行梳理 以便于你在应用中可以更好地进行消息队列选型 另外 这两款消息队列也是面试的高频考点 所以 本文我们就一起来看一下 Kafka 是如何实现高性能的
  • 【开题报告】基于SpringBoot的幼儿园学生成长管理系统的设计与实现

    1 研究背景 随着社会的发展和人们教育观念的转变 幼儿园在孩子的成长过程中扮演着越来越重要的角色 幼儿园是孩子们接受早期教育的重要阶段 对于他们的身心发展 学习能力和社交能力的培养起着至关重要的作用 因此 建立一套科学 高效的幼儿园学生成长
  • 边缘计算:构建下一代计算基础设施的关键技术

    随着物联网 人工智能和大数据等技术的快速发展 对计算基础设施的需求越来越高 然而 传统的云计算模式存在延迟高 数据传输量大等问题 为了解决这些问题 边缘计算应运而生 本文将介绍边缘计算的概念 探讨其在构建下一代计算基础设施中的关键技术 什么
  • BENTLY 125720-01 后卡模块

    BENTLY 125720 01 后卡模块 BENTLY 125720 01 后卡模块 产品详情 Bently Nevada 的产品 尤其是振动监测和机械振动解决方案 具有以下可能的特点 高精度测量 Bently Nevada 的产品通常设
  • 做一个wiki页面是体验HTML语义的好方法

    HTML语义 如何运用语义类标签来呈现Wiki网页 在上一篇文章中 我花了大量的篇幅和你解释了正确使用语义类标签的好处和一些场景 那么 哪些场景适合用到语义类标签呢 又如何运用语义类标签呢 不知道你还记不记得在大学时代 你被导师逼着改毕业论
  • git commit提交代码时 提交类别 - 提交开头命名规范

    feat 新功能 feature fix 修补bug refactor 重构 即不是新增功能 也不是修改bug的其他代码改动 style 格式 不影响代码运行的变动 test 增加测试 docs 文档 documentation chore
  • 20231219_101701 java io演练 功能演练 保存学生姓名到记事本

    需求 程序启动后 向用户询问学生姓名 如果输入的内容是s 就保存并退出 当程序结束后 把所有的输入的学生姓名 保存到名为students txt的记事本中 一个学生的名字占一行 分析 因为接收的是中文名字 所以建议使用字符流 我们随意选择一
  • 【数据结构和算法】 K 和数对的最大数目

    其他系列文章导航 Java基础合集 数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一 题目描述 二 题解 2 1 方法一 双指针排序 三 代码 3 1 方法一 双指针排序 3
  • 20231219_093920 java 字符流写数据 FileWriter

    说明 FileWriter比起FileOutputWriter要更加好用 后者使用的时候还需要一个FileOutputStream对象 前者直接使用 示例 定义对象 FileWriter fileWriter new FileWriter
  • 比 style gan 更好的 style gan2

    上一篇博客介绍了 style gan 原理 但是 style gan 的结果会有水珠伪影 作者实验后发现是 Adain 导致的 AdaIN对每一个feature map的通道进行归一化 这样可能破坏掉feature之间的信息 当然实验证明发
  • 【工具库推荐】小程序一款阳历阴历(农历)日历组件

    展示 使用方法 组件目录如上图 调用如下图 第一步 在pages rl index json中设置引用这个日历组件 代码如下 第二步 在需要调用页面wxml文件中引用这个日历组件 并绑定相应的属性 如下图 属性解释 showDatePick
  • 策略模式在数据接收和发送场景的应用

    其他系列文章导航 Java基础合集 数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一 策略模式改进 1 1 策略模式的定义 1 2 策略模式的结构通常包括以下组成部分 1 3
  • C/C++编程:令人印象深刻的高级技巧案例

    C C 编程语言在软件开发领域有着悠久的历史 由于其高效 灵活和底层访问能力 至今仍然被广泛应用 本文将介绍一些在C C 编程中令人印象深刻的高级技巧 帮助读者提升编程水平 更加高效地使用这两种强大的编程语言 一 指针运算与内存管理 C C
  • 高可用:如何实现消息队列的 HA?

    管理学上有一个木桶理论 一只水桶能装多少水取决于它最短的那块木板 这个理论推广到分布式系统的可用性上 就是系统整体的可用性取决于系统中最容易出现故障 或者性能最低的组件 系统中的各个组件都要进行高可用设计 防止单点故障 消息队列也不例外 本