Erlang OTP学习(3) supervisor
今天細致的看了下supervisor,現(xiàn)在做個總結:?
?
其中,方塊代表supervisor process,它的功能很簡單,就負責看管它下面的“小弟”(child processes) 并且在必要的時候對某個child process執(zhí)行restart或者terminate操作;而圓形就代表worker process,它才是真正負責干活的process;特別注意,supervisor process 監(jiān)控的不一定都是worker process 可以是別的supervisor(如上圖)。通過以上方式,我們就可以按照一定層次結構將process管理起來,構建一個強健的容錯系統(tǒng) 。?
現(xiàn)在我們就看看如何創(chuàng)建一個supervisor:?
類似gen_server, gen_event模塊,erlang已經(jīng)把如何創(chuàng)建一個supervisor解耦:分成非功能模塊和功能模塊。非功能模塊是一個叫supervisor的module(后面簡稱為 S module),功能模塊則由各個使用方以callback module形式提供,在callback模塊中,你只需要編寫一個init方法供S module回調(diào)即可,該init方法指定了將要創(chuàng)建的supervisor的三個屬性:?
1.重啟策略(Restart Strategy)?
a. one_for_one?
當一個child process掛掉時,它的監(jiān)控者(supervisor)僅重啟該child process,而不會影響其他child process?
b.one_for_all?
當一個child process掛掉時,它的監(jiān)控者(supervisor)將會terminate其余所有child? process,然后再重啟所有child process?
c.rest_for_one?
當一個child process掛掉時,它的監(jiān)控者(supervisor)只會terminate在該child process之后啟動的process,然后再將這些process 通通重啟?
d.simple_one_for_one?
重啟策略與one_for_one相同,唯一的區(qū)別是:所有的child process都是動態(tài)添加的并且執(zhí)行同樣一份代碼(稍后詳述)?
2.最大重啟頻率(Maximum Restart Frequency)?
該屬性的主要目的是為了防止child proces 頻繁的terminate-restart,當某個child process超過這個頻率,supervisor將會terminate所有的child process然后再terminate掉自己(根據(jù)我的測試結果,這個頻率的計算是這次重啟距離上次重啟的的時間間隔)?
3.Child Specification?
這個屬性說白了,就是告訴supervisor,你要監(jiān)控哪些child process,你該怎么啟動這些child process以及如何結束它們等等,該屬性的詳細格式如下:?
{Id, StartFunc, Restart, Shutdown, Type, Modules}?
??? Id = term()?
??? StartFunc = {M, F, A}?
??? Restart = permanent | transient | temporary?
??? Shutdown = brutal_kill | integer()>0 | infinity?
??? Type = worker | supervisor?
??? Modules = [Module] | dynamic?
其中:?
| Id?唯一標示了一個child process; |
| StartFunc告訴supervisor如何啟動它(即調(diào)用哪一個方法),特別要注意的是:1. StartFunc 必須 create a link to? the child process(只有這樣 supervisor才能夠監(jiān)控到child process,感知它的生死)2.若child process 創(chuàng)建成功,它必須返回 {ok, Child} 或者 {ok, Child,? Info},其中Child 為child process的Pid,Info值被supervisor忽略(我一開就在這里栽了跟頭,沒有按標準格式返回) |
| Restart?這個參數(shù)用來告訴supervisor,當該child process掛掉時,是否能夠重啟它,permanent表示永遠可以(不管child process是以何種原因掛掉),temporary表示永遠不可以(即掛掉了將不再重啟),transient 有點特殊,它表示child process若是因為normal或者shutdown原因結束,則不再重啟,否則可以restart(ps:Restart參數(shù)設置會覆蓋Restart Strategy,譬如一個child process的Restart設置為temporary,supervisor的Restart Strategy是one_for_all,那么當其他某個child process掛掉后,將會導致該child process(temporay)被terminate并且不再被重啟) |
| Shutdown?用來告訴supervisor當它想terminate某個child process該如何terminate,brutal_kill 顧名思義就是很粗魯,很暴力的結束一個child process(supervisor內(nèi)部調(diào)用exit(ChildPid, kill)方法,注意exit reason為kill的exit signal是不可被捕獲的,無論ChildPid是否為system process);整型值TimeOut表示當supervisor想結束一個child process時,它調(diào)用exit(ChildPid, shutdow),若在Timout時間范圍內(nèi)supervisor沒有收到來自child process的exit signal(因為supervisor linked to child process,所以當child process掛掉時,supervisor會收到一個exit signal),那么supervisor將會調(diào)用exit(ChildPid, kill)方法,暴力的terminate child process(這里我突然疑惑了?這樣不也是會導致supervisor 收到一個不可捕獲的exit signal?);infinity:當你的child process 也是一個supervisor并且你需要terminate,這時你需要將Shutdown參數(shù)設置為infinity,從而保證child process(supervisor)能夠有充分的時間結束它的supervision tree; |
| Type:用來指定child process的類型(worker or superviosr) |
| Module: 這個參數(shù)我目前還不是很明白,暫且擱置 |
說完了這么多,我們來看一個簡單的例子(child process 每5s由它的supervisor重啟一次):?
worker process?
?
該worker process做的事情很簡單,啟動時會打印start...,然后暫停5s,最后退出打印一條quit...消息,其中start_link供supervisor調(diào)用?
supervisor?
我們重點看下幾個參數(shù)的設置:?
supervisor重啟策略:one_for_one?
supervisor最大重啟頻率:1 / s?
child process的StartFunc: tick模塊的start_link方法,參數(shù)為空?
child process的Restart屬性:permanent(這個是child process 掛掉后能被重啟的關鍵)?
我們看下程序運行效果:?
?
第一行調(diào)用supervisor:start_link(my_supervisor, []) 創(chuàng)建一個supervisor(其中my_supervisor是callback module),若成功創(chuàng)建supervisor(它所監(jiān)控的child process也創(chuàng)建成功),則返回{ok, SupPid}(譬如這里的{ok, <0.34.0>),之后我們就看到屏幕上一直循環(huán)打印start.... quit.... 并且每一個pid都不一樣,這就說明,當supervisor發(fā)現(xiàn)child process掛掉后(不論什么原因,哪怕是正常退出),都會restart child process(你可以嘗試把child process的permanent修改為temporary,看看運行結果又是如何)?
至此我們已經(jīng)完成了一個supervisor的例子,別看它簡單,但確實構建了一個supervision tree,關于supervisor的更多細節(jié),請參看下列文檔:?
http://www.erlang.org/doc/design_principles/sup_princ.html?
http://www.erlang.org/doc/man/supervisor.html?
最后我們在看下:simple_one_for_one,這種Restart Strategy和one_for_one基本相同(即當一個child process掛掉后,僅僅重啟該child process 而不影響其他child process),唯一不同的是:simple_one_for_one 只能夠動態(tài)的添加child process并且所有的child process執(zhí)行同一份代碼 ,我們來看一個例子(來自otp 官方文檔)?
?
注意這里的StartFunc: {call, start_link, []} 并不會真正的去啟動一個child process,而必須通過調(diào)用 supervisor:start_child(Sup, List) 動態(tài)添加child process,其中第一個參數(shù)Sup是表示你要往哪個supervisor下添加child process,第二個參數(shù)用來在創(chuàng)建child process時傳遞給它(內(nèi)部調(diào)用apply(M, F, A++List))?
好了,關于supervisor先就說到這里,若有不對的地方懇請指出!
轉載于:https://www.cnblogs.com/huangxiaoyi/p/5033105.html
總結
以上是生活随笔為你收集整理的Erlang OTP学习(3) supervisor的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LAMP 2.2 Apache配置静态
- 下一篇: (2015-12-09)java.uti