Erlang:RabbitMQ源碼分析 3. supervisor和supervisor2深入分析

supervisor也是Erlang/OTP裏一個常用的behavior,用於構建supervisor tree實現進程監控,故障恢復。

而RabbitMQ實現了一個supervisor2,我們從源碼角度分析二者的實現和區別。


先介紹一些supervisor的基本概念,假設node_manager_sup是一個supervisor,它的init函數會定義supervisor的一些參數和它的children。

參數:

          1. Restart Strategy:

                  Strategy必須是simple_one_for_one,one_for_one, one_for_all, rest_for_one 中的一種

                    simple_one_for_one是指supervisor啓動時並不啓動children,children個數不限,但只能是同一個類型的child,共享一份代碼

                    one_for_one是指supervisor啓動時就啓動所有children,一旦一個child掛了,supervisor只去重啓這一個child process,不影響其他children

                    one_for_all是指supervisor啓動時就啓動所有children,一旦一個child掛了,supervisor重啓所有children processes

                    one_for_rest是指supervisor啓動時就啓動所有children,一旦一個child掛了,supervisor重啓在這個child之後聲明的所有children


         2. intensity and period:如果在period時間內重啓超過intensity 次,supervisor就把所有children連同自己一起kill掉


Children的參數:

         1. StartFun,child啓動函數,必須返回{ok,ChildPid} or {ok,ChildPid,Info}

         2. Restart, 本child的重啓策略, permanent代表一直重啓,temporary代表絕不重啓,transient代表只有當error退出時才重啓

         3. ShutDown, 本child process的shutdown策略,brutal_kill代表立刻強行kill掉, 正整數代表timeout,即發送一個kill的request,如果timeout時間還沒收到response,就強行kill掉,infinity代表只是發送一個kill的request過去,不強行kill,一般用於當child也是一個supervisor的時候。


supervisor也是一個gen_server

supervisor2並沒有使用gen_server2而是使用了原版的gen_server


既然是gen_server,supervisor的入口start_link,其實也就是內部的init函數:

1. 檢查supervisor的所有參數

2. 如果不是simple_one_for_one, 就啓動所有children。


當有child process exit 時,根據gen_server的behavior,會由handle_info({'EXIT', Pid, Reason}, State)來處理,根據此child的Restart類型進行重啓。

重啓之前會更新重啓次數,如果發現在period時間內重啓超過intensity 次,就把所有children連同自己一起kill掉

如果重啓失敗會再次重啓,再次重啓的請求由handle_cast處理


最後再看supervisor的幾個export函數:

start_child, 是一個gen_server:call,

1. 如果是simple_one_for_one,就從children裏隨便拿一個啓動,因爲simple_one_for_one的children都一樣,而且都沒隨supervisor啓動

2. 如果不是simple_one_for_one,start_child就傳入一個child,啓動這個child

restart_child,delete_child, terminate_child,which_children,which_children也都是gen_server:call


supervisor2:

supervisor2並沒有使用RabbitMQ自己的gen_server2而是使用gen_server,原因supervisor接收的request比較少(都是重啓,啓動,終止之類),也沒有用到hibernate。

supervisor2對supervisor的改動並不算多:

1. intrinsic, child的Restart增加了intrinsic類型,和transient很像,不同的是,transient如果child非正常退出,就將其刪除,supervisor照常運行;但intrinsic如果child非正常退出,supervisor也會退出並刪除其他所有children。

2. Delay, 如上所述,在period時間內重啓超過intensity 次,supervisor就把所有children連同自己一起kill掉supervisor2裏,child的Restart可以寫{permanent, Delay} | {transient, Delay} | {intrinsic, Delay},這樣在period時間內重啓超過intensity 次後,supervisor並不會kill所有,而是等待Delay時間再嘗試重啓該child。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章