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。

时间: 2024-10-27 16:37:14

Erlang:RabbitMQ源码分析 3. supervisor和supervisor2深入分析的相关文章

Erlang:RabbitMQ源码分析 4. file_handle_cache实现分析

RabbitMQ的文件操作使用file_handle_cache,将Erlang的prim_file Module包了一层.增加了writeBuffer和对文件打开数量的控制逻辑 file_handle_cache也是一个gen_server2,但一般来说只有Open操作会send message to gen_server2, 读写操作,包括writeBuffer都在Client Process里执行和维护. file_handle_cache里存储了几张表: 1. Elders:    {P

Erlang:RabbitMQ源码分析 5. worker pool 实现分析

worker_pool 由一个worker_pool 和N个worker_pool_worker组成, N = number of scheduler threads 外部程序有两种方式来call worker_pool ,  submit(func) and submit_async(func) submit(func) 是同步的提交Task,worker_pool 用worker_pool_worker做完返回 submit_async(func)是异步的提交Task,worker_pool

RabbitMQ源码分析 1. 启动过程

RabbitMQ的启动是基于boot steps, boot steps的每一个step可能是启动一个component,也可能是打印一个启动信息. boot steps是一个有向无环图,保证了启动的顺序性. 一个boot step: -rabbit_boot_step({recovery, [{description, "exchange, queue and binding recovery"}, {mfa,         {rabbit, recover, []}}, {req

storm启动supervisor源码分析-supervisor.clj

supervisor是storm集群重要组成部分,supervisor主要负责管理各个"工作节点".supervisor与zookeeper进行通信,通过zookeeper的"watch机制"可以感知到是否有新的任务需要认领或哪些任务被重新分配.我们可以通用执行bin/storm supervisor >/dev/null 2>&1 &来启动supervisor.bin/storm是一个python脚本,在这个脚本中定义了一个superv

supervisor启动worker源码分析-worker.clj

supervisor通过调用sync-processes函数来启动worker,关于sync-processes函数的详细分析请参见"storm启动supervisor源码分析-supervisor.clj".sync-processes函数代码片段如下: sync-processes函数代码片段 ;; sync-processes函数用于管理workers, 比如处理不正常的worker或dead worker, 并创建新的workers;; supervisor标识supervis

ranch 源码分析(一)

以前写了一个ranch的处理流程,http://www.cnblogs.com/tudou008/p/5197314.html ,就只有一张图,不是很清晰,现在有空做个源码分析. ranch的源码(版本v1.2.1 下载链接https://github.com/ninenines/ranch.git) 我们从一个最简单的例子开始 tcp_echo 1 [[email protected] ranch-master]# pwd 2 /home/erlang/ranch-master 3 [[ema

ranch 源码分析(二)

接上ranch 源码分析(一) 上次讲到了ranch.erl的start_listener函数,下面我们详细分析下这个函数 -module(ranch). %...... 省略若干行 -spec start_listener(ref(), non_neg_integer(), module(), any(), module(), any()) -> supervisor:startchild_ret(). start_listener(Ref, NbAcceptors, Transport, T

storm操作zookeeper源码分析-cluster.clj

storm操作zookeeper的主要函数都定义在命名空间backtype.storm.cluster中(即cluster.clj文件中).backtype.storm.cluster定义了两个重要protocol:ClusterState和StormClusterState.clojure中的protocol可以看成java中的接口,封装了一组方法.ClusterState协议中封装了一组与zookeeper进行交互的基础函数,如获取子节点函数,获取子节点数据函数等,ClusterState协

storm启动nimbus源码分析-nimbus.clj

nimbus是storm集群的"控制器",是storm集群的重要组成部分.我们可以通用执行bin/storm nimbus >/dev/null 2>&1 &来启动nimbus.bin/storm是一个python脚本,在这个脚本中定义了一个nimbus函数: nimbus函数 def nimbus(klass="backtype.storm.daemon.nimbus"):    """Syntax: [s