我想创建一个不会出现单点故障的系统。 我的印象是路由器是这样做的工具,但我不确定它是否像我期望的那样工作。 这是我的计划的切入点:
object Main extends App{
val system = ActorSystem("mySys", ConfigFactory.load("application"))
val router = system.actorOf(
ClusterRouterPool(RoundRobinPool(0), ClusterRouterPoolSettings(
totalInstances = 2, maxInstancesPerNode = 1,
allowLocalRoutees = false, useRole = Some("testActor"))).props(Props[TestActor]),
name = "testActors")
}
这是运行远程ActorSystem
的代码(因此路由器可以将TestActor
代码部署到远程节点):
object TestActor extends App{
val system = ActorSystem("mySys", ConfigFactory.load("application").getConfig("testactor1"))
case object PrintRouterPath
}
我运行了两次,一次使用testactor1
,一次使用testactor2
。
TestActor
代码:
class TestActor extends Actor with ActorLogging{
implicit val ExecutionContext = context.dispatcher
context.system.scheduler.schedule(10000 milliseconds, 30000 milliseconds,self, PrintRouterPath)
override def receive: Receive = {
case PrintRouterPath =>
log.info(s"router is on path ${context.parent}")
}
}
和application.conf
akka{
actor {
provider = "akka.cluster.ClusterActorRefProvider"
}
remote {
log-remote-lifecycle-events = off
netty.tcp {
hostname = "127.0.0.1"
port = 2552
}
}
cluster {
seed-nodes = [
"akka.tcp://mySys@127.0.0.1:2552"
"akka.tcp://mySys@127.0.0.1:2553"
"akka.tcp://mySys@127.0.0.1:2554"]
auto-down-unreachable-after = 20s
}
}
testactor1{
akka{
actor {
provider = "akka.cluster.ClusterActorRefProvider"
}
remote {
log-remote-lifecycle-events = off
netty.tcp {
hostname = "127.0.0.1"
port = 2554
}
}
cluster {
roles.1 = "testActor"
seed-nodes = [
"akka.tcp://mySys@127.0.0.1:2552"
"akka.tcp://mySys@127.0.0.1:2553"
"akka.tcp://mySys@127.0.0.1:2554"]
auto-down-unreachable-after = 20s
}
}
}
testactor2{
akka{
actor {
provider = "akka.cluster.ClusterActorRefProvider"
}
remote {
log-remote-lifecycle-events = off
netty.tcp {
hostname = "127.0.0.1"
port = 2553
}
}
cluster {
roles.1 = "testActor"
seed-nodes = [
"akka.tcp://mySys@127.0.0.1:2552"
"akka.tcp://mySys@127.0.0.1:2553"
"akka.tcp://mySys@127.0.0.1:2554"]
auto-down-unreachable-after = 20s
}
}
}
现在的问题是,当启动路由器的进程被终止时,运行代码TestActor
的actor没有收到任何消息(调度程序发送的消息),我原以为路由器将部署在集群中的另一个种子节点上,并且将恢复actor。这可能吗?或者是否有其他方法来实现此流程并且没有单点故障?
答案 0 :(得分:2)
我认为,通过仅在一个节点上部署router
,您将设置一个主从集群,其中主服务器根据定义是单点故障。
根据我的理解(查看docs),路由器可以是集群感知的,因为它可以在集群中的节点上部署(池模式)或查找(组模式)路由。路由器本身不会通过在集群中的其他位置生成来对故障作出反应。
我相信你有两个选择:
利用多个路由器使您的系统更具容错能力。路由器可以在路由器之间共享(组模式)或不共享(池模式)。
使用Cluster Singleton模式 - 允许主从配置,在发生故障时将自动重新生成主服务器。关于您的示例,请注意通过在每个节点中部署actor(ClusterSingletonManager
)来实现此行为。这个演员的目的是确定所选的大师是否需要重生并在哪里。对于像您设置的路由器那样的群集感知路由器,这些逻辑都不存在。
您可以在此Activator sample中找到多个群集设置的示例。
答案 1 :(得分:0)
我测试了两种方法,首先使用代码ClusterRouterPool
就像你说当启动路由器的进程被杀死时,TestActor没有收到更多的消息。
在阅读文档和测试时,如果您更改了application.conf
:
`auto-down-unreachable-after = 20s`
这个
`auto-down-unreachable-after = off`
TestActor继续接收消息,但在日志中会出现以下消息(我不知道如何将日志放在这里,抱歉):
[WARN] [01/30/2017 17:20:26.017] [mySys-akka.remote.default-remote-dispatcher-5] [akka.tcp://mySys@127.0.0.1:2554 /system/endpointManager/reliableEndpointWriter-akka.tcp%3A%2F%2FmySys%40127.0.0.1%3A2552-0]与远程系统[akka.tcp://mySys@127.0.0.1:2552]的关联失败,地址现在门限为[5000] ms。原因:[关联失败,[akka.tcp://mySys@127.0.0.1:2552]]引起:[连接被拒:/127.0.0.1:2552] [INFO] [01/30/2017 17:20:29.860] [mySys-akka.actor.default-dispatcher-4] [akka.tcp://mySys@127.0.0.1:2554 / remote / akka.tcp / mySys @ 127.0.0.1:2552/user/testActors/c1]路由器在路径上的Actor [akka.tcp://mySys@127.0.0.1:2552 / user / testActors#-1120251475] [WARN] [01/30/2017 17:20:32.016] [mySys-akka.remote.default-remote-dispatcher-5]
在重新启动MainApp的情况下,日志正常工作,没有警告或错误
MainApp日志:
[INFO] [01/30/2017 17:23:32.756] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster(akka:// mySys)]群集节点[akka.tcp://mySys@127.0.0.1:2552] - 欢迎来自[akka.tcp://mySys@127.0.0.1:2554]
TestActor日志:
INFO] [01/30/2017 17:23:21.958] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster(akka:// mySys)]群集节点[ akka.tcp://mySys@127.0.0.1:2554] - 现有成员的新版本[Member(地址= akka.tcp://mySys@127.0.0.1:2552,status = Up)]正在尝试加入。现有将从群集中删除,然后允许新成员加入。 [INFO] [01/30/2017 17:23:21.959] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster(akka:// mySys)]群集节点[akka.tcp:/ /mySys@127.0.0.1:2554] - 将无法访问的节点[akka.tcp://mySys@127.0.0.1:2552]标记为[Down] [INFO] [01/30/2017 17:23:22.454] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster(akka:// mySys)]群集节点[akka.tcp:/ /mySys@127.0.0.1:2554] - 领导者可以再次履行职责 [INFO] [01/30/2017 17:23:22.461] [mySys-akka.actor.default-dispatcher-2] [akka.cluster.Cluster(akka:// mySys)]群集节点[akka.tcp:/ /mySys@127.0.0.1:2554] - 领导者正在删除无法访问的节点[akka.tcp://mySys@127.0.0.1:2552] [INFO] [01/30/2017 17:23:32.728] [mySys-akka.actor.default-dispatcher-4] [akka.cluster.Cluster(akka:// mySys)]群集节点[akka.tcp:/ /mySys@127.0.0.1:2554] - 节点[akka.tcp://mySys@127.0.0.1:2552]正在加入,角色[] [INFO] [01/30/2017 17:23:33.457] [mySys-akka.actor.default-dispatcher-14] [akka.cluster.Cluster(akka:// mySys)]群集节点[akka.tcp:/ /mySys@127.0.0.1:2554] - 领导者正在将节点[akka.tcp://mySys@127.0.0.1:2552]移动到[Up] [INFO] [01/30/2017 17:23:37.925] [mySys-akka.actor.default-dispatcher-19] [akka.tcp://mySys@127.0.0.1:2554 / remote / akka.tcp / mySys @ 127.0.0.1:2552/user/testActors/c1]路由器在路径上的Actor [akka.tcp://mySys@127.0.0.1:2552 / user / testActors#-630150507]
另一种方法是使用ClusterRouterGroup
,因为路由在群集的节点之间共享
主要应用程序
object Main extends App {
val system = ActorSystem("mySys", ConfigFactory.load("application.conf"))
val routerGroup = system.actorOf(
ClusterRouterGroup(RoundRobinGroup(Nil), ClusterRouterGroupSettings(
totalInstances = 2, routeesPaths = List("/user/testActor"),
allowLocalRoutees = false, useRole = Some("testActor"))).props(),
name = "testActors")
}
您必须在每个远程节点中启动TestActor
object TestActor extends App{
val system = ActorSystem("mySys", ConfigFactory.load("application").getConfig("testactor1"))
system.actorOf(Props[TestActor],"testActor")
case object PrintRouterPath
}
http://doc.akka.io/docs/akka/2.4/scala/cluster-usage.html#Router_with_Group_of_Routees
应该在启动actor系统时尽早启动routee actor,因为路由器会在成员状态更改为“Up”后尝试使用它们。
我希望它可以帮到你