Akka-Networking Cluster Specification

Akka:集群规范

Akka集群提供容错的(fault-tolerant)、去中心化的(decentralized)、基于点对点的(peer-to-peer based),没有单点故障或单点瓶颈的集群成员服务。Akka集群使用Gossip协议和自动故障检测器(automatic failure detector)来实现上述目标。

1. 术语

1. 节点(node)

集群的逻辑成员。一台物理机上可能有多个节点。一个节点由节点标识符“hostname:port:uid”定义。

2. 集群(cluster)

通过成员服务(membership service)连接在一起的一组节点。

3. 领导(Leader)

集群中充当领导者的单个节点。管理集群收敛和成员状态的转换。

2. 成员(Membership)

集群由一组成员节点组成。每个节点的标识符是一个“hostname:port:uid”元组。一个Akka应用程序可以分布在一个集群上,每个节点都承载了应用程序的某些部分。集群成员和运行在该应用程序节点上的Actor是解耦的(decoupled)。一个管理任何Actor的节点也可以是集群的成员。可以通过向集群中的一个节点发出JOIN命令来加入集群。

节点标识符内部还包含一个UID,来唯一标识具有“hostname:port ”的Actor系统的实例。Akka通过UID来可靠的触发远程死亡监视(remote death watch)。这意味着相同的Actor系统一旦从集群中删除,就不能再次加入集群。要将一个具有相同“hostname:port ”的Actor系统重新加入到集群中,必须先停止该Actor系统并启动一个新的具有相同“hostname:port ”的Actor系统,然后它将接收一个不同的UID。

集群成员状态是特定的CRDT(Convergent and Commutative Replicated Data Types),这意味着它具有单调合并功能。当并发的更改发生在不同节点上时,更新总是可以被合并,并收敛到相同的最终结果。

3. Gossip

Akka的集群基于Amazon的Dynamo系统,尤其是在Basho的“Riak分布式数据库”中所采用的方法。集群成员使用Gossip协议进行沟通交流,其中集群的当前状态通过“gossiped”随机的在集群中散布,优先散布到没有接收到集群最新版本的成员。

1.矢量时钟(Vector Clocks)

矢量时钟是一种数据结构和算法,用于在分布式系统中生成事件的部分排序并检测违规因果关系。

我们使用矢量时钟来协调和合并在gossiping期间的集群状态差异。矢量时钟是一组(node, counter)键值对。对集群状态的每次更新都会伴随矢量时钟的更新。

2.Gossip Convergence

有关集群的信息在特定时间点在本地节点收敛。这是一个节点用来证明:他正在观察的集群状态已经被集群中的所有其他节点观察到。收敛是通过一组在gossiping期间看到当前状态版本的节点来实现的。这个信息被称为在gossip overview中看到的集合。当所有节点都包含在可见集合中时,就会收敛。

当有任何节点变为不可达状态时(unreachable),不能发生Gossip Convergence。节点需要重新变为可达状态(reachable),或移动到down或remove状态(参见下面的Membership Lifecycle部分)。这只会阻止Leader执行集群成员管理,并不会影响在集群上运行的应用程序。例如,在网络分区期间,无法向集群添加更多节点。节点可以加入(join),但是在分区已经愈合或者不可达节点被关闭之前,新加入的节点不会被移动为up状态。

3.故障检测器(Failure Detector)

故障检测器负责检测节点是否与集群其余部分不可达(unreachable)。为此,通过使用Hayashibara等人的“The Phi Accrual Failure Detector ”来实现。

故障检测器解耦监测和解释。这使得它们适用于更广泛的场景,并且更适合构建通用的故障检测服务。它保留了失败统计的历史,计算从其他节点收到的心跳,试图通过考虑多个因素来进行有根据的猜测,并且考虑到他们随着时间的推移积累会如何变化,以便更好的猜测一个特定节点是up或down。

对于“节点是否关闭(is the node down?)”的问题,它返回一个表示节点关闭的可能性的phi值,而不是回答“是”或“否”。

作为计算基础的阈(yù)值(threshold)可由用户配置。低阈值容易产生许多错误的怀疑,但确保在真实发生崩溃事件中进行快速检测。相反,高阈值会产生较少的错误,但需要更多时间来检测实际的崩溃。 默认阈值为8,适用于大多数情况。然而,在云环境(如Amazon EC2)中,该值可以增加到12,以解决此类平台上偶尔出现的网络问题。

在一个群集中,每个节点由几个其他节点进行监视(默认最多5个),当这些节点中的任何一个检测到某节点unreachable时,该信息将通过gossip传播到集群的其余部分。换句话说,只要有一个节点标记某个节点unreachable,其余的集群便会标记该节点unreachable。

要监视的节点从散列有序节点环中的邻居节点中选出。 这是为了增加对跨机房和数据中心进行监控的可能性,但在所有节点上的顺序是相同的,这确保了监视的全面覆盖。

心跳每秒发出一次,每次心跳通过请求/应答握手实行,并将应答用作故障检测器的输入。

故障检测器还将检测节点是否再次可达(reachable)。当监听不可达节点的所有节点检测到该节点可以再次到达时(reachable),在gossip传播后,集群将认为它是可达到的(reachable)。

如果无法将系统消息传递到节点,则会将其隔离,并无法从不可访问的状态恢复。 如果存在太多未确认的系统消息(例如监视,终止,远程Actor部署,由远程父节点监督的Actor的失败),则可能发生这种情况。 然后,节点需要移动到down或remove状态(参见下面的Membership Lifecycle部分),并且必须重新启动 Actor系统才能再次加入集群。

4.Leader

在Gossip Convergence后,可以确定集群的Leader。没有Leader的选举过程,无论何时有Gossip Convergence,任何一个节点都可以确定地认出Leader。Leader只是一个角色,任何一个节点都可以成为Leader,它可以在收敛轮次之间改变。Leader只是排序顺序中第一个能够担任领导角色的节点,Leader的首选成员状态为up和leaving(有关成员状态的更多信息,请参阅下面的Membership Lifecycle部分)。

Leader的作用是管理成员加入或退出集群,将joining的成员转变为up状态或将exiting的成员转变为removed状态。目前Leader的行为只能通过接收在gossip convergence后新的集群状态来触发。

通过配置,Leader也有权力“auto-down”一个被故障检测器认为不可达的节点。 这意味着在配置的不可达时间之后,将unreachable节点状态设置为down 。

5.种子节点(Seed Nodes)

种子节点被配置为加入集群的新节点的联系点。当新节点启动时,它会向所有种子节点发送一条消息,然后发送一个join命令到首先应答的种子节点。

种子节点的配置值对运行的集群本身没有任何影响,有助于新节点加入集群时,找到发送join命令的联系点; 新成员可以将此命令发送到当前群集的任何成员,而不仅仅是发送给种子节点。

6.Gossip Protocol

推挽(push-pull)Gossip的变化是用来减少围绕集群发送的Gossip信息量。在推挽Gossip中,发送摘要(digest)代表当前版本,但不是实际值; Gossip的收件人可以发回任何具有较新版本的值,并请求具有过时版本的值。Akka使用一个单独的共享状态和一个矢量时钟进行版本控制,因此在Akka中使用的推挽Gossip变体来使用此版本:只根据需要推送实际状态。

每个节点定期地(默认每1秒一次)选择另一个随机节点来发起一轮Gossip。 如果少于1/2的节点驻留在所看到的集合中(已经看到新的状态),那么该集群会每秒进行3次Gossip。这种调整后的Gossip间隔是在状态变化后的早期传播阶段,一种加速收敛过程的方法。

对要Gossip的节点的选择是随机的,但偏向于可能没有看到当前状态版本的节点。在每一轮gossip exchange中,当还没有达到收敛时,节点使用非常高的概率(可配置)与另一个不属于所看到的集合中的节点进行Gossip,也就是可能具有旧版本状态的节点。 否则,它将随意向活动节点进行Gossip。

这种有偏向的选择是在状态改变后的后期传播阶段,加快收敛过程的一种方式。

对于大于400个节点(可配置,并通过经验证据建议)的集群,0.8概率(偏向的概率)逐渐减小,以避免单个散布者与过多的并发Gossip请求。Gossip接收器还有一种机制,通过丢弃已经在邮箱中排队太久的消息来保护自己免受太多同时发生的Gossip消息的影响。

当集群处于收敛状态时,gossiper仅向所选节点发送一个包含Gossip版本的小型Gossip状态消息。一旦集群发生变化(意味着不收敛),那么它再次回到偏向的Gossip。

Gossip状态或Gossip状态的接收者可以使用Gossip版本(矢量时钟)(gossip version (vector clock) )来确定:

  1. 它有一个较新版本的Gossip状态,在这种情况下,它将较新版本的Gossip状态发送回到gossiper。
  2. 它有一个过时的状态版本,在这种情况下,接收者通过发回其Gossip状态的版本来请求来自gossiper的当前状态。
  3. 它具有冲突的Gossip版本,在这种情况下,不同的版本被合并后发回。

如果接收者和Gossip具有相同的版本,则不会发送或请求Gossip状态。

Gossip的周期性对状态变化具有很好的批量处理效果, 将多个节点快速地连接到一个节点之后将导致只有一个状态变化传播到集群中的其他成员。

Gossip消息通过protobuf进行序列化,并gzipped以减少有效负载大小。

4.成员生命周期(Membership Lifecycle)

  节点从joining状态开始。 一旦所有节点都看到新节点正在加入(通过gossip convergence),Leader就会将该成员状态设置为up。

  如果节点以安全、预期的方式离开集群,则它切换到leaving状态。一旦Leader观测到leaving状态节点上的收敛,Leader将会将其移动到exiting状态。 一旦所有节点都看到了exiting状态(收敛),则Leader将从集群中删除节点,将其标记为removed。

  如果一个节点不可达(unreachable ),则Gossip是不可能收敛的,因此任何Leader的行为(actions)也是不可能的(例如,允许节点成为集群的一部分)。为了能够继续前进发展,必须改变unreachable节点的状态。unreachable节点必须再次可达(reachable )或标记为down。如果该节点要再次加入集群,则必须重新启动该Actor系统并再次通过加入过程(joining process)来加入集群。集群可以在配置的不可达时间超时后,通过Leader自动关闭节点。如果不可达节点的新化身试图重新加入集群,在集群中的旧的化身将被标记为关闭,新的化身可以重新加入集群而无需手动干预。

注意:

​ 如果启用了“auto-down”功能、触发了故障检测器,并且您没有采取措施关闭已经无法访问的节点,则最终会导致出现许多单个节点的集群。 这是因为无法访问的节点可能会将其余集群视为无法访问,则成为自己的Leader并形成自己的集群。

  如前所述,如果一个节点unreachable,则Gossip是不可能收敛的,因此任何Leader的行为也是不可能的。通过启用akka.cluster.allow-weakly-up-member(默认启用),可以在尚未达到收敛的同时促进新节点的加入。这些新连接的节点将被提升为WeaklyUp状态。 一旦达到Gossip收敛,Leader将WeaklyUp状态的成员移至Up。

  请注意,网络分区另一端的成员并不了解新成员是否存在。 例如,您不应该在做群体决策的时候计入WeaklyUp状态的成员。

1.Member States

  • joining – 加入集群时的瞬时状态
  • weakly up – 网络拆分(network split)时的瞬时状态(只有当‘akka.cluster.allow-weakly-up-members=on’时会出现)
  • up – 正常运行状态
  • leaving / exiting – 优雅的删除过程中的状态
  • down – 标记为 down (不再是集群决策的一部分)
  • removed – 墓碑状态(不再是集群成员)

2.User Actions

  • join – 将单个节点连接到集群 – 如果在配置中指定了要加入的节点,则可以显式或自动启动
  • leave – 告诉节点优雅的离开集群
  • down – 标识一个节点为down

3.Leader Actions

​ 集群Leader有以下职责:

  • 将成员加入和移出集群
    • joining –> up
    • exiting –> removed

4.故障检测和不可达性(Failure Detection and Unreachability)

  • fd * – 其中一个监控节点的故障检测器已经触发,导致被监视节点被标记为不可达
  • unreachable*  –  unreachable不是一个真正的成员状态,更多的是一个标志,表明集群无法与该节点进行交流,在不可达之后,故障检测器可以检测到它再次可达,从而移除标志

5.成员状态图(akka.cluster.allow-weakly-up-members = off)

member-states.png

6.成员状态图 (akka.cluster.allow-weakly-up-members=on)

member-states-weakly-up.png

知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

发表评论

电子邮件地址不会被公开。 必填项已用*标注