使用Akka Cluster Singleton实现集群单例

上篇文章主要讲了如何使用Akka做异步任务处理。最后还抛出一个问题。node

具体问题的描述就不在这篇文章赘述了,咱们仅简单回顾一下第一种解决方案:覆写persistenceId()时,加一个UUID,这样三台服务器上的Actor就不会再共享journal。虽然这个方案已经能够解决问题了,但并非最理想的。首先,如今的项目中只是用akka处理一些无状态的任务异步处理,可是未来确定要用akka做更多的事情。好比,缓存,DAO这些能够设计成有状态的,而如今actor重启时是不能replay消息消息历史的,因此这样不能最大限度发挥actor的优点。还有,个人目标是把全部的后端server构建为一个逻辑上的server,如今他们仍然是三个各自为营的独立server。所以我又继续做了一些调研,最终发现了Cluster Singleton。后端

文档上给出了Cluster Singleton的适用场景:缓存

  • 集群中的单点决策,或者协调服务器

  • 统一外部系统出口异步

  • 一主多从ide

  • 统一命名服务或路由逻辑工具

第二点正好就是咱们的场景。下边看一下如何使用Cluster Singleton。性能

  1. 添加依赖(我用的构建工具是Gradle)设计

compile("com.typesafe.akka:akka-cluster_2.11:${akkaVersion}")
compile("com.typesafe.akka:akka-cluster-tools_2.11:${akkaVersion}")
  1. 建立actor代理

actorSystem.actorOf(ClusterSingletonManager.props(
    SpringExtProvider.get(actorSystem).props("NotificationActor"),
    PoisonPill.getInstance(),
    ClusterSingletonManagerSettings.create(actorSystem).withRole("master")
), "notification-master");

notificationActor = actorSystem.actorOf(
    ClusterSingletonProxy.props(
        "/user/notification-master",
        ClusterSingletonProxySettings.create(actorSystem).withRole("master")),
    "notification-proxy");

建立actor比原来复杂了。首先要建立一个ClusterSingletomManager。ClusterSingletonManager也是一个Actor,它会在Cluster的每一个节点上都启动起来(或者集群拥有某些角色的节点)。ClusterSingletomManager.props要传入三个参数,第一个是须要建立Singleton实例的Actor配置;第二个是当Manager关闭时要给它管理的Actor发送什么消息;第三个,集群部署配置,即指定ClusterSingletomManager在哪些集群Node上启动。

接下来ClusterSingletonManager会选择一个最老的实例并在上面建立Actor单例。ClusterSingletonManager能够确保整个集群中至多有一个singleton的实例,言下之意,存在没有singleton实例的时刻。好比cluster node crash,原有的singleton实例丢失,这时须要从新选举新最老的ClusterSingletonManager,而后建立新的singleton实例。

访问Singleton Actor须要借助于ClusterSingletonProxy,ClusterSingletonProxy会把全部的消息forward给当前被代理的Actor实例。由于有可能某些时刻是没有singleton actor实例的,因此遇到这种状况ClusterSingletonProxy会先把消息缓存,当新的Actor单例建立以后,再把缓存的消息转发过去。

固然,Cluster Singleton也有它的问题,好比单点潜在的性能问题,并且singleton actor并非100%可用。但相比于第一种方案,显然这个要更接近个人指望。


write on 2017-1-10

相关文章
相关标签/搜索