新人接触线上的时候一般都会碰到supervise这个工具,导师对这个模块的解释一般就是,这个模块是监控进程,当进程挂掉之后,supervise会将进程启动。这样当进程出
现问题,如因出core而导致进程down掉的时候,supervise会马上将进程起起来,从而快速恢复服务。
新人一般就会记住这一点,然后就一直没有去深入理解,supervise具体是怎么做的这一点的,以及从supervise我们能获得什么信息。
实际上supervise是开源工具集daemontools( http://cr.yp.to/daemontools.html )其中的一个工具,公司将这个工具单独从daemontools剥离,
并且根据公司的需求更改了源代码,这个工作是逢春同学负责
模块的工作原理实际上很简单,supervise启动的时候fork一个子进程,子进程执行execvp系统调用,将自己替换成执行的模块,
模块变成supervise的子进程在运行,而supervise则死循环运行,并通过waitpid或者wait3系统调用选择非阻塞的方式去侦听子进程的运行情况,
当然同时也会读取pipe文件svcontrol的命令,然后根据命令去执行不同的动作,
如果子进程因某种原因导致退出,则supervise通过waitpid或者wait3获知,并继续启动模块,如果模块异常导致无法启动,则会使supervise陷入死循环,不断的启动模块
原理总结下来就是导师给新人所介绍的那样。
supervise要求在当前目录下有status目录,同时status目录下面会有通过supervise启动的模块名的目录,而该目录下会有三个文件,分别为lock status svcontrol,对应的功能和我们可以从中获取的信息如下
对于以上三个文件,从中获取的信息的用处,我认为主要在优化模块的控制脚本上面,
现有的控制模块起停脚本一般都是通过grep命令去获取对应的进程的pid,然后发送信号给对应的pid,
这种方式是从外部方式获取信息,在准确性上面会差一点,可能会造成误杀,而如果通过status目录的三个文件去获取模块的信息,
并且通过svcontrol控制接口去控制,这种方式是从内部方式去获取模块运行的一些信息,能够保证准确性
space现在部分模块的起停脚本已经更改过,但是没有全面推广,因现在推广的需求不强烈,因此推广也没有排期
OP同学会发现,使用supervise去启动transmit的时候,然后通过pstree space(或者其他工作帐号)去观察进程的时候,会发现进程打印的不规范,如下
supervise.trans---supervise.trans
transmit---2*[transmit]
具体原因是这样子的,supervise通过waitpid或者wait3去侦擦子进程的情况,但是由于transmit这个模块在内部逻辑里面要求自己形成守护进程,
进而脱离了supervise这个父进程,成为init的子进程,此时waitpid或者wait3返回的不是预期的,supervise就认为子进程异常
从而进入了启动transmit的阶段,去重启启动一个transmit,但是新启动的transmit因为端口已经被占用,因此无法启动
自己进程退出,supervise又认为子进程异常,从而陷入死循环,不断的重启transmit,因此通过pstree 去看就形成那种格式
因为此时transmit和superivse.transmit已经不是父子关系了。当然需要提一下的是,supervise在死循环重启子进程的时候,
每次重启前都会sleep 一段时间,因此可以认为几乎不耗机器的资源
memcached如果使用了-d选项,也会出现如上的问题,-d选项为memcached自己形成守护进程,
因此现在space的memcached一般都把-d选项关闭,理论上只要形成守护进程的程序,使用supervise去启动的时候都会有这个问题
这个跟rd有很大的关系,个人建议rd写程序的时候不要自己去把程序写成守护进程,没啥意义