关于erlang application supervisor 进程及子进程结束的几个实验


一. application 
    能够严格保证先启动的后结束,后启动的先结束
 
二. supervisor
   
    a. supervisor simple_one_for_one方式启动的子进程在supervisor结束的时候同时通知所有子进程要结束(通过exit信号)
        这个在supervisor的文档中有说明:
        Because a simple_one_for_one supervisor could have many children, it shuts them all down at same time. So, order in which they are stopped is not defined. For the     same reason, it could have an overhead with regards to the Shutdown strategy.(所以看文档一定要仔细)
    
    b. supervisor one_for_one 方式启动的子进程在supervisor 结束的时候逐个结束其下子进程
   
    c. application-supervisor结构
                node
                  /|\
     ----------------------------------------------------------------------------------------------------------------------------
                         app1                                                                                     app2         app3
                            |
       application_master-main_loop
                            |
                      application_master-loop_it
                                        /      \
                                   sup1     sup2
     如果是这种方式挂靠,我们执行init:stop的时候,只有最后面的一个supervisor收到了结束通知,这个大家可以去看看底层代码
 
 
    d. application-supervisor结构
                node
                  /|\
     ----------------------------------------------------------------------------------------------------------------------------
                         app1                                                                                     app2         app3
                            |
       application_master-main_loop
                            |
                      application_master-loop_it
                                            |    
                                       sup_root
                                        /      \
                                   sup1     sup2   
如果是这种方式挂靠,我们执行init:stop的时候,sup_root收到了结束通知,sup1和sup2也会分别接到通知
sup2首先结束,sup2结束完成后sup1接着进行结束操作,所以我们监控树下的子进程如果是supervisor的话,那么shutdown参数应该设置为infinity,永远等待
但是,如果子进程是worker的话那么一定不要设置为infinity,这样有可能会导致进程一直等待下去,不重启,不结束,
而supervisor之所以可以设置为infinity是因为结束的代码是系统代码,基本上可以信任,而worker代码是我们自己写的代码,bug,异常都可能会导致程序在出现
问题的时候卡到这个环节.
 
      e.如果是这种方式的话根supervisor下面既有子supervisor又有子worker,那么工作方式也是一样的从右到左来结束

 
    f.appmon:start()显示的进程组织结构,并不是从左到右对应从前到后,例如下图102,101进程实际上是后启动的,所以是先结束,跟显示无关
 
 
 

 
   g.  supervisor只关注直接挂在在其下的进程,如果是worker link woker,例如95 sleep 2秒 96 sleep 3秒 shutdown = 5秒
        那么e_test_sup_root 即使shutdown等待时间足够也不会关注96,除非我们再95的terminate中使用moniter监控96进程结束后再让96结束
        或者我们将96也挂在到sup下面,然后通过link关联95和96
   

 
   h.  shutdown参数Shutdown = brutal_kill | int()>=0(单位毫秒) | infinity 要特别关注,如果设置为brutal_kill或者一个较小的时间那么可能会导致清理完成前结束
 
 i.  父决定了子,例如sup1和sup2, sup1先于sup2启动,但是他们的子启动的顺序反过来了,那么是先结束哪个呢,如下图:
       e_test:start(),
        e_test_sup_root:start_child_sup(e_test_sup, []),
        e_test_sup_root:start_child_sup(e_test_sup2, []),
        e_test_server2:start(1),
        %e_test_server:start(),
        e_test_server:start()

  实际上是e_test_sup2下的所有进程先结束的,与具体进程启动顺序无关,跟他们所在的supervisor相关
 

j.
 关于supervisor下面挂载进程,子worker和link连接
   1>.一种启动方式是:{ok, _} = supervisor:start_child(e_test_sup, []).这也是标准的启动方式,
        这种方式启动的进程是标准的worker进程使用重启策略,结束的时候supervisor按照shutdwon策略处理
    

 
   2>.还有一种启动方式是:让supervisor直接link到子进程,例如
        这种方式无论e_test_sup是什么重启策略 96进程被结束后都不会重启,也就是不使用它的重启策略; 
        虽然如此,这种方式在结束的时候依然是先结束后启动的e_test_sup2然后是e_test_sup,只是e_test_sup不会等待link的进程

 
k. 子进程和进程间链接,进程间链接不影响supervisor和workder的关系,同样link还是按照link的逻辑处理,这样当一个结束的时候另一个会收到退出信号消息,
    当init:stop的时候还是按照原来结束方式进行结束,只是先结束的98会通知97,97可能在收到父supervisor的结束信号前就会结束,这种情况下要注意防止死循环的产生
    子进程重启策略最好设置为temporary,而不是transient更不是permanent.
   

 
 
 本文原创,转载注明出处.
 参考:http://www.qingliangcn.com/2010/08/erlang-otp%E4%B9%8Bterminate-%E6%B7%B1%E5%85%A5%E5%88%86%E6%9E%90/

posted on 2012-08-16 14:50  fangjie008  阅读(1263)  评论(0编辑  收藏  举报

导航