Akka-cluster 在 EC2/docker 上持有并继续存储有关成员资格的错误信息
Akka-cluster holds and keeps storing wrong info about membership on EC2/docker
环境:scala-2.11.x
、akka-2.5.9
EC2 上有两个主机:H1
和 H2
。
sbt-project 的树模块有:master
、client
和 worker
。
每个模块都实现 akka-cluster 节点,它订阅集群事件并记录它们。此外,每个节点每 1 分钟记录一次集群状态(用于调试)。以下端口用于集群节点:master: 2551
、worker: 3000
、client: 5000
项目可用 github
有关基础设施的更多详细信息:
模块可以在 H1
或 H2
中随机重新部署。
akka 集群有一个奇怪的行为。重新部署其中一个节点(例如 worker
)时。以下步骤说明了部署历史:
初始状态 - 当 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)
----------------
之后 worker
模块已在主机 H2
上重新部署
----[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
returns connection refused
。
但是为什么 akka-cluster 一直存储这个错误的信息?
此行为是有意为之,生产中的 Akka 集群应该 运行 没有自动关闭,以防止 split-brain 问题。
想象一个具有两个客户端(X 和 Y)的双节点(A 和 B)集群:
- 一开始一切正常,
Y
连接到 B
的请求可以转发到 Actor1
运行ning 在 A
for通过远程处理
- 然后,由于网络分区,
A
无法从 B
访问,B
可能会试图将 A
标记为关闭并重新启动 Actor1
本地。
客户端 Y
在 B
运行ning
上向 Actor1 运行 发送消息
网络分区另一端的客户端X
仍然连接到A
,并将向Actor1
[=48发送消息=]
这是一个 split-brain 问题:具有相同标识符的同一个 actor 运行ning 在具有两种不同状态的两个节点上。重建正确的 actor 状态非常困难或不可能。
为防止这种情况发生,您必须针对您的问题或用例选择合理的停机策略:
- 如果你负担得起,就用手动downing吧。操作员将识别出集群确实已关闭,并将节点标记为不可访问。
- 如果您的集群具有动态数量的节点,那么您需要一些复杂的东西,例如 Lightbend Split Brain Resolver
- 如果你的集群是静态的,你可以使用仲裁策略来避免脑裂。您总是需要 运行 奇数个节点。
环境:scala-2.11.x
、akka-2.5.9
EC2 上有两个主机:H1
和 H2
。
sbt-project 的树模块有:master
、client
和 worker
。
每个模块都实现 akka-cluster 节点,它订阅集群事件并记录它们。此外,每个节点每 1 分钟记录一次集群状态(用于调试)。以下端口用于集群节点:master: 2551
、worker: 3000
、client: 5000
项目可用 github
有关基础设施的更多详细信息:
模块可以在 H1
或 H2
中随机重新部署。
akka 集群有一个奇怪的行为。重新部署其中一个节点(例如 worker
)时。以下步骤说明了部署历史:
初始状态 - 当 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)
----------------
之后 worker
模块已在主机 H2
----[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
returns connection refused
。
但是为什么 akka-cluster 一直存储这个错误的信息?
此行为是有意为之,生产中的 Akka 集群应该 运行 没有自动关闭,以防止 split-brain 问题。
想象一个具有两个客户端(X 和 Y)的双节点(A 和 B)集群:
- 一开始一切正常,
Y
连接到B
的请求可以转发到Actor1
运行ning 在A
for通过远程处理 - 然后,由于网络分区,
A
无法从B
访问,B
可能会试图将A
标记为关闭并重新启动Actor1
本地。 客户端
Y
在B
运行ning 上向 Actor1 运行 发送消息
网络分区另一端的客户端
[=48发送消息=]X
仍然连接到A
,并将向Actor1
这是一个 split-brain 问题:具有相同标识符的同一个 actor 运行ning 在具有两种不同状态的两个节点上。重建正确的 actor 状态非常困难或不可能。
为防止这种情况发生,您必须针对您的问题或用例选择合理的停机策略:
- 如果你负担得起,就用手动downing吧。操作员将识别出集群确实已关闭,并将节点标记为不可访问。
- 如果您的集群具有动态数量的节点,那么您需要一些复杂的东西,例如 Lightbend Split Brain Resolver
- 如果你的集群是静态的,你可以使用仲裁策略来避免脑裂。您总是需要 运行 奇数个节点。