【问题标题】:Akka Cluster - Recover data from a crashed actorAkka Cluster - 从崩溃的 actor 中恢复数据
【发布时间】:2018-08-15 19:25:44
【问题描述】:

假设我有一个有 n 个从属的主控,其中从属位于其他计算机上。

男主角长得像

class MasterActor extends Actor {

  val router: ActorRef = // ... initialized router to contact the slaves

  override def receive: Receive = {
    case work: DoWork => router ! work
  }
}

虽然我的奴隶看起来像

class SlaveActor extends Actor {

  override def receive: Receive = {
    case work: DoWork => // Some logic that takes a couple of seconds
  }
}

如果托管一些从属服务器的机器崩溃,或者应用程序在处理一些work 时已停止,我希望有一种后备机制使系统(我想是主服务器)能够意识到这一点失败,然后将 lost work 重新分配给其他从站。

我已经理解了 Akka 中的监督原理,当子 actor 无法访问时,master 可以得到通知,但是我怎样才能取回 actor 必须重新分配的 work 的具体实例呢?

由于我最近开始使用 Akka,我的方法可能不适合最佳实践,我应该以其他方式解决这种情况吗?

谢谢!

【问题讨论】:

    标签: scala akka akka-cluster


    【解决方案1】:

    现在这种方法并不适用于所有场景,但是如何将子角色的工作存储到文件系统中。您可以创建为每个孩子提供一个 ID,并将工作保存在基于 key -> value 对的文件中,其中孩子演员 ID 是键,值是正在进行的工作。

    现在,您必须决定要保存哪些数据,但这是您可以尝试的最简单的方法之一。

    希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      听起来你想要的是Akka Persistence。主要的模型是事件溯源

      粗略的描述是在收到DoWork 时保留一个事件,并在完成工作时保留第二个事件。在恢复时,状态是一个未完成的工作列表(如果你得到正确的协议,最多只能是一项工作),大致如下:

      case class DidWork(dw: DoWork)
      
      class SlaveActor extends PersistentActor {
        val persistenceId: String = ???
        var workToDo: List[DoWork] = Nil
      
        val receiveRecover: Receive = {
          case dw: DoWork => workToDo = dw :: workToDo
          case DidWork(dw: DoWork) => workToDo = workToDo.filter(_ != dw)
          case SnapshotOffer(_, snapshot: List[DoWork]) => workToDo = snapshot
        }
      
        val snapshotInterval = ???
      
        val receiveCommand: Receive = {
          case dw: DoWork =>
            persist(dw) { event =>
              workToDo = dw :: workToDo
              context.system.eventStream.publish(event)
              if (lastSequenceNr % snapshotInterval == 0 && lastSequenceNr != 0)
                saveSnapshot(workToDo)
      
              doWork
            }
        }
      
        private[this] def doWork: Unit = {
          workToDo.reverse.foreach { dw: DoWork =>
            // do the work
            persist(DidWork(dw)) { event =>
              workToDo = workToDo.tail
              context.system.eventStream.publish(event)
              if (lastSequenceNr % snapshotInterval == 0 && lastSequenceNr != 0)
                saveSnapshot(workToDo)
            }
          }
        }
      }
      

      【讨论】:

        【解决方案3】:

        如果你想确保主人知道工人离开你可以watch他们(见文档https://doc.akka.io/docs/akka/current/actors.html#lifecycle-monitoring-aka-deathwatch)。如果您跟踪已分配给哪个工作人员的工作量,尚未完成,您可以实施重新发送。但是,您可能必须考虑 master 或它的 actor 系统也消失的情况,以及如果发生这种情况如何恢复。

        Akka 分布式工作人员示例正好涵盖了这一点,因此它可能是一个很好的灵感来源:https://developer.lightbend.com/guides/akka-distributed-workers-scala/

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-28
          • 1970-01-01
          • 2014-01-18
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多