本文档介绍了Akka Cluster的设计概念。有关使用Akka群集的指南,请参见:
- 集群使用
- 基于经典Akka API的群集使用
- 集群成员服务
介绍
Akka Cluster提供了容错的、分散的点对点集群成员服务,没有单点故障或单点瓶颈。它基于gossip协议和自动故障检测器实现。
Akka Cluster允许构建分布式应用程序,其中一个应用程序或服务跨越多个节点(实际上是多个ActorSystem)。
条款
- 节点
集群的逻辑成员。物理机上可能有多个节点。由主机名:端口:uid元组定义。
- 集群
一组节点通过集群成员服务连接在一起。
- leader
集群中的单个节点充当领导者。管理集群收敛和成员状态转换。
gossip
Akka中使用的集群成员基于Amazon的Dynamo系统,尤其是Basho的Riak分布式数据库中采用的方法。集群集成员使用Gossip协议进行通信,该协议中群集的当前状态是通过群集随机进行的,优先传递给那些没有看到最新版本的成员。
矢量时钟
矢量时钟是一种数据结构和算法,用于在分布式系统中生成事件的部分排序,检测违反因果关系。
在gossip中,我们使用矢量时钟来协调和合并群集状态的差异。向量时钟是一组(节点,计数器)对。群集状态的每次更新都会伴随矢量时钟的更新。
Gossip收敛
集群在某个时间点收敛到某个节点上。节点可以证明集群中所有其他节点都已观察到集群状态。在gossip时,通过传递一组看到当前状态版本的节点实现收敛。该信息在gossip概述中称为可见集。当所有节点都包含在可见集合中时,就会收敛。
当任何节点都不可达时,gossip就不会收敛。节点需要再次可访问,或移动到关闭和删除状态(请参阅集群成员生命周期部分)。这只会阻止领导者执行其集群成员管理,并且不会影响在集群运行的应用程序。例如,这意味着在网络分区期间无法向群集添加更多节点。节点可以加入,但是在分区修复或无法访问的节点已关闭之前,它们将不会移入Up状态。
故障检测
Akka群集中的故障检测负责检测群集的其余部分是否无法访问该节点。为此,我们使用了Phi应计故障检测器。为了能够应对突发异常情况(例如垃圾收集暂停、瞬态网络故障),可以轻松配置故障检测器以适应您的环境和需求。
在群集中,每个节点都由几个(默认最多5个)其他节点监控。要监控的节点是从哈希排序的节点环中的邻居中选择的。这是为了增加跨机架和数据中心进行监视的可能性,但是在所有节点上的顺序都是相同的,这可以确保完全覆盖。
当检测到任何节点不可达时,该数据将通过gossip传播到集群的其余部分。换句话说,只有一个节点需要将一个节点标记为不可达,以使集群的其余部分将该节点标记为不可达。
故障检测器还将检测节点是否再次可访问。当监视不可达节点的所有节点再次将其视为可达时,在gossip传播之后,群集将认为它是可达的。
如果无法将系统消息传递到节点,它将被隔离,然后就无法从无法访问的节点变为可以访问。如果存在太多未确认的系统消息(例如,监控,已终止,远程actor部署,由远程父级监督的actors失败),则会发生这种情况。然后,需要将节点移至“已关闭”或“已删除”状态(请参阅集群成员生命周期),必须重新启动被隔离节点的actor系统,然后才能再次加入集群。
更多详细信息,请参见以下内容:
- Phi应计故障检测器实现
- 使用故障检测器
Leader
gossip收敛之后,可以确定集群的leader。没有leader选举过程,只要出现gossip收敛,任何节点都可以始终确定地识别leader。leader只是一个角色,任何节点都可以成为leader,并且它可以在收敛回合之间改变。leader是按顺序排列的第一个节点,它可以充当领导者角色,leader的首选成员状态是Up,Leaving(有关成员状态的更多信息,请参阅集群成员生命周期)。
领导者的角色是将成员移入和移出群集,将加入成员更改为向上状态,或将退出成员更改为已移除状态。当前,领导者动作仅通过八卦收敛接收到新的集群状态来触发。
种子节点
种子节点是新节点加入群集的联系点。启动新节点时,它将向所有种子节点发送一条消息,然后将联接命令发送到首先响应的种子节点。
种子节点配置值对正在运行的群集本身没有任何影响,它仅与新节点加入群集有关,因为它有助于它们找到将连接命令发送到的联系点;新成员可以将此命令发送给集群的任何成员,而不仅是种子节点。
Gossip协议
push-pull gossip的变体用于减少在集群发送的gossip信息的数量。在push-pull gossip协议中,将发送摘要以表示当前版本,而不是实际值。然后,gossip的接收者可以将其具有较新版本的任何值发送回去,还可以请求其具有过时版本的值。 Akka使用带有矢量时钟的单个共享状态进行版本控制,因此Akka中使用的push-pull gossip变体利用此版本仅根据需要推送实际状态。
周期性地,默认值为每1秒一次,每个节点选择另一个随机节点来发起一轮gossip。如果少于1/2的节点驻留在可见集中(已经看到新状态),则群集将gossip 每秒3次,而不是每秒一次。调整后的gossip间隔是在状态更改后加快早期传播阶段的收敛过程。
gossip节点的选择是随机的,但偏向可能没有看到当前状态版本的节点。在每次gossip交换过程中,当尚未达到收敛时,一个节点会以很高的概率(可配置)与另一个不属于可见集合的节点(即可能具有较旧版本的状态)进行gossip。否则,它会和存活节点随机gossip。
这种有偏见的选择是在状态更改后,加速后期传播阶段收敛过程的方法。
对于大于400个节点的集群(可配置,根据经验证据),逐渐降低到0.8的概率,避免单个散乱者出现过多并发gossip请求的。gossip接收者还具有一种机制,可以通过丢弃已在邮箱中排队太长时间的消息来保护自己免受太多同时发的gossip消息的侵害。
当群集处于聚合状态时,gossiper只会向所选节点发送一条包含gossip版本的gossip状态消息。一旦集群发生变化(意味着不收敛),它将再次回到有偏差的gossip中。
gossip状态或gossip状态的接收者可以使用gossip版本(矢量时钟)来确定:
1.它具有gossip状态的新版本,在这种情况下,它会将其发送回gossiper
2.它具有过时的状态版本,在这种情况下,接收者通过回传其gossip状态版本,向gossiper请求当前状态
3.它的gossip版本冲突,在这种情况下,不同的版本将合并,并发回
如果收件人和gossip版本相同,则不会发送或请求gossip状态。
gossip的周期性对状态变化具有很好的批处理效果,例如很快将多个节点彼此连接到一个节点,仅导致一个状态更改,传播到集群中的其他成员。
gossip消息使用protobuf进行序列化,并且也被压缩,以减小有效负载大小。