Akka Cluster Singleton

Akka集群单例

对于某些使用情况,方便、有时也是强制性的,以确保恰好只有一个特定类型的actor在群集某处运行。

例如:

  • 针对集群范围内某些统一决策的单一责任点,或协调集群系统中的行为。
  • 指向外部系统的单一入口。
  • 单个管理者,多个工作者。
  • 统一命名服务或路由逻辑

使用单例不应该是程序设计的首选。它有几个缺点,例如单点瓶颈。单点故障也是一个相关的问题,但是在某些情况下,这个功能会通过确保最终启动另一个单例实例来处理这一点。

集群单例模式由akka.cluster.singleton.ClusterSingletonManager实现。它在所有集群节点或标有特定角色的一组节点之间管理一个单例Actor实例。 ClusterSingletonManager是一个Actor,应该在集群中的所有节点或具有指定角色的所有节点上启动。实际的单例Actor由最早节点上的ClusterSingletonManager启动,通过ClusterSingletonManager提供的Props创建一个子Actor。在任何时间点,ClusterSingletonManager确保至多只有一个单例实例运行。

单例Actor总是在具有指定角色的最老的集群成员身上运行。最老的成员由akka.cluster.Member#isOlderThan决定。从群集中删除该成员时,这可能会发生更改。请注意,在移交过程中有很短的一段时间里,单例是不活跃的。

由于JVM崩溃,硬停机或网络故障等原因,集群故障检测器会注意到最老的节点变得无法访问。然后一个新的最老的节点将接管,并创建一个新的单例Actor。对于这些故障情况,将不会有优雅的交接,但是应通过一切合理的手段避免集群中存在一个以上的单例Actor。某些极端情况应当通过超时时间来解决。

​ 可以使用akka.cluster.singleton.ClusterSingletonProxy访问单例Actor,它会将所有消息路由到单例的当前实例。ClusterSingletonProxy将跟踪集群中最老的节点,并通过actorSelection向单例发送akka.actor.Identify消息并等待它的回复,以此来解析单例的ActorRef。如果单例在某个时间(可配置)内没有回复,则会周期性执行。鉴于实现,可能存在ActorRef不可用的时间段,例如当节点正在离开集群时。 在这些情况下,ClusterSingletonProxy将缓冲发送给单例的消息,在单例最终可用时再传递消息。如果缓冲区已满,当再通过ClusterSingletonProxy发送新消息时,ClusterSingletonProxy将丢弃旧消息。缓冲区的大小是可配置的,配置为0时,缓冲区被禁用。

​ 值得注意的是,由于这些Actor的分布性,消息总是会丢失的。一如以往,在单例(确认)和客户端Actor(重试)中应该实现额外的逻辑,以确保消息至少一次交付。

​ 单例实例不会运行在状态为WeaklyUp的成员上。

需要注意的潜在问题

​ 这种模式起初似乎是非常诱人的,但它有几个缺点,其中一些如下:

  • 集群单例可能很快成为性能瓶颈。
  • 不能指望集群单例是永远可用的。例如,当单例所运行的节点处于死亡状态时,需要花费几秒钟的时间才能注意到单例被移植到了另一个节点,。
  • 如果网络分区出现在使用Automatic Downing的群集中(参见 Auto Downing文档),可能会发生这样的情况:孤立群集各自决定启动自己的单例,这意味着可能有多个单例存在于系统中,且集群无法找到他们(由于分区)。​特别是最后一点是应该注意的地方。一般来说,当使用Cluster Singleton模式时,应该自己负责downing节点,而不是依赖基于时序的自动关闭功能。

警告:

​ 不要将Cluster Singleton与自动Automatic Downing一起使用,因为它允许集群分成两个独立的集群,这反过来将导致多个Singleton启动,每个独立的集群中会有一个!

示例

​ 假设我们需要一个到外部系统的单独入口。从JMS队列接收消息的Actor,严格要求必须只有一个JMS消费者存在,才能确保消息按顺序处理。这可能不是设计想要的东西,但是与外部系统集成时的典型的现实场景。

在解释如何创建一个集群单例actor之前,让我们先定义一个单例使用的消息类和对应的工厂方法。

在集群中的每个节点上,您需要启动ClusterSingletonManager,并提供单例actor(本例中为JMS队列使用者)的Props。

在这里,我们将单例限制为标有“worker”角色的节点。但是所有节点,不论什么角色,都可以不指定withRole来使用单例。

我们使用特定于应用程序的终止消息(即TestSingletonMessages.end()消息)能够在实际停止单例之前关闭资源。 请注意,PoisonPill是一个完美的终止消息,如果你只是需要停止一个Actor。

​ 这里是单例actor在这个例子中处理terminateMessage的逻辑。

使用给定的名称,可以使用正确配置的proxy从群集中任一节点获取对单例的访问。

Distributed workers with Akka and Java!中提供了更全面的示例。

Dependencies

​ 要使用Cluster Singleton,必须在项目中添加以下依赖项。

Configuration

​ 当使用ActorSystem参数创建时,ClusterSingletonManagerSettings将读取以下配置属性。也可以修改ClusterSingletonManagerSettings,或者从另一个配置部分创建如下相同的布局。ClusterSingletonManagerSettings是ClusterSingletonManager.props工厂方法的参数,即每个单例可以根据需要配置不同的设置。

​ 当使用ActorSystem参数创建时,ClusterSingletonProxySettings将读取以下配置属性。也可以修改ClusterSingletonProxySettings,或者从另一个配置部分创建如下相同的布局。ClusterSingletonProxySettings是ClusterSingletonProxy.props工厂方法的参数,即每个单例代理可以根据需要配置不同的设置。

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

发表评论

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