Akka 在容错方面有如下特点:
- 分区容错(local & remote),错误隔离
- Actors 基于策略进行监督和恢复
- 在错误解决前,失效的Actor 可被挂起,转由系统代收消息(Dead Letter),并在恢复时继续之前的消息处理
Akka 对于错误的观点值得称道:没有银弹,还是着眼于如何进行灾后重建吧 🙂
Let it crash
与传统应用将 业务逻辑和 try {} catch{}
错误处理 绞在一起不同,Akka 的容错恢复是独立于业务逻辑的:Actors专注于自己的消息处理逻辑,而错误处理和策略设定,则由层 级结构里,它的监督者(父级Actor结点)来操心。
监督者(Supervisor)并不去catch子结点的错误,而是仅决策子结点该如何恢复:
恢复策略
在一个策略中,应对子结点错误,我们有四个选项进行响应:
- 重启:actor将被ActorSystem用Props重新创建,新的actor实例在重启完成后,会继续处理出错前的消息——Akka中各actor进行通信是基于引用(ActorRef,由ActorSystem维护),所以在重启后它会自动接收到未处理的消息
- 继续:忽略错误
- 终止:actor下线,不再继续处理消息
- 提升:监督者不知道怎么处理错误,向上级抛(如果是顶级结点,系统崩溃
系统内置了两种策略:
- defaultStrategy:默认的策略响应将会应用到所有子结点上
- stoppingStrategy:出错的结点将会被终止
我们也可以自定义结点的策略:OneForOneStrategy 是仅响应出错结点的策略,AllForOneStrategy 策略则是响应影响所有的子结点。
实例
在一个Actor系统中,Supervisor收到spawn
消息就创建Worker子结点,当这些Worker遇到不同的错误时,Supervisor 将使用一对一策略进行不同的响应:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import scala.concurrent.duration._ import akka.actor.{Actor, ActorLogging, ActorSystem, OneForOneStrategy, Props} import akka.actor.SupervisorStrategy._ class Supervisor extends Actor with ActorLogging { override def receive: Receive = { case "spawn" => context.actorOf(Props[Worker]) } override val supervisorStrategy = OneForOneStrategy(maxNrOfRetries = 10, withinTimeRange = 30 seconds) { case _: ArithmeticException => Resume case _: NullPointerException => Restart case _: IllegalArgumentException => Stop case _: Exception => Escalate } } class Worker extends Actor with ActorLogging { override def receive: Receive = ??? } object StrategyApp extends App { implicit val system = ActorSystem("actor-system") import system.dispatcher system.actorOf(Props[Supervisor], "supervisor") } |
打赏作者
您的支持将激励我继续创作!