[轉] Actor生命週期理解
[轉] https://blog.csdn.net/wsscy2004/article/details/38875065
鎮圖: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,使用靜態類儲存狀態。