Erlang 将容错性引入了Actor 模型,它使用的概念叫做监督(supervision)。监督的核心思想就是把对于失败的响应和可能引起失败的组件分隔开,并且把可能发生错误的组件通过层级结构来组织,以便管理。
1.监督的层级结构
Akka 使用Actor 层级结构来描述监督。当我们创建Actor 时,新建的Actor 都是作为另一个Actor 的子Actor,父Actor 负责监督子Actor。Actor 的路径结构就展示了它的层级结构,所以和文件系统中的文件夹有点像。
位于Actor 层级结构顶部的是路径为/的根Actor。然后是路径为/user 的守护Actor。
使用actorSystem.actorOf() 函数创建的所有Actor 都是守护Actor 的子Actor(/user/yourActor)。
如果在一个Actor 内部创建另一个Actor,那么可以通过调用context().actorOf 使得
新建的Actor 成为原Actor 的子Actor。这个新建的Actor 就成为了Actor 树结构中的下一个叶节点(/user/yourActor/newChild)。
根Actor 下面还有其他Actor 层级结构。系统操作相关的Actor 在路径为/system 的
系统守护Actor 下面。路径/temp 下面还包含了一个临时的Actor 层级结构,用于完成Future 的临时Actor 就处于这个子树中。我们并不需要对这些细节担心过多,这些基本上都是Akka 的内部实现,对于开发者是不可见的。
2.做法
继续(resume):Actor 继续处理下一条消息;
停止(stop):停止Actor,不再做任何操作;
重启(restart):新建一个Actor,代替原来的Actor;
向上反映(escalate):将异常信息传递给下一个监督者。
3.监督策略
Actor 运行过程中抛出异常:restart();
Actor 运行过程中发生错误:escalate();
Actor 初始化过程中发生异常:stop()。
在默认监督策略中还定义了另一种情况:ActorKilledException。如果Actor 被“杀”(kill)了,那么这个Actor 的监督者会接收到一个ActorKilledException,执行stop()会接收到该异常。
4.Actor的生命周期中会调用的几个方法
prestart():在构造函数之后调用。
postStop():在重启之前调用。
preRestart(reason, message):默认情况下会调用postStop()。
postRestart():默认情况下会调用preStart()。
5.终止或kill 一个Actor
有多种不同的方法可以用来停止一个Actor。下面任一方法都可以停止Actor:
调用ActorSystem.stop(actorRef);
调用ActorContext.stop(actorRef);
给Actor 发送一条PoisonPill 消息,会在Actor 完成消息处理后将其停止;
给Actor发送一条kill消息,会导致Actor抛出ActorKilledException异常。
6.生命周期监控和DeathWatch
监督机制描述了如何对子Actor 的状态进行响应。而Actor 也可以对其他任何Actor
进行监督。通过调用context.watch(actorRef)注册后,Actor 就能够监控另一个Actor 的
终止,而调用context.unwatch(actorRef)就可以取消监控注册。如果被监控的Actor 停止了,负责监控的Actor 就会收到一条Terminated(ActorRef)消息。
7.状态
我们可以使用几种不同的机制来改变Actor 的行为:
(1)基于Actor 状态的条件语句;
(2)热交换(Hotswap):become()和unbecome();
在Actor 的context()中,有两个方法:
become(PartialFunction behavior):这个方法将receive 块中定义的行为修改为一个新的PartialFunction。
unbecome():这个方法将Actor 的行为修改回默认行为。
(3)有限自动机
8.定义状态
Disconnected:离线,队列中没有任何消息;
Disconnected and Pending:离线,队列中包含消息;
Connected:在线,队列中没有消息;
Connected and Pending:在线,队列包含消息。
在Java 中,我们使用enum 来定义状态:
enum State{
DISCONNECTED,
CONNECTED,
CONNECTED_AND_PENDING,
}
9.定义状态容器
我们将保存一个请求列表作为状态容器。在接收到Flush 消息的时候会处理这个列表中的请求:
public class EventQueue extends LinkedList<Request> {}
(1)在FSM 中定义行为
首先,FSM 必需要混入一个Trait。
在Java 8 中,我们继承akka.actor.AbstractFSM。
public class BunchingAkkademyClient extends AbstractFSM<State,
RequestQueue>{
{//init block}
}
2)现在就可以在Actor 中使用FSM API 来定义不同状态的行为了。首先,调用startWith 方法来定义Actor 如何启动:
{
startWith(DISCONNECTED, null);
}
startWith(Disconnected, null) //scala needs no init block!