Scala Akka集群在EC2/docker上保存并不断存储关于成员资格的错误信息

Scala Akka集群在EC2/docker上保存并不断存储关于成员资格的错误信息,scala,docker,amazon-ec2,akka-cluster,Scala,Docker,Amazon Ec2,Akka Cluster,环境:scala-2.11.x,akka-2.5.9 EC2上有两台主机:H1和H2。 sbt项目有三个树模块:master、client和worker。 每个模块实现akka集群节点,该节点订阅集群事件并记录它们。此外,每个节点每1分钟记录一次集群状态(用于调试)。以下端口用于群集节点:主节点:2551,工作节点:3000,客户端:5000 该项目可在 有关基础设施的更多详细信息: 模块可以在H1或H2中随机重新部署 阿克卡星系团有一种奇怪的行为。重新部署其中一个节点(例如工作者)时。以下步骤

环境:
scala-2.11.x
akka-2.5.9

EC2上有两台主机:
H1
H2
。 sbt项目有三个树模块:
master
client
worker
。 每个模块实现akka集群节点,该节点订阅集群事件并记录它们。此外,每个节点每1分钟记录一次集群状态(用于调试)。以下端口用于群集节点:
主节点:2551
工作节点:3000
客户端:5000

该项目可在

有关基础设施的更多详细信息:

模块可以在
H1
H2
中随机重新部署

阿克卡星系团有一种奇怪的行为。重新部署其中一个节点(例如
工作者
)时。以下步骤说明了部署的历史记录:

初始状态-当
worker
部署在
H1
master
client
部署在
H2

----[state-of-deploying-0]---  
H1 = [worker]
H2 = [master, client]

cluster status:    // cluster works correctly
  Member(address = akka.tcp://ClusterSystem@H1:3000, status = Up)
  Member(address = akka.tcp://ClusterSystem@H2:2551, status = Up)
  Member(address = akka.tcp://ClusterSystem@H2:5000, status = Up)
----------------
----[state-of-deploying-1]---  
H1 = [-]
H2 = [master, client, worker (Redeployed)]

cluster status:    // WRONG cluster state!
  Member(address = akka.tcp://ClusterSystem@H1:3000, status = Up) // ???
  Member(address = akka.tcp://ClusterSystem@H2:2551, status = Up)
  Member(address = akka.tcp://ClusterSystem@H2:3000, status = WeaklyUp)
  Member(address = akka.tcp://ClusterSystem@H2:5000, status = Up)
----------------
之后,
worker
模块已重新部署到主机
H2

----[state-of-deploying-0]---  
H1 = [worker]
H2 = [master, client]

cluster status:    // cluster works correctly
  Member(address = akka.tcp://ClusterSystem@H1:3000, status = Up)
  Member(address = akka.tcp://ClusterSystem@H2:2551, status = Up)
  Member(address = akka.tcp://ClusterSystem@H2:5000, status = Up)
----------------
----[state-of-deploying-1]---  
H1 = [-]
H2 = [master, client, worker (Redeployed)]

cluster status:    // WRONG cluster state!
  Member(address = akka.tcp://ClusterSystem@H1:3000, status = Up) // ???
  Member(address = akka.tcp://ClusterSystem@H2:2551, status = Up)
  Member(address = akka.tcp://ClusterSystem@H2:3000, status = WeaklyUp)
  Member(address = akka.tcp://ClusterSystem@H2:5000, status = Up)
----------------
上述情况时有发生。在这种情况下,群集存储了错误的成员状态,并且不会修复它:

Member(address = akka.tcp://ClusterSystem@H1:3000, status = Up) // ???
主机
H1
不包含
worker
的任何实例。和
>telnet H1 3000
返回
拒绝连接

但是为什么akka集群一直存储错误的信息?

这种行为是有意的,生产中的akka集群应该在没有自动关闭的情况下运行,以防止大脑分裂问题

设想一个具有两个客户端(X和Y)的双节点(a和B)集群:

  • 开始时,一切正常,连接到
    B
    Y
    请求可以转发到
    a
    上运行的
    Actor1
    进行远程处理
  • 然后,由于网络分区,
    a
    无法从
    B
    访问,
    B
    可能会尝试将
    a
    标记为关闭,并在本地重新启动
    Actor1
  • 客户端
    Y
    向运行在
    B

  • 网络分区另一端的客户端
    X
    仍连接到
    A
    ,并将向
    Actor1

这是一个大脑分裂的问题:具有相同标识符的同一参与者在具有两种不同状态的两个节点上运行。重建正确的参与者状态非常困难或不可能

为了防止这种情况发生,您必须为您的问题或用例选择合理的停机策略:

  • 如果你能负担得起,可以使用手动羽绒服。操作员将识别出集群确实已关闭,并将节点标记为无法访问
  • 如果您的集群具有动态数量的节点,那么您需要一些复杂的东西,如Lightbend Split Brain解析器
  • 如果集群是静态的,您可以使用仲裁策略来避免大脑分裂。您始终需要运行奇数个节点

这种行为是有意的,生产中的Akka cluster应该在没有自动关机的情况下运行,以防止大脑分裂问题

设想一个具有两个客户端(X和Y)的双节点(a和B)集群:

  • 开始时,一切正常,连接到
    B
    Y
    请求可以转发到
    a
    上运行的
    Actor1
    进行远程处理
  • 然后,由于网络分区,
    a
    无法从
    B
    访问,
    B
    可能会尝试将
    a
    标记为关闭,并在本地重新启动
    Actor1
  • 客户端
    Y
    向运行在
    B

  • 网络分区另一端的客户端
    X
    仍连接到
    A
    ,并将向
    Actor1

这是一个大脑分裂的问题:具有相同标识符的同一参与者在具有两种不同状态的两个节点上运行。重建正确的参与者状态非常困难或不可能

为了防止这种情况发生,您必须为您的问题或用例选择合理的停机策略:

  • 如果你能负担得起,可以使用手动羽绒服。操作员将识别出集群确实已关闭,并将节点标记为无法访问
  • 如果您的集群具有动态数量的节点,那么您需要一些复杂的东西,如Lightbend Split Brain解析器
  • 如果集群是静态的,您可以使用仲裁策略来避免大脑分裂。您始终需要运行奇数个节点