Akka 【四】 Supervision and Monitoring
来源:互联网 发布:和大学老师啪啪知乎 编辑:程序博客网 时间:2024/05/16 12:20
什么是Supervision
在之前介绍Actor Model的文章中提到了,上级Actor对于它的下级Actor有监管作用:因为下级Actor的任务是上级Actor分配的,因此当下级Actor出错的时候,上级Actor必须做出回应。当一个Actor监测到异常的发生,它会挂起自己和它的所有下级Actor(所谓的挂起应该就是指不再执行任何任务),并且发送消息到它的监督者(也就是它的上级)表明自己出现了异常。监督者对错误做出相应的处理。
Supervision策略
监督者面对其下属的失败,有不同的策略。不过大致可以分为已下的四类:
1)恢复下级Actor,并且保持下级Actor的内部状态
2)重新启动下级Actor,并且清除下级Actor的内部状态
3)永久的停止下级Actor
4)将错误逐层上传,从而暂停自己(有点像java中的throw exception)
其中需要知道的是,Akka中的每一个Actor都在监督树中,他们既可以扮演监督者的角色,也可以扮演被监督者的角色。上级Actor的状态直接影响着下级Actor的状态,因此对上面的前三条策略可以做如下补充(诠释)
1)当恢复某个Actor的时候同时也要恢复它的所有下级Actor
2)重新启动某个Actor的时候也要重启它所有的下级Actor
3)停止某个Actor的时候也需要停止它所有的下级Actor。
Actor的preRestart方法的默认行为就是:在这个Actor重启前,先终止它所有的下级Actor,这个过程其实就是一个递归的过程。但是这个方法是可以重写的,因此在重写的时候需要谨慎。
UntypedActor中preRestart方法,
/** * User overridable callback: '''By default it disposes of all children and then calls `postStop()`.''' * <p/> * Is called on a crashed Actor right BEFORE it is restarted to allow clean * up of resources before Actor is terminated. */ @throws(classOf[Exception]) override def preRestart(reason: Throwable, message: Option[Any]): Unit = super.preRestart(reason, message)
继续调用父类的preRestart方法,也就是Actor中的方法。
Actor中的preRestart方法,/** * User overridable callback: '''By default it disposes of all children and then calls `postStop()`.''' * @param reason the Throwable that caused the restart to happen * @param message optionally the current message the actor processed when failing, if applicable * <p/> * Is called on a crashed Actor right BEFORE it is restarted to allow clean * up of resources before Actor is terminated. */ @throws(classOf[Exception]) // when changing this you MUST also change UntypedActorDocTest //#lifecycle-hooks def preRestart(reason: Throwable, message: Option[Any]): Unit = { context.children foreach { child ⇒ context.unwatch(child) context.stop(child) } postStop() }
可以较为清晰的看到,针对每一个child,都进行了stop操作。
Actor通过某个配置函数,来决定针对特定异常采用什么策略。
来看看默认的监督策略,
/** * When supervisorStrategy is not specified for an actor this * [[Decider]] is used by default in the supervisor strategy. * The child will be stopped when [[akka.actor.ActorInitializationException]], * [[akka.actor.ActorKilledException]], or [[akka.actor.DeathPactException]] is * thrown. It will be restarted for other `Exception` types. * The error is escalated if it's a `Throwable`, i.e. `Error`. */ final val defaultDecider: Decider = { case _: ActorInitializationException ⇒ Stop case _: ActorKilledException ⇒ Stop case _: DeathPactException ⇒ Stop case _: Exception ⇒ Restart } /** * When supervisorStrategy is not specified for an actor this * is used by default. OneForOneStrategy with decider defined in * [[#defaultDecider]]. */ final val defaultStrategy: SupervisorStrategy = { OneForOneStrategy()(defaultDecider) }
针对ActorInitializationException,ActorKilledException,DeathPactException采用Stop策略,而其他Exception采用Restart策略。
TOP-LEVEL监督者
一个Actor系统至少会在开始的时候创造3个Actor,如下面所示,
/user:The Guardian Actor
普通的Actor最可能和所有user-created Actor打交道,这个监督者叫做/user。所有使用system.actorOf()都是这个监督者的子Actor。这就意味着当这个监督者终止的时候,系统中所有的用户级别的Actor都会被终止。这就意味着这个监督者的监督策略决定了所有用户级别的top-level Actor是如何被监督的。当/user把错误升级到/root的时候,/root会终止/user,根据前面提到的四个原则这就意味着停止整个系统。
/system:The System Guardian
所有system-created Actor的监督者,比如logging listeners。当普通Actor都终止的时候,日志模块仍然处于活跃状态。/system监听/user,当/user和/user所有的下级Actor都已经终止的时候,/system根据Terminated消息启动自己的终止行为。这个监督者的策略是:除了ActorInitializationException和ActorKilledException会直接终止top-level system Actor以外,其他exception都会重新启动top-level system Actor。
什么是restart
当一个Actor在处理某些消息的时候会发生故障,引起这些错误主要包含以下几个情况:
1)接收到的消息有系统错误(编程错误)
2)在处理消息的时候,外部资源故障
3)Actor内部状态错误
除非故障可以被明确的识别出来,否则第三个因素不能被忽略,并且在这种情况下Actor的内部状态需要被清除。当然如果监督者判定其他的子Actorr和它本身不受这个内部状态错误的影响,最好的方法就是重启这个子Actor。这是通过如下方式实现的:创建一个新的Actor,并且用这个新的Actor去替换ActorRef中的那个故障的实例。新的
Actor继续处理它的邮箱,这就意味着restart活动在这个Actor之外是不可见的。
下面是Restart的几个步骤:
1)挂起Actor(这就意味直到Actor被唤醒,他都不会再处理消息),同时递归的挂起所有的子Actor。
2)调用老的实例的preStart方法,默认情况下是发送termincation请求到所有的子Actor并且调用postStop方法,这个在之前也已经提到过了
3)等待所有的子Actor终止完成。和其他Actor操作一样,这个操作也是非阻塞的。当收到最后一个Actor的终止结束提示的时候,就会进行下一步
4)调用原始的工厂创建新的Actor实例
5)调用新的实例的postRestart方法,默认情况下也是调用preStart方法
6)发送重启请求到所有在第三步没有终止的Actor,这些将要被重启的子Actor也会递归的进行处理(从第2步开始)
7)唤醒Actor
什么是Monitoring
import java.util.concurrent.atomic.AtomicInteger;import akka.actor.ActorRef;import akka.actor.PoisonPill;import akka.actor.Props;import akka.actor.SupervisorStrategy;import akka.actor.Terminated;import akka.actor.UntypedActor;import akka.japi.Creator;public class Actor1 extends UntypedActor {private static final class CreatorImplementation implements Creator<Actor1> {/** * */private static final long serialVersionUID = 1L;private AtomicInteger index = new AtomicInteger();public Actor1 create() throws Exception {// TODO Auto-generated method stubreturn new Actor1("Actor1", index.getAndAdd(1));}}String name;int index;public Actor1(String name, int index) {this.name = name;this.index = index;}@Overridepublic void onReceive(Object message) throws Exception {System.out.println(name + "_" + index + " receive message");System.out.println("message: " + message);if (message instanceof MSG) {if (message.equals(MSG.OK)) {System.out.println("i receive ok");getContext().watch(getSender());} else {unhandled(message);}} else if (message instanceof Terminated){System.out.println(getSender() + " terminate");} else {unhandled(message);}}public static Props props() {return Props.create(new CreatorImplementation());}}
import java.util.concurrent.atomic.AtomicInteger;import akka.actor.Props;import akka.actor.UntypedActor;import akka.japi.Creator;public class Actor2 extends UntypedActor {private static final class CreatorImplementation implements Creator<Actor2> {/** * */private static final long serialVersionUID = 1L;private AtomicInteger index = new AtomicInteger();public Actor2 create() throws Exception {// TODO Auto-generated method stubreturn new Actor2("Actor2", index.getAndAdd(1));}}String name;int index;public Actor2(String name, int index) {this.name = name;this.index = index;}@Overridepublic void onReceive(Object message) throws Exception {System.out.println(name + "_" + index + " receive message");if (message instanceof MSG) {if (message.equals(MSG.HI)) {System.out.println("i receive hi");getSender().tell(MSG.OK, getSelf());} else {unhandled(message);}} else {unhandled(message);}}public static Props props() {return Props.create(new CreatorImplementation());}}
import akka.actor.ActorRef;import akka.actor.ActorSystem;public class CreateTest {@SuppressWarnings("static-access")public void communication() {// 使用Props创建Actorfinal ActorSystem system = ActorSystem.create("MySystem");// 创建actor1final ActorRef actor1 = system.actorOf(Actor1.props(), "actor1");// 创建actor2final ActorRef actor2 = system.actorOf(Actor2.props(), "actor2");// actor1发送消息到actor2actor2.tell(MSG.HI, actor1);// 使得actor1和actor2有充分的时间处理消息try {Thread.currentThread().sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}// 关闭actor2system.stop(actor2);system.shutdown();}public static void main(String[] args) {new CreateTest().communication();}}
运行后,出现如下消息
Actor2_0 receive messagei receive hiActor1_0 receive messagemessage: OKi receive okActor1_0 receive messagemessage: Terminated(Actor[akka://MySystem/user/actor2#-1091096557])Actor[akka://MySystem/user/actor2#-1091096557] terminate[INFO] [07/20/2014 12:14:41.522] [MySystem-akka.actor.default-dispatcher-2] [akka://MySystem/user/actor2] Message [akka.dispatch.sysmsg.Terminate] from Actor[akka://MySystem/user/actor2#-1091096557] to Actor[akka://MySystem/user/actor2#-1091096557] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
- Akka 【四】 Supervision and Monitoring
- akka actor监控(monitoring)
- 学习akka之——akka监督supervision
- supervision
- JMX Management and Monitoring
- Nginx LOGGING AND MONITORING
- Kubernetes - Monitoring and Logging
- Java垃圾回收机制四 Monitoring and Analyzing Java Garbage Collection
- Nagios - System and Network Monitoring
- Linux System and Performance Monitoring
- Linux System and Performance Monitoring
- Linux System and Performance Monitoring
- Monitoring and benchmark tools(1)
- Monitoring Open and Cached Cursors
- Monitoring Open and Cached Cursors
- 8 Monitoring Performance and Troubleshooting
- Percona Monitoring and Management架构
- Percona Monitoring and Management 部署
- 考研日记-2014/07/16
- 进制 转换
- Thrift使用实例
- 互联网金融进入洗礼阶段,控制风险是制胜之道
- CScrollView
- Akka 【四】 Supervision and Monitoring
- ReadString在UNICODE/多字节下中文乱码的解决办法
- 第四章 字符串,多维数组和广义表
- IOS的一个带动画的多项选择的控件(一)
- Ubuntu中文字体难看修正
- 关于git的ssh-key:解决本地多个ssh-key的问题
- IOS 软键盘灵活使用KeyBoard库
- switch分支结构————分段函数求值
- 树莓派的基本连接和启动