Akka Cluster - Восстановление данных с разбившегося актера

Предположим, у меня есть мастер с 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, я ожидаю резервного механизма, который позволит системе (я полагаю, главному) узнать об этом сбое, а затем перераспределить потеряно work для других ведомых устройств.

Я понял принцип надзора в Akka, который позволяет мастеру получать уведомления, когда дочерний актор недоступен, но как я могу вернуть конкретный экземпляр work, который актор должен был перераспределить?

Поскольку я начал использовать Akka совсем недавно, мой подход, возможно, не адаптирован к лучшим практикам, и я должен решить эту ситуацию по-другому?

Спасибо !


person Jämes    schedule 15.08.2018    source источник


Ответы (3)


Теперь этот подход не будет работать в каждом сценарии, но как насчет сохранения работы дочернего актера в файловой системе. Вы можете создать идентификатор для каждого дочернего элемента и сохранить работу в файле на основе пары key -> value, где идентификатор дочернего актера — это ключ, а значение — незавершенная работа.

Теперь, какие данные должны быть сохранены, это вы должны решить, но это один из самых простых подходов, который вы можете попробовать.

Надеюсь это поможет!

person zenwraight    schedule 16.08.2018

Похоже, вам нужно 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)
      }
    }
  }
}
person Levi Ramsey    schedule 18.08.2018

Если вы хотите убедиться, что мастер знает об уходе рабочих, вы можете watch их watch (см. документацию https://doc.akka.io/docs/akka/current/actors.html#lifecycle-monitoring-aka-deathwatch ). Если вы отслеживаете, какую рабочую нагрузку вы назначили какому работнику, который еще не завершен, вы можете реализовать повторную отправку. Однако вы, вероятно, должны рассмотреть случай, когда главная система или ее акторная система также исчезнет, ​​и как восстановиться, если это произойдет.

Образец распределенных рабочих процессов Akka охватывает именно это, поэтому он может стать хорошим источником вдохновения: https://developer.lightbend.com/guides/akka-distributed-workers-scala/

person johanandren    schedule 27.08.2018