在之前的一篇文章《终端自动化测试探索之路》中提到过当发生断电等情况,服务器重启之后如何快速恢复自动化服务,这里针对这个问题具体讲讲我的实现方式。
背景
自动化测试系统中涉及很多服务进程,比如appium server、http server、stf、还有用来管理服务器上挂载设备状态的agent等,如果出现断电等异常情况机器重启,那么这些服务将变的不可用,影响系统的整体稳定性。
方案选型
基于上述原因,我考虑采用supervisor来管理这些进程,supervisor是一个UNIX-like系统上的进程管理工具,是一个由Python开发的c/s系统,可以管理和监控unix上面的进程,不过它不能监控daemon进程。
1、部署简单
我们通常管理linux进程的时候,一般来说都需要自己编写一个能够实现进程start/stop/restart/reload功能的脚本,然后丢到/etc/init.d/下面,这么做有很多不好的地方:
- 我们要编写这个脚本,本身就很耗时耗力。
- 当这个进程挂掉的时候,linux是不会自动重启它的,想要自动重启的话,我们还要自己写一个监控重启的脚本,而supervisor则可以完美的解决这些问题。
那supervisor是如何实现进程管理并重启的呢?
- supervisor管理进程就是通过fork/exec的方式把这些被管理的进程,当作supervisor的子进程来启动。这样的话,我们只要在supervisor的配置文件中把要管理进程的可执行文件的路径写进去就OK了,这样就省下了自己写控制脚本带来的麻烦。
- 被管理进程作为supervisor的子进程,当子进程挂掉的时候,父进程可以准确获取子进程挂掉的信息,所以当然也就可以对挂掉的子进程进行自动重启操作,当然重启还是不重启,还要看你的配置文件里面有没有设置autostart=true。
supervisor管理的进程、进程组信息,全部都写在一个ini格式的文件里。而且我们管理supervisor的时候的可以在本地进行管理,也可以远程管理,而且supervisor提供了一个web界面,我们可以在web界面上监控、管理进程。
2、精准
使用supervisor监控子进程,得到的子进程状态无疑是准确的。
3、进程组
supervisor可以对进程组进行统一管理,也就是说我们可以把需要管理的进程写到一个组里面,然后把这个组作为一个对象进行管理,如启动、停止、重启等操作。而在linux系统上是没有这种功能的,我们想要停止一个进程,只能一个一个的去停止,要么就自己写个脚本去批量停止。
大家应该都知道linux的进程,特别是监听在1024端口之下的进程,一般用户大多数情况下是不能对其进行控制的。想要控制的话,必须要有root权限,而supervisor提供了一个功能,可以为supervisord或者每个子进程,设置一个非root的user,这个user就可以管理它对应的进程了。
supervisor的结构
supervisor主要由Supervisord、Supervisorctl、Web server和XML-RPC interface组成。
- Supervisord:负责管理进程的server,它会根据配置文件创建指定数量的应用程序的子进程,管理子进程的整个生命周期,对挂掉的进程重启,对进程变化发送事件通知等。
- Supervisorctl:负责管理进程的client,用户通过命令行发送消息给supervisord,可以查看进程状态,加载配置文件,启动停止进程等。
- Web server:supervisor提供了web server功能,可通过web远程控制进程。
- XML-RPC interface: 提供XML-RPC服务来对子进程进行管理和监控。
安装部署
由于我使用的服务器是Macmini,在Mac上安装supervisor可以使用brew:
代码语言:javascript复制brew install supervisor
使用
代码语言:javascript复制执行 supervisorctl 进入supervisor的命令行交互界面 > status # 查看程序状态 > stop program_name # 关闭 program_name 程序 > start program_name # 启动 program_name 程序 > restart program_name # 重启 program_name 程序 > reread # 读取有更新(增加)的配置文件,不会启动新添加的程序,也不会重启任何程序 > reload # 载入最新的配置文件,停止原有的进程并按照新的配置启动 > update # 重启配置文件修改过的程序,配置没有改动的进程不会收到影响而重启
开启 web 管理
文章头图就是supervisor的web管理页面。
代码语言:javascript复制vi /usr/local/etc/supervisord.ini# 将下面注释去掉 [inet_http_server] ; inet (TCP) server disabled by default port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface) username=root ; (default is no username (open server)) password=root ; (default is no password (open server))# 重启服务 $ brew services restart supervisor
进程管理
配置supervisord可以查看supervisord.ini的最后一行配置:
代码语言:javascript复制vim /usr/local/etc/supervisord.ini# [include] # files = /usr/local/etc/supervisor.d/*.ini
可以把配置文件写到/usr/local/etc/supervisor.d/目录下,只要以.ini后缀结尾就行,就拿appium server来说:
代码语言:javascript复制vi appium.ini[program:appium] directory=/Users/xxxxcommand=/usr/local/bin/appium --address 127.0.0.1 --port 4723 --log "log_path" --log-timestamp --local-timezone --session-overridenumprocs=1numprocs_start=0priority=999autostart=trueautorestart=truestartsecs=3startretries=3exitcodes=0,2stopwaitsecs=60user=rootenvironment=PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:stopasgroup=truekillasgroup=trueredirect_stderr=truestdout_logfile=/var/log/appium_out.logstderr_logfile=/var/log/appium_err.logstdout_logfile_maxbytes=100MBstdout_logfile_backups=10stderr_logfile_maxbytes=100MBstderr_logfile_backups=10loglevel=debug
这里有一点需要注意的是,当我们需要管理的进程中有用到adb等命令的时候要在上面配置文件中的environment这里配置一下系统的环境变量。
接下来重新载入配置文件,就可以通过上面的web管理页面管理进程了:
代码语言:javascript复制supervisorctl reload