共计 7563 个字符,预计需要花费 19 分钟才能阅读完成。
Split Brain Resolver
在操作 Akka 集群时,必须思考如何解决网络分区 (又称裂脑场景) 和机器解体(包含 JVM 和硬件故障)。如果您应用集群单例或集群分片,尤其是与 Akka Persistence 一起应用,这对于正确的行为至关重要。
“ 裂脑解析器 ” 视频是一个很好的终点:学习为什么应用正确的 downing 提供程序很重要,以及裂脑解析器如何工作的。
模块信息
Akka Split Brain Resolver 是 akka-cluster 的一部分,您可能曾经蕴含了该依赖项。否则,在您的我的项目中增加以下依赖项:
启用裂脑解析器
您须要通过在 ActorSystem(application.conf)的配置中将其配置为 Downing 提供程序来启用 Split Brain Resolver:
您还应该思考其余可用的降落策略。
问题
对于观察者而言,分布式系统中的一个根本问题是,网络分区 (裂脑场景) 和机器解体是无奈辨别的,一个节点能够察看到另一个节点存在问题,然而它无奈确定它是否已解体并且永远不会再次可用,或者因为网络问题可能会或可能不会在一段时间后再次治愈。暂时性和永久性故障是无奈辨别的,因为必须在无限的工夫内做出决定,并且总是存在持续时间长于决策工夫限度的暂时性故障。
第三类问题是过程是否没有响应,例如因为过载,CPU 饥饿或长时间的垃圾回收暂停。这与网络分区和解体也没有区别。咱们惟一须要做出决定的信号是 ” 在给定的工夫内没有对心跳的回复 ”,这意味着造成提早或心跳失落的景象是彼此无奈辨别的,必须以雷同的形式进行解决。
产生解体时,咱们心愿立刻从集群成员关系中删除受影响的节点。当存在网络分区或无响应的过程时,咱们心愿期待一会儿,心愿它是一个临时的问题,该问题将再次失去解决,然而在某些时候,咱们必须放弃并持续应用网络分区一侧的节点,并敞开另一端的节点。此外,某些性能在分区期间并不齐全可用,因而,如果分区破费的工夫太长,则该分区是否瞬态不重要。这两个指标互相抵触,并且咱们能够在删除解体节点的工夫,与对瞬态网络分区进行过早的操作之间进行衡量。
鉴于网络分区不同侧的节点无奈通信,这是一个很难解决的问题。咱们必须确保单方能够本人做出决定,并且就哪一部分将持续运行以及哪一部分将自行敞开做出雷同的决定。
另一种问题很难看清 ” 正确 ” 的图景,即某些节点未齐全连贯且无奈间接互相通信,但能够通过其余节点在它们之间流传信息。
Akka 集群具备故障检测器,该故障检测器会留神到网络分区和机器解体(但无奈辨别两者)。它应用定期的心跳音讯来查看其余节点是否可用并且运行状况良好。故障检测器的这些察看后果称为节点不可达,如果故障检测器察看到它能够再次通信,则该节点可能再次变为可达。
故障检测器自身不足以在所有状况下做出正确的决定。简略的办法是在超时后从集群成员中删除无法访问的节点。这对于解体和短暂的瞬态网络分区十分有用,但不适用于较长的网络分区。网络分区的两侧将看到另一端无法访问,不久后将其从其集群成员中删除。因为这种状况在单方都产生,因而后果是创立了两个独自的断开连接的集群。此办法由 OSS 版本的 Akka Cluster 中的启用 (默认状况下为禁用) 性能提供。
如果将基于超时的主动敞开性能与 ” 集群单例 ” 或 ” 集群分片 ” 联合应用,则意味着将运行两个具备雷同标识符的单例实例或两个分片实体。一个会在运行:每个集群一个。例如,当与 Akka Persistence 一起应用时,可能导致具备雷同 persistenceId 的持久性 actor 的两个实例正在运行并同时写入同一持久性事件流,这在重播这些事件时将具备致命的结果。
Akka Cluster 中的默认设置是不主动删除无法访问的节点,建议您由操作员或内部监视系统来决定要做什么。这是一个无效的解决方案,然而如果您因为其余起因而没有此人员或内部零碎,则不是很不便。
如果根本无法敞开不可达节点,则它们仍将成为集群成员的一部分。这意味着 ” 集群单例 ” 和 ” 集群分片 ” 将不会故障转移到另一个节点。当存在无法访问的节点时,不会把退出集群的新节点晋升为齐全有价值的成员(状态为 Up)。同样,在解决所有无法访问的节点之前,不会删除来到成员。换句话说,将无法访问的成员保留有限工夫是不心愿的。
有了问题域的介绍,就该看看提供的用于解决网络分区,无响应节点和解体节点的策略了。
策略
默认状况下,将应用 ” 保留少数 ” 策略,因为该策略在大多数零碎上都实用。然而,思考其余可用策略并抉择适宜您零碎特色的策略会很麻烦。例如,在 Kubernetes 环境中,租赁策略可能是一个不错的抉择。
每个策略都有一个失败场景,在该场景中会做出 ” 谬误 ” 的决定。本节介绍何时应用什么策略和准则。
当存在不确定性时,它将抉择敞开比必要数量更多的节点,甚至敞开所有节点。因而,应该始终将 Split Brain Resolver 与一种机制联合应用,以主动启动已敞开的节点,并将它们退出现有集群或再次造成新集群。
您能够应用配置属性 akka.cluster.split-brain-resolver.active-strategy 启用策略。
稳固之后
在集群成员关系和无关不可达节点的信息在特定时间段内保持稳定之前,所有策略均处于非活动状态。存在网络分区的状况下间断增加更多节点不会影响此超时,因为在存在无法访问的节点时,这些节点的状态不会更改为 Up。策略逻辑中不计入连贯节点。
将 akka.cluster.split-brain-resolver.stable-after 设置为较短的持续时间,以更快地删除解体的节点,但这样做的代价是对过渡网络分区采取过早的解决措施,否则可能会恢复原状。请勿将其设置为比集群中的成员流传工夫短的持续时间,后者取决于集群的大小。不同集群大小的倡议最小持续时间:
不同的策略可能具备以下形容的其余设置。
留神
在所有节点上应用雷同的配置很重要。
决定敞开本身的决裂一侧,应用 cluster down 命令启动对集群成员的移除。将其分布在可达到的节点之间后,它将从集群成员中删除。
从集群中删除节点后,最好终止 ActorSystem 并退出 JVM。
这是由 Coordinated Shutdown 解决的,然而要退出 JVM,建议您启用以下操作:
留神
一些旧容器可能会阻止对 System.exit(..)的调用,您可能必须找到其余办法来敞开应用程序。例如,在 Spring/Tomcat 设置之上运行 Akka 时,能够将对 System.exit(..)的调用替换为对 Spring 的 ApplicationContext.close()办法的调用(或对 Tomcat Manager 的 API 的 HTTP 调用勾销部署该应用程序)。
放弃少数
如果基于最新已知的成员信息,以后节点占大多数,则 keep-majority 策略将敞开不可达节点。否则沿着可达到的节点,即本人的局部。如果局部大小相等,则将保留蕴含地址最低的节点的局部。
当集群中的节点数动静更改并且因而无奈应用动态仲裁时,此策略是一个不错的抉择。
此策略还解决在产生网络分区的同时产生成员身份更改,可能产生的边缘状况。例如,两个成员的状态在一侧更改为 ” 启动 ”,然而在断开连接之前该信息不会流传到另一侧。而后,一侧会看到另外两个节点,并且单方可能会认为本人领有少数。如果将退出节点的另一侧更改为 ” Up”,它将检测到这种状况并做出平安的决定来敞开该侧上所有多数节点。请留神,这样做的毛病是,如果未将连贯节点更改为 Up 并在另一侧成为少数,则每个局部都将自行敞开,从而终止整个集群。
请留神,如果有两个以上的分区,但大多数分区都不占多数,则每个局部都会自行敞开,从而终止整个集群。
如果有一半以上的节点同时解体,则其余正在运行的节点将自行敞开,因为它们认为本人不是少数节点,从而终止了整个集群。
该决定能够基于具备配置角色的节点,而不是集群中的所有节点。当某些类型的节点比其余类型更有价值时,这可能会很有用。例如,您可能有一些负责持久性数据的节点和一些具备无状态工作程序服务的节点。而后,即便意味着要敞开更多的工作程序节点,保留尽可能多的持久数据节点可能更为重要。
配置
动态仲裁
如果残余节点数大于或等于配置的仲裁大小,则名为动态仲裁的策略将敞开不可达节点。否则,它将敞开可拜访的节点,即它将敞开分区的另一侧。换句话说,仲裁大小定义了集群必须必须运行的最小节点数。
当集群中有固定数量的节点,或者能够定义具备特定角色的固定数量的节点时,此策略是一个不错的抉择。
例如,在 9 个节点的集群中,您将仲裁大小配置为 5。如果网络拆分为 4 个和 5 个节点,则 5 个节点的一侧将持续存在,而其余 4 个节点将被敞开。尔后,在 5 节点集群中,无奈解决更多故障,因为残余集群大小将小于 5。在该 5 节点集群中产生另一个故障的状况下,所有节点都将被敞开。
因而,在删除旧节点后退出新节点十分重要。
这样做的另一个后果是,如果启动集群时存在无法访问的节点,则在达到此限度之前,集群可能会立刻敞开本身。如果您在大概雷同的工夫启动所有节点,或在 leader 将 ”Joining” 成员的成员状态更改为 ”UP” 之前,应用 akka.cluster.min-nr-of-members 定义所需的成员数,则这不是问题。您能够在做出 downing 决策后,应用 stable-after 设置,调节超时工夫。
增加到集群中的成员数量不应超过 quorum-size*2-1。如果违反此倡议,则会记录一条正告。如果在须要 SBR 决策时仍保留超出的集群大小,则它将敞开所有节点,因为可能会导致单方彼此中断从而造成两个独自的集群的危险。
对于滚动更新,最好通过协调关机 (SIGTERM) 失常退出集群。为了胜利来到,将不应用 SBR(no downing),然而如果在滚动更新进行的同时存在无法访问性问题,则能够做出 SBR 决定。为防止滚动更新期间不超过成员总数限度,倡议在应用动态仲裁时来到并齐全删除一个节点,而后再增加新节点。
如果将集群分为 3 个 (或更多) 局部,则每个局部都小于配置的仲裁大小,这将导致本身解体并可能敞开整个集群。
如果同时呈现的节点数量多于配置的仲裁大小解体,则其余正在运行的节点将自行敞开,因为它们认为本人不在少数节点中,从而终止了整个集群。
该决定能够基于具备配置角色的节点,而不是集群中的所有节点。当某些类型的节点比其余类型更有价值时,这可能会很有用。例如,您可能有一些负责持久性数据的节点和一些具备无状态工作程序服务的节点。而后,即便意味着要敞开更多的工作程序节点,保留尽可能多的持久数据节点可能更为重要。
角色还有另一个用处。把集群中的几个 (例如 7 个) 稳固节点定义角色,并在动态仲裁配置中应用该角色,您将可能在没有该角色的状况下动静增加和删除其余节点,并且在网络分区的状况,依然能够很好地决定保留哪些节点以及敞开哪些节点。与放弃少数状态 (如下所述) 相比,此办法的劣势在于您无需承当将集群分成两个独自的集群的危险,即脑裂 *。您依然必须恪守以下规定:不要应用此角色启动太多节点。如上所述,如果在集群中没有足够的角色的节点时产生故障,它也有敞开所有节点的危险。
配置:
放弃最旧
keep-oldest 的策略将删除不蕴含最旧成员的局部。最旧的成员很乏味,因为流动的 Cluster Singleton 实例在最旧的成员上运行。
如果将 down-if-alone 配置为 on,则此规定有一个例外。而后,如果最旧的节点已与所有其余节点进行了分区,则最旧的节点将自行敞开并放弃所有其余节点运行。当集群中残余惟一的节点时,该策略将不会敞开该节点。
请留神,如果最旧的节点解体,当 down-if-alone 是 on,则其余节点将其从集群中删除,否则,如果最旧的节点解体,它们将自行敞开,即敞开整个集群以及最旧的节点。
如果您应用集群单例,并且不想敞开运行单例实例的节点,则能够应用此策略。如果最旧的节点解体,则新的单例实例将在下一个最旧的节点上启动。毛病是该策略可能在大型集群中仅保留几个节点。例如,如果最早的一部分蕴含 2 个节点,而另一部分蕴含 98 个节点,则它将保留 2 个节点并敞开 98 个节点。
此策略还解决边缘状况,在产生网络分区的同时产生成员身份更改。例如,最早的成员的状态更改为一侧退出,但在断开连接之前该信息不会流传到另一侧。它将检测到这种状况,并做出平安的决定,将最旧的那一侧视为 ” 来到 ”。请留神,这样做的毛病是,如果最旧的是 ” 来到 ” 并且未更改为 ” 退出 ”,则每个局部都会自行敞开,从而终止整个集群。
该决定能够基于具备已配置角色的节点而不是集群中的所有节点,即,应用具备该角色的节点中最旧的成员(单个)。
配置
全副 down
down-all 策略将敞开所有节点。
如果网络环境高度不稳固且无奈齐全察看到无法访问的察看后果,并且包含频繁产生的间接连贯节点,则此策略能够是一种平安的抉择。因为不稳固,在分区的不同侧上减少不同信息的危险,因而其余策略可能会导致决策抵触。在这种环境中,最好敞开所有节点并启动新的新集群。
敞开所有节点意味着在节点重新启动并造成新集群之前,零碎将齐全不可用。不倡议对大型集群 (> 10 个节点) 应用此策略,因为任何较小的问题都会敞开所有节点,并且在较大的集群中更可能产生这种状况,因为有更多的节点可能会产生故障。
另请参阅在不稳固且间接连贯的节点时全副敞开。
租约
“ 少数租约 ” 的策略正在应用分布式租约 (锁定) 来决定容许哪些节点存活。只有一个 SBR 实例能够获取租约,以决定保留该租约。另一方将无奈取得租约,因而将自行吊销。
尽最大的致力保留具备最多节点的一方,即少数一方。这是通过在尝试取得少数派一方的租约之前减少提早来实现的。
以后有一种受反对的租约实现,由 Kubernetes 中的自定义资源定义 (CRD) 反对。Kubernetes 租赁文档中对此进行了形容。
该策略十分平安,因为协调是由内部仲裁员增加的。与其余策略相比,须要进行衡量的是,它须要用于施行租赁的其余根底构造,并且将决策的可用性升高到反对租赁 store 的零碎的可用性。
与其余策略相似,请勿提早决策,这一点很重要,因为无奈获取租约的节点必须决定自行敞开,如果不稳固,请参阅全副敞开。
在某些状况下,当须要所有 SBR 实例做出决定时,例如,因为它位于网络分区的另一侧,因而所有节点都将被敞开。
组态:
另请参阅 Kubernetes 租赁中的配置和其余依赖关系
间接连贯的节点
在产生故障的网络中,有时会发现某些节点无奈通过某些网络链接拜访节点,但它们仍通过其余节点间接连贯,即不是洁净的网络分区(或节点解体)。
当检测到这种状况时,” 裂脑解析器 ” 将放弃齐全连贯的节点, 并使所有间接连贯的节点放弃 down 状态。
如果存在间接连贯的节点和洁净的网络分区的组合,则它将上述决策与一般决策联合起来,例如在排除可疑故障检测察看后果之后,放弃少数。
不稳固时全副 down
当故障检测器的可达性观测值发生变化时,SBR 决策将推延直到 stable-after 工夫内没有变动。如果继续的工夫过长,则可能表明零碎 / 网络不稳固,并且可能导致网络分区的各个方面的决策提早或抵触。
作为该状况的预防措施,如果在第一个不可拜访事件之后的 table-after + down-all-when-unstable 没有做出决定,则所有节点都将敞开。如果所有无奈达到的中央都已被治愈,downed 或去除,或者在 stable-after * 2 内没有变动,则重置测量。
默认状况下,所有策略均启用此性能,默认状况下,持续时间推导为 stable-after 的 3 /4。
上面的属性能够定义为 stable-after 后能够承受持续更改的持续时间,也能够将其设置为 off 以禁用此性能。conf
正告
倡议放弃所有不稳固状态均放弃启用状态,并且不要将其设置为比之后稳固工夫 (向下移除余量) 更长的持续时间,因为这可能会导致本应升高的方面的决策提早,例如在洁净的网络分区的状况下,那一侧的继续不稳固应该敞开。这可能导致成员从一侧移开,但仍在另一侧运行。
多个数据中心
Akka Cluster 反对多个数据中心,其中集群成员资格由每个数据中心别离治理,并且独立于不同数据中心的网络分区。Split Brain Resolver 正在采纳该策略,并且不会计算另一个数据中心中的节点或 down 的节点。
当跨数据中心的网络分区时,典型的解决方案是期待分区恢复正常,即不执行任何操作。其余决定应由内部监控工具或人工操作员执行。
集群单例和集群分片
集群单例和集群分片的目标是在任何工夫点最多运行给定 actor 的一个实例。当敞开此类实例时,应该在集群中的其余地位启动一个新实例。重要的是,在进行旧实例之前,不要启动新实例。当单例或分片实例是持久性实例时,这尤其重要,因为持久性 actor 实例的日志事件必须只有一个流动 writer。
因为网络分区不同侧的策略无奈互相通信,并且它们可能在稍有不同的工夫点做出决策,因而必须有基于工夫的余量,以确保在进行旧实例之前不启动新实例。
您心愿将其配置为较短的工夫以进行疾速故障转移,然而这会减少同时运行多个单例 / 分片实例的危险,并且可能须要破费不同的工夫来执行决策(down/ 移除)。默认状况下,持续时间与 stable-after 属性雷同(请参阅上文稳固)。倡议将此值放弃不变,但也能够应用 akka.cluster.down-removal-margin 属性独自笼罩它。
设置此 after-after/akka.cluster.down-removal-margin 的另一个问题是解决 JVM 暂停,例如垃圾收集。当节点无响应时,不晓得它是因为暂停,过载,解体还是网络分区引起的。如果暂停的持续时间长于 stable-after*2,则 SBR 须要工夫来使节点 down,并让单例和分片在其余节点上启动。当节点勾销暂停时,将有很短的工夫能力看到其本身呈现故障,此时单例对象和分片 actor 仍在运行。因而,重要的是要理解您的应用程序可能产生的最大暂停工夫,并确保它小于 stable-margin。
如果抉择为 down-removal-margin 设置一个独自的值,则倡议的不同集群大小的最小持续时间为:
预期的故障转移工夫
如您所见,有几个配置的超时会减少总故障转移提早。应用默认配置,这些是:
- 故障检测 5 秒
- stable-after 20
- down-removal-margin(默认与 stable-after 雷同)20 秒
总体而言,应用默认配置,您能够预期单例或分片实例的故障转移工夫约为 45 秒。默认配置的大小为 100 个节点的集群的大小。如果您有大概 10 个节点,则能够将 stable-after 缩小到大概 10 秒,从而导致预期的故障转移工夫大概为 25 秒。