掘金 后端 ( ) • 2024-04-27 21:48

什么是流言协议?

在分布式系统中,以下两个是典型的问题:

  • 维护系统状态(节点的活跃性)
  • 节点间的通信

解决这些问题的解决方案之一如下:

  • 集中式状态管理服务
  • 对等状态管理服务

集中式状态管理服务

像 Apache Zookeeper 这样的集中式状态管理服务可以被配置为服务发现,以跟踪系统中每个节点的状态。尽管这种方法提供了强大的一致性保证,但主要缺点是状态管理服务成为单点故障,并且对于大型分布式系统也会遇到可扩展性问题。

对等状态管理服务

对等状态管理方法倾向于高可用性和最终一致性。可以使用流言协议算法(Gossip Protocol)来实现具有高可扩展性和改进的弹性的对等状态管理服务。 流言协议也被称为流行病协议,因为消息的传输类似于流行病的传播方式。流言协议中的通信概念类似于谣言在公司员工之间的传播,或者是信息在社交媒体网站上的传播。

广播协议

在分布式系统中,流行的消息广播技术包括:

  • 点对点广播
  • 可靠广播
  • 流言协议

点对点广播

在点对点广播中,生产者直接向消费者发送消息。生产者上的重试机制和消费者上的去重机制使点对点广播可靠。当生产者和消费者同时失败时,消息会丢失。

可靠广播

每个节点通过可靠的网络链接将消息重新广播给每个其他节点。这种方法提供了改进的容错性,因为即使生产者和消费者同时失败,消息也不会丢失。剩余节点将重新广播消息。可靠广播的注意事项包括:

  • 由于为 n 个节点广播 O(n²) 条消息,导致显著的网络带宽使用
  • 发送节点可能因O(n)线性广播而成为瓶颈
  • 每个节点存储系统中所有节点的列表,导致存储成本增加

流言协议

流言协议是一种去中心化的对等通信技术,用于在庞大的分布式系统中传输消息。流言协议的关键概念是每个节点定期向其他随机节点的子集发送消息。整个系统最终将以很高的概率接收到特定消息。概括来说就是,流言协议是一种通过有限的局部交互建立全局映射的技术。

流言协议建立在健壮、可扩展且最终一致的算法之上。流言协议通常用于维护分布式系统中的节点成员列表、达成共识和故障检测。此外,还可以在流言消息上附带应用程序级数据等附加信息。

流言协议是可靠的,因为节点故障可以通过另一个节点重新传输消息来克服。可以使用流言协议实现先进先出(FIFO)广播、因果广播和完全顺序广播。

可以调整流言协议参数,如周期和扇出,以提高流言协议的概率保证。

流言协议的以下特性使其成为大规模分布式系统中通信协议的最佳选择:

  • 限制每个节点传输的消息数量
  • 限制带宽消耗,防止应用程序性能下降
  • 容忍网络和节点故障

只有当执行的操作是可交换的,并且不需要序列化时,流言协议才能用于保持节点一致性。墓碑是一种特殊条目,用于使具有匹配键的数据条目无效,而不是实际删除数据。流言协议使用墓碑从节点中删除数据。

流言协议类型

在选择特定用例的流言协议类型时,必须考虑流言协议传播消息所需的时间和在传播消息时产生的网络流量。流言协议可以大致分类为以下类型:

  • 反熵增模型
  • 谣言传播模型
  • 聚合模型

反熵增流言协议

反熵增算法旨在减少如数据库等有状态服务的副本之间的熵。比较复制的数据,并修补副本之间的差异。在每个流言轮次中,拥有最新消息的节点将其与其他节点共享。

反熵增模型通常会传输整个数据集,导致不必要的带宽使用。可以使用诸如校验和、最近更新列表和 Merkle 树等技术来识别节点之间的差异,以避免传输整个数据集并减少网络带宽使用。反熵增流言协议将发送无限数量的消息,没有终止。

谣言传播流言协议

谣言传播协议也被称为传播协议。谣言传播周期比反熵增周期发生得更频繁,并以最坏情况负载淹没网络。谣言传播模型使用更少的资源,如网络带宽,因为只有最新的更新被传输到节点之间。

消息在几轮通信后将被标记为已删除,以限制消息的数量。通常,消息有很高的概率到达所有节点。

聚合流言协议

聚合流言协议通过采样每个节点的信息并结合值来计算系统范围的聚合值。

通过流言协议传播消息的策略

流言协议是构建高可用服务的最佳框架。通过流言协议传播消息的策略应根据服务要求和可用的网络条件进行选择。在带宽、延迟和可靠性方面,每种传播消息的策略都有权衡。适用于反熵增和谣言传播模型的传播消息的不同策略如下:

  • 推模型
  • 拉模型
  • 推拉结合模型

推模型

当只有少数更新消息时,推模型是有效的,因为流量开销。在推模型中,拥有最新消息的节点将消息发送给其他节点的随机子集。

拉模型

在拉模型中,每个节点将主动轮询节点的随机子集,以获取任何更新消息。当有许多更新消息时,这种方法是有效的,因为很有可能找到具有最新更新消息的节点。

推拉结合模型

推拉结合模型是快速可靠传播更新消息的最佳选择。节点可以推送新更新消息,也可以轮询新更新消息。推方法在初始阶段是有效的,因为只有少数节点具有更新消息。拉方法在最后阶段是有效的,当时有许多节点具有许多更新消息。

流言协议性能

从特定节点接收消息的节点数称为扇出。将消息传播到整个集群所需的流言轮数称为周期

将消息传播到集群所需的周期数 = O(log n),其中 n = 节点总数

例如,将消息传播到 25,000 个节点大约需要 15 轮流言。可以将流言间隔设置为低至 10 ms,以在大约 3 s 内将消息传播到大型数据中心。流言协议中的信息传播应自动老化,以减少不必要的负载。可以使用以下指标来衡量流言协议实现的性能:

  • 残留:尚未收到消息的剩余节点数量应最小化
  • 流量:节点之间发送的平均消息数应最小化
  • 收敛:每个节点应尽快收到消息
  • 时间平均:将消息发送给每个节点所需的平均时间应低
  • 时间最后:最后一个节点收到消息所需的时间应低

案例研究表明,具有 128 个节点的系统在运行流言协议时消耗的 CPU 不到 2 %,带宽不到 60 KBps。

流言协议属性

没有正式的方法来定义流言协议。一般来说,流言协议应该满足以下属性:

  • 节点选择必须是随机的,以执行扇出
  • 每个节点只有本地信息可用,并且节点不了解集群的状态
  • 节点之间的通信涉及定期的、成对的、进程间交互
  • 每个流言轮次的传输容量有界
  • 每个节点部署相同的流言协议
  • 假设节点之间存在不可靠的网络路径
  • 节点交互频率低
  • 节点交互导致状态交换

流言算法

流言算法的流程如下:

  1. 每个节点维护一个节点子集及其元数据的列表
  2. 定期向随机活动对等节点的端点流言
  3. 每个节点检查接收到的流言消息,将最高版本号合并到本地数据集中

当特定节点参与流言交换时,节点的心跳计数器会增加。当心跳计数器持续增加时,节点被标记为健康。另一方面,当心跳计数器由于网络分区或节点故障而在很长一段时间内没有变化时,节点被认为不健康。其中,流言协议中对等节点选择的不同标准如下:

  • 使用编程语言提供的库,如使用 java.util.random
  • 与联系最少的节点进行交互
  • 强制执行网络拓扑感知交互

流言协议实现

流言协议通过用户数据报协议(UDP)或传输控制协议(TCP)传输消息,具有可配置但固定的扇出和间隔。对等采样服务由流言协议用于识别流言消息交换的对等节点。对等采样服务使用随机算法选择对等节点。对等采样服务的接口一般会提供以下功能接口:

  • /gossip/init:在启动时返回特定节点已知的节点列表
  • /gossip/get-peer:返回独立对等节点的地址(IP 地址和端口号)

对等采样服务执行的工作流程如下:

  1. 使用系统的部分视图(节点子集的列表)初始化每个节点
  2. 在流言交换上将节点的视图与对等节点的视图合并

换句话说,每个节点维护一个小的本地成员表,具有系统的部分视图,并通过流言消息定期刷新表。流言协议可以利用概率分布选择对等节点,以减少向同一节点传输重复消息。

应用程序状态可以通过流言协议作为键值对传输。当节点对同一键执行多个更改时,必须传输最新值。流言协议提供的 API 来协调应用程序状态交换如下:

  • /gossip/on-join
  • /gossip/on-alive
  • /gossip/on-dead
  • /gossip/on-change

种子节点是基于静态配置的完全功能节点。系统中的每个节点都必须知道种子节点。流言系统与种子节点交互,以防止逻辑分区。当节点接收到包含对等节点元数据的流言消息时,以下是由流言协议执行的详细流程:

  1. 比较传入的流言消息,以识别本地节点数据集中缺失的值
  2. 比较传入的流言消息,以识别对等节点数据集缺失的值
  3. 当节点已经包含传入流言消息中存在的值时,选择更高版本值
  4. 在本地节点的数据集中附加缺失的值
  5. 在响应中返回对等节点数据集中缺失的值
  6. 使用收到的响应更新对等节点的数据集

通常,在节点启动时,通过流言协议传输整个节点元数据。每个节点可以通过维护一个内存中的版本号,通过流言协议只发送节点元数据的增量更新。

生成时钟是一个单调递增的数字,表示服务器的生成。每当节点重新启动时,生成时钟就会增加。版本号保证了应用程序状态的排序和版本控制。版本号只能增加。生成时钟可以与版本号一起使用,以在节点重新启动时正确检测节点元数据的更改。

流言定时器是流言协议的一个组件,将确保每个节点最终包含有关对等节点的关键元数据,包括位于网络分区后面的节点。每个节点都包含与之关联的心跳。心跳状态由生成和版本号组成。应用程序状态由表示节点状态的键值对和版本号组成。

发起流言交换的节点发送一个流言摘要同步消息,该消息包含流言摘要的列表。流言摘要包含端点地址、生成编号和版本号。流言摘要确认消息包含流言摘要列表和端点状态列表。

流言协议应用场景

流言协议在许多最终一致性受到青睐的应用程序中使用。流言协议的流行应用程序如下:

  • 数据库复制
  • 信息传播
  • 维护集群成员资格
  • 故障检测
  • 生成聚合(计算平均值、最大值、总和)
  • 生成覆盖网络
  • 领导者选举

流言协议可以以很高的概率在分布式系统中检测节点故障。节点故障的检测可以节省 CPU、带宽和队列空间等资源。在分布式系统中,当单个客户端无法与特定节点交互时,不能断言节点故障,因为可能会发生网络分区或客户端故障。当几个节点(客户端)通过流言协议确认特定节点的活动性时,可以确定特定节点的故障。

流言协议对于数据交换和指挥控制比通过 TCP 连接更可靠。流言协议允许将关于节点和子系统属性的通信从应用程序逻辑中抽象出来。可以将诸如平均负载和空闲内存之类的节点统计信息传输到流言消息中,以改善有关扇出的本地决策制定。

诸如队列深度、关键元数据(如配置更改)甚至请求-响应之类的子系统信息可以通过流言协议传输。通过流言协议聚合节点更新消息允许以单个块发送数据,而不是多个小消息,以减少通信开销。

通过识别节点的活动性,可以跨集群最优地路由消息。在不涉及集中式服务的情况下,在本地节点级别进行决策制定是扩展流言协议的关键。可以使用向量时钟对消息进行版本控制,以便节点通过向量时钟忽略旧的消息版本。使用流言协议的一些常见组件如下:

  • Apache Cassandra 使用流言协议维护集群成员资格,传输节点元数据(令牌分配)
  • Consul 使用 swim-gossip 协议变体进行组员资格、领导者选举和 consul 代理的故障检测
  • CockroachDB 操作流言协议来传播节点元数据
  • Amazon S3 使用流言协议在系统中传播服务器状态
  • Redis 集群使用流言协议传播节点元数据

流言协议优势

流言协议具有以下优势:

  • 可扩展性
  • 容错性
  • 鲁棒性
  • 一致性
  • 去中心化
  • 有界负载

可扩展性

可扩展性是系统在处理不断增加的负载时不降低性能的能力。流言协议循环需要对数时间来实现收敛。此外,每个节点只与固定数量的节点进行交互,并独立于系统中节点的数量发送固定数量的消息。节点不会等待确认以提高延迟。

容错性

容错性是系统在发生故障(如节点崩溃、网络分区或消息丢失)时仍能保持功能的能力。采用流言协议的分布式系统具有容错性,因为它能够容忍不可靠的网络。流言协议提供的冗余、并行性和随机性提高了系统的容错性。

此外,节点的对称性和去中心化特性增强了流言协议的容错性[5]。相同的消息通常通过多个节点多次传输。换句话说,消息在源点和目的地之间有许多路由。因此,通过另一个节点的消息传输可以克服节点故障。

鲁棒性

参与流言协议的节点的对称性质提高了系统的鲁棒性。节点故障不会破坏系统质量。流言协议还对瞬态网络分区具有鲁棒性。然而,除非数据自验证,否则流言协议对故障节点或恶意流言消息并不鲁棒。

可以使用基于分数的节点声誉系统来防止恶意节点破坏流言系统。必须实施适当的机制和政策,如加密、认证和授权,以强制执行流言系统的隐私和安全。

一致性

一致性是确保系统中每个节点都有相同状态视图的技术。不同的一致性级别,如强一致性、最终一致性、因果一致性和概率一致性,对系统的性能、可用性和正确性有不同的影响。通过数据的指数级传播,流言协议以对数时间复杂度收敛到最终一致状态。

去中心化

流言协议提供了一个通过对等通信进行信息发现的极端去中心化模型。

有界负载

经典的分布式系统协议通常会产生高突增负载,可能会使单个分布式系统组件超载。流言协议将对单个分布式系统组件产生严格有界的最坏情况负载,以避免破坏服务质量。流言协议中的对等节点选择可以调整以减少网络链路上的负载。在实践中,流言协议产生的负载不仅是有界的,而且与可用带宽相比也是微不足道的。

流言协议缺点

当然,事物都有两面性,流言协议的也存在如下一些缺点:

  • 最终一致性
  • 对网络分区不敏感
  • 相对较高的带宽消耗
  • 增加延迟
  • 调试和测试困难
  • 成员协议不可扩展
  • 容易计算错误

最终一致性

流言协议本质上是最终一致的。与多播相比,流言协议会相对较慢。与流言消息相关的开销以及流言行为取决于网络拓扑和节点异构性。因此,集群识别新节点或节点故障会有一定的延迟。

网络分区不敏感

当发生网络分区时,子分区中的节点仍将相互流言。因此,流言协议对网络分区不敏感,可能会显著延迟消息传播。

带宽

流言协议并不以效率著称,因为相同的消息可能会多次重新传输到同一节点,消耗不必要的带宽。尽管由于有界消息大小和消息的周期性交换,流言协议的带宽使用受到限制,但当节点应该流言的信息量超过有界消息大小时,通过流言交换的有效扇出可能会降低[7]。

流言协议的饱和点取决于不同的参数,如消息生成速率、消息大小、扇出和流言协议的类型。

延迟

使用流言协议会导致延迟增加,因为节点必须等待下一个流言周期(间隔)来传输消息。消息不会触发流言交换,但流言协议间隔计时器会。将消息传播到系统所需的时间复杂度是 O(log n)。

调试和测试

调试是识别和修复导致流言协议偏离预期行为的故障。测试是验证流言协议是否满足功能和非功能要求(如性能、可靠性和安全性)的能力。

流言协议固有的非确定性和分布式特性使其难以调试和重现故障。调试验证时可以使用模拟、仿真、日志记录、跟踪、监控和可视化等工具和技术来测试和调试流言系统。

可扩展性

大多数流言协议的变体依赖于一个不可扩展的成员协议。

计算错误

由于恶意节点,流言协议倾向于计算错误。节点应实现自我纠错机制,因为流言协议的鲁棒性仅限于某些故障类别。尽管如此,流言协议非常可靠,具有概率为一的结果很常见。

总结

在分布式系统中,流言是一件好事,而在现实世界中就不一定了。。