Actor生命周期理解

简介: <h2 class="note-title" style="font-family:'Helvetica Neue',Arial,'Hiragino Sans GB',STHeiti,'Microsoft YaHei','WenQuanYi Micro Hei',SimSun,Song,sans-serif; line-height:1.1; color:rgb(22,32,41); ma



Actor生命周期理解

镇图:Actor内功心法图

Actor的生命周期可以用Hooks体现和控制,下面是默认的Actor Hooks的方法,我们可以选择性的进行重写:

def preStart(): Unit = ()

def postStop(): Unit = ()

def preRestart(reason: Throwable, message: Option[Any]): Unit = {
  context.children foreach { child ⇒
    context.unwatch(child)
    context.stop(child)
  }
  postStop()
}

def postRestart(reason: Throwable): Unit = {
  preStart()
}

每个Hooks,在不同的策略下调用次数及顺序是不同的,那什么是策略?:

  class DbSupervisor extends Actor {
    override def supervisorStrategy = OneForOneStrategy() {
      //如果dbWriter失败,则调用Restart策略,重启该出错的Actor
      case _: DbBrokenConnectionException => Restart
    }

策略,比如Restart,实际上就是执行了一系列的方法包括:preRestart,postRestart

Start策略

Start策略,调用preStart Hook,一般用于初始化资源.在创建一个Actor的时候,会调用构造函数,之后调用preStart,那这两个方法有什么区别呢,资源初始化是放在构造函数,还是放在preStart里面呢?在Restart策略里面会详细介绍。

Stop策略

postStop hook 一般用于回收资源。Actor在被调用postStop之前,会将邮箱中剩下的message处理掉(新的消息变成死信了)。Actor是由UID和Path来唯一标识的,也就是说ActorRef也是通过UID和Path来定位。在Actor被Stop之后,新的Actor是可以用这个Path的,但是旧的ActorRef是不能用的,因为UID不一样。

Restart策略

Restart策略是最为复杂的一种情况,先上个图:

在默认情况下,Restart策略会:

  1. actor被挂起
  2. 调用旧实例的 supervisionStrategy.handleSupervisorFailing 方法 (缺省实现为挂起所有的子actor)
  3. 调用preRestart方法,从上面的源码可以看出来,preRestart方法将所有的children Stop掉了!(Stop动作,大家注意!),并调用postStop回收资源
  4. 调用旧实例的 supervisionStrategy.handleSupervisorRestarted 方法 (缺省实现为向所有剩下的子actor发送重启请求)
  5. 等待所有子actor终止直到 preRestart 最终结束
  6. 再次调用之前提供的actor工厂创建新的actor实例
  7. 对新实例调用 postRestart
  8. 恢复运行新的actor

Restart策略,和Stop策略有什么不同的地方?
Stop策略会调用postStop(),Restart策略也会调用postStop(),但是Restart策略不是通过Stop策略来停止旧的Actor,UID和Path都没变。也就是说,在被Restart之后,不用重新获取ActorRef.

preRestart Hook有什么特别之处?
默认的preRestart Hook会将所有的Children通过Stop策略停止,这个时候Children就是通过Stop策略->Start策略启动的,而不是被递归Restart.那有什么影响?如果有外部的Actor持有旧的Chidren ActorRef,那这个Ref就是不能用的,因为虽然Path是对的,但是UID已经变了!

postRestart Hook有什么特别之处?
默认postRestart是调用preStart(),这样在重启的过程中,构造函数和preStart方法都会被重新调用,如果有个资源只想初始化一次,那么就必须重写掉这个方法.所以一般创建children是放在preStart里面。

override def preStart(): Unit = {
  // 初始化children
}

// 重写postRestart防止preStart每次重启都被调用
override def postRestart(reason: Throwable): Unit = ()


override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
  // 任然要清理自己,但是不Stop children
  postStop()
}

被重启后,如何继承旧的actor的状态?
通过将state转储到:

  • 数据库(案例:Hbase,也是郑草原的实时计算集群采用的持久化方法)
  • 官方的包akka-persistence-experimental(测试阶段), ppt介绍 and Persistence文档
  • 非JVM级别的crash,使用静态类保存状态
目录
相关文章
|
3月前
|
设计模式 人工智能 安全
【Tomcat源码分析】生命周期机制 Lifecycle
Tomcat内部通过各种组件协同工作,构建了一个复杂的Web服务器架构。其中,`Lifecycle`机制作为核心,管理组件从创建到销毁的整个生命周期。本文详细解析了Lifecycle的工作原理及其方法,如初始化、启动、停止和销毁等关键步骤,并展示了LifecycleBase类如何通过状态机和模板模式实现这一过程。通过深入理解Lifecycle,我们可以更好地掌握组件生命周期管理,提升系统设计能力。欢迎关注【码上遇见你】获取更多信息,或搜索【AI贝塔】体验免费的Chat GPT。希望本章内容对你有所帮助。
|
4月前
|
安全 Java 数据库连接
|
4月前
NettyHandler 常用生命周期方法
NettyHandler 常用生命周期方法
34 0
|
6月前
|
Java 测试技术 图形学
UE Actor生命周期
UE Actor生命周期
|
7月前
|
存储 安全 IDE
C/C++ 作用域,生命周期,执行线程的概念
C/C++ 作用域,生命周期,执行线程的概念
95 2
|
7月前
|
前端开发 JavaScript Python
学不懂生命周期函数正常吗?
学不懂生命周期函数正常吗?
|
7月前
将生命周期方法添加到类中
将生命周期方法添加到类中
|
存储 安全 Java
|
JavaScript 调度 开发者
生命周期函数-组件运行和销毁阶段的钩子函数|学习笔记
快速学习生命周期函数-组件运行和销毁阶段的钩子函数
224 0
生命周期函数-组件运行和销毁阶段的钩子函数|学习笔记
|
存储 Android开发
Activity的生命周期-典型情况下的生命周期
Activity的生命周期分为两部分内容,一部分是典型情况下的生命周期,另一部分是异常情况下的生命周期。所谓典型情况下的生命周期,是指在有用户参与的情况下,Activity所经过的生命周期的改变;而异常情况下的生命周期是指Activity被系统回收或者由于当前设备的Configuration发生改变从而导致Activity被销毁重建,异常情况下的生命周期的关注点和典型情况下略有不同。
558 0
Activity的生命周期-典型情况下的生命周期