閱讀47 返回首頁    go 技術社區[雲棲]


2.4 監管和監測

2.4 監管和監測
本節將從概念層麵上介紹有關監管的一些基本元素及其語義。至於在代碼中如何具體實現,請參考API的相關章節。


2.4.1 什麼是監管
正如角色係統一節所描述,監管描述了角色之間的相互依賴關係:監管者委派任務給它的子角色,並負責對它們的失敗做出響應。當子角色監測到一個錯誤(例如,拋出一個異常),它將掛起它自己以及它所有的子角色,並且發消息通知它的監管者任務失敗。根據被監測工作的性質以及失敗的性質,監測者可以做出如下四種響應:
1.重啟子角色,並保持它失敗前的內部狀態
2.重啟子角色,並清空它的內部狀態
3.永久性的停止子角色
4.向它的監管者報告錯誤信息,並終止自己
應該始終將角色看做是監管體係的一部分,這一點很重要。它也解釋了為什麼監管者可以做出上述四種響應(監管者其實也是它自身監管者的子角色),並且它還蘊含了前三種選擇:恢複角色時,也恢複它所有的子角色;重啟角色時,也重啟它所有的子角色(下麵將介紹更細節的一些內容);同理,終止一個角色也終止它所有的子角色。需要注意的是,角色類的preRestart鉤子的默認行為是在重啟之前先終止所有的子角色;在鉤子執行完後再遞歸地重啟所有的子角色。
每個監管者都配置了一個函數來將所有可能的錯誤(如異常)映射到上麵提到的四種響應的一種;特別地,這個函數不需要知道失敗角色的標識號。我們很容易想出很多的例子來證明這種處理方式並不是很靈活。例如,當我們希望對不同的子角色實施不同的策略時。此時,我們最需要理解的是,監管者將會形成一個遞歸的錯誤處理結構。如果你在同一層次中執行了太多的操作,那麼這種遞歸的處理將很難延續。因此,在這種情況下我們推薦的處理方式是增加一級監管者。
Akka實現了一種特殊的形式叫“父層監控”。角色隻能被其它角色創建——頂級的角色由程序庫創建——並且被創建的角色將被它的父節點監控。這個限製隱式的形成了角色監控體係的形式,並且鼓勵健全的設計決策。同時,這樣也保證了角色不會成為孤兒或者依附於係統外的監控者,否則那樣將會很難監控它們。另外,這種方式也使得(子)角色應用的關閉變的非常容易和徹底。
警告:父-子角色監管相關的通信是通過一種特殊的係統消息來實現的。並且每個角色都有一個與普通用戶消息分開的信箱來存放該係統消息。這也就暗示著,監管事件和普通消息之間並沒有一個確定的處理順序。通常,用戶是無法影響普通消息和失敗消息的順序的。如果想了解更多的細節和實例,請參考討論:消息順序一節。

2.4.2 頂級監管者

2.4.2
如上圖所示,一個角色係統在它運行期間至少要啟動三個角色。如果想了解更多的有關角色路徑的信息,請參考角色路徑的頂級範圍一節。
/user: 守護角色
與這個角色打交道最多的就是用戶創建角色的父角色。我們將其命名為“/user”。所有以system.actorOf()創建的角色都是它的子角色。這意味著當這個角色終止時,係統中所有的普通角色也都將被關閉。同時,這也意味著這個守護者的監管策略決定了最頂層的普通角色是怎樣被監管的。從Akka版本2.1以後,可以通過配置akka.actor.guardian-supervisor-strategy來設置它。它的值必須是一個SupervisorStrategyConfigurator類的全路徑。當該守護者向上匯報失敗時,根守護者的響應就是終止該守護者,即停止整個角色係統。
/system:係統守護者
這個特殊的守護者是為了實現有序的關閉一係列的角色引入的。當所有的普通角色終止時,它會記錄那些仍然活著的角色。日誌的記錄也是通過使用這類角色實現的。它的實現是通過讓係統守護者監控用戶守護者,並在收到Terminated消息時關閉自己。頂層的係統角色通過這樣一種策略監控:當遇到Exceptoin時,它將無限次的重啟角色。但ActorInitialzationException和ActorKilledException例外,遇到這兩種異常時,它將終止有問題的子角色。對於那些被拋出去的異常將會被升級,從而導致整個角色係統被關閉。
/:根守護者
根守護者是那些所謂的“頂層”角色的祖父。它通過SupervisorStrategy.stoppingStrategy策略來監控所有在角色路徑的頂級範圍一節中提到的特殊角色。該策略的目的是當遇到任何異常時終止它的子角色。所有被拋出去的異常將會被升級…但是升級給誰呢?因為每個真正的角色都會有一個監控者,而根守護者的監控者不可能是一個真正的角色。這意味著“走到了氣泡以外”,所以我們將其稱作“氣泡-行走者”。這是一個綜合的角色引用,它可以在收到第一個錯誤信號的時候停止它的子角色,並且在根守護者終止時,將係統角色的isTerminated狀態置為真(所有的子角色遞歸的停止)。
2.4.3 重啟指的是什麼
當一個角色在處理特定的消息失敗時,通常引起失敗的原因可以歸為下列三類:
處理收到的特定消息的係統(如程序)錯誤
在消息處理過程中係統外部資源(短暫地)錯誤
角色內部狀態崩潰
除非這個失敗是具體可辯認的,否則我們並不能排除第三種錯誤。所以,我們得出一個結論:每次出錯都要清空內部狀態。如果監管者判斷本次的崩潰不會影響到其它子角色或者它本身——如,因為故意的調用錯誤內核模式——那麼最好重啟這對應的子角色。這是通過創建角色類的一個新對象,然後在子角色的ActorRef中,由它來取代失敗的對象來實現的;之所以可以這樣實現,是因為在特定的引用中角色的封裝特性。新的角色將開始繼續處理它的信箱。這也就意味著,這個重啟動作對外是不可見的,引起異常錯誤的消息將不會被重新處理
重啟過程中各個事件的順序如下所述:
1. 掛起角色(這也就意味著在重啟之前它將不能出來正常的消息),並且遞歸的掛起所有子角色
2. 調用老實例的preRestart鉤子(默認行為是向所有子角色發送終止請求,並且調用postStop) 3.等待在preRestart中請求終止的所有子角色真正終止;這個操作——像所有的角色操作一樣——是非阻塞的,最後一個被殺死的子角色的終止消息將會影響接下來的操作。
4. 調用最初提供的工廠創建新的角色實例。
5. 在新實例上調用postRestart.(默認還會調用preStart)
6. 向第3步中未被殺掉的子角色發送重啟請求;重啟的子角色將遞歸的從第2步開始,按照相同的流程處理
7. 重啟這個角色
2.4.4 生命周期監控是什麼
提示: 在Akka中生命周期監控通常指的是DeathWatch
與前麵介紹的父角色和子角色的關係相比,每個角色可能還監視著其它任意的角色。因為角色創建後,它活著的期間以及重啟在它的監管者之外是看不到的,所以對監視者來說它能看到的狀態變化就是從活著變到死亡。所以監視的目的是當一個角色終止時可以有另一個相關角色做出響應,而監管者的目的是對角色的失敗做出響應。
監視角色通過接收Terminated消息來實現生命周期監控。如果沒有其它的處理方式,默認的行為是拋出一個DeathPactException異常。為了能夠監聽Terminated消息,你需要調用ActorContext.watch(targetActorRef)。調用ActorContext.unwatch(targetActorRed)來取消對目標角色的監聽。需要注意的是,Terminated消息的發送與監視角色注冊的時間和被監視角色終止的時間順序無關。例如,即使在你注冊的時候目標角色已經死了,你仍然能夠收到Terminated消息。 當監管者不能簡單的重啟子角色而必須終止它們時,監視將顯得非常重要。例如,角色在初始化的時候報錯。在這種情況下,它應該監視這些子角色並且重啟它們或者稍後再做嚐試。
另一個常見的應用案例是,一個角色或者它的子角色在無法獲得需要的外部資源時需要失敗。如果是第三方通過調用system.stop(child)方法或者發送PoisonPill消息來終止子角色是,監管者也將會受到影響。

2.4.5 一對一策略 VS. 多對一策略
Akka有兩種類監管策略:一對一策略和多對一策略。它們都配置了從異常類型到監管命令的一個映射(參考上文),並且限製子角色在終止之前允許失敗的次數。它們之間的不同是,前者隻可以將指令實施在其失敗的子角色上,而後者還可以將指令實施在它的兄弟姐妹之上。通常,你應該使用一對一策略,它也是默認的選項。
多對一策略(AllForOneStrategy)策略適用於子角色之間有相互依賴關係的場景,當一個子角色失敗時,會影響到其它子角色的功能。例如,它們難見難分的鏈接在一起。因為重啟並不會清空信箱,所以最好的選擇通常是,終止失敗的子角色,然後由監管者顯式的重新創建它們(通過觀察它們的生命周期);否則你必須能夠確保每個重啟的角色都能正確的處理重啟之前入隊的消息。
通常,在多對一策略中,停止一個子角色(例如,不響應失敗)並不會自動的終止其他子角色;這個可以通過觀察它們的生命周期很容易的實現:如果Terminated消息沒有被監管者處理,它將會拋出一個DeathPactException(決定於它的監管者)來重啟自己,默認的preStart行為將會終止它所有的子角色。當然這些也可以顯式的實現。
需要注意的是,對於多對一監管者來說創建一次性的角色將會導致零時角色的失敗被擴大化,從而影響永久性角色。如果這個不是你希望的,那麼請創建一個中間監管者;這個可以通過創建一個大小為1的路由器來實現,具體參見3.6路由一節。

 

最後更新:2017-05-23 16:33:20

  上一篇:go  演講實錄丨丨Young-Jo Cho 基於網絡的機器智能機器人技術的發展
  下一篇:go  Java網絡教程之Socket