Supervisor進程管理
在后台應用中,有時候程序進程會異常中止退出,如果沒有一個守護進程去守護這個應用進程我們就需要及時發現並重啟進程。如果每一個應用進程都寫一個自己的守護進程難免會比較麻煩,而Supervisor可以解決這種情況。Supervisor是一個python開發的類unix系統的進程管理系統。
簡介
supervisor管理進程,是通過fork/exec的方式將這些被管理的進程當作supervisor的子進程來啟動,所以我們只需要將要管理進程的可執行文件的路徑添加到supervisor的配置文件中就好了。此時被管理進程被視為supervisor的子進程,若該子進程異常中斷,則父進程可以准確的獲取子進程異常中斷的信息,通過在配置文件中設置autostart=ture,可以實現對異常中斷的子進程的自動重啟。
安裝
-
Supervisor可以使用pip安裝:
pip install supervisor
-
通過系統包管理工具安裝
CentOS:
yum install epel-release
yum install supervisor
Ubuntu:
sudo apt-get install supervisor
配置
Supervisor 是一個 C/S 模型的程序,supervisord
是 server 端,supervisorctl
是 client 端。
使用echo_supervisord_conf
可以獲得配置內容,默認配置文件在/etc/supervisord.conf
,你可以將配置文件放到自己指定的目錄下,最后啟動用-c指定配置文件路徑。
配置有如下幾個模塊:
[unix_http_server]: 這部分設置HTTP服務器監聽的UNIX domain socket
file=/var/run/supervisor/supervisor.sock 指定socket文件的路徑,supervisorctl用XML_RPC和 supervisord通信就是通過它進行
;chmod=0700 ; 設置上面socket文件權限為0700
;chown=nobody:nogroup ; 設置上面socket文件屬主和屬組
;username=user ; 使用supervisorctl連接的時候,認證的用戶,不設置默認為不需要用戶
;password=123 ; 和上面用戶對應的密碼,可使用SHA加密
;[inet_http_server] ; 偵聽在TCP上的scoket,Web服務和遠程supervisorctl都有用到,默認不開啟
;port=127.0.0.1:9001 ; 監聽端口
;username=user ; 同上的unix_http_server
;password=123 ;
[supervisord] 這個主要是定義supervisord這個服務端進程的一些參數的,必須設置
logfile=/var/log/supervisor/supervisord.log ; supervisor主進程的日志文件路徑
logfile_maxbytes=50MB ; supervisor日志文件最大值
logfile_backups=10 ; 日志文件保存的數量,用於日志輪轉;設置為0表示不限制文件數量
loglevel=info ; 日志級別,有critical, error, warn, info, debug, trace, or blather等
pidfile=/var/run/supervisord.pid ; supervisord的pid文件路徑
nodaemon=false ; 如果是true,supervisord進程將在前台運行,默認為false,也就是后台以守護進程運行
minfds=1024 ; 這個是最少系統空閑的文件描述符,低於這個值supervisor將不會啟動
minprocs=200 ; 最小可用的進程描述符數目,默認200
;umask=022 ; 進程創建文件的掩碼
;user=chrism ; (default is current user, required if root)
;identifier=supervisor ; 這個參數是supervisord的標識符,主要是給XML_RPC用的。當你有多個
supervisor的時候,而且想調用XML_RPC統一管理,就需要為每個
supervisor設置不同的標識符了
;directory=/tmp ; 這個參數是當supervisord作為守護進程運行的時候,設置這個參數的話,啟動
supervisord進程之前,會切換到這個目錄執行
;nocleanup=true ; 這個參數當為false的時候,會在supervisord進程啟動的時候,把以前子進程
產生的日志文件(路徑為AUTO的情況下)清除掉。
;childlogdir=/tmp ; 當子進程日志路徑為AUTO的時候,子進程日志文件的存放路徑。
;environment=KEY=value ; 這個是用來設置環境變量的,supervisord在linux中啟動默認繼承了linux的
環境變量,在這里可以設置supervisord進程特有的其他環境變量。
supervisord啟動子進程時,子進程會拷貝父進程的內存空間內容。 所以設置的
這些環境變量也會被子進程繼承。
;strip_ansi=false ; (strip ansi escape codes in logs; def. false)
[rpcinterface:supervisor] ; 這個選項是給XML_RPC用的,當然你如果想使用supervisord或者web server 這
個選項必須要開啟
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl] ; 這個主要是針對supervisorctl的一些配置
serverurl=unix:///var/run/supervisor/supervisor.sock ; 這個是supervisorctl本地連接supervisord的時候, 本地UNIX socket路徑,注意這個是和前面的[unix_http_server]對應。
;serverurl=http://127.0.0.1:9001 ; supervisorctl遠程連接supervisord的時候,用到的TCP socket路徑,這個 和前面的[inet_http_server]對應
;username=chris ; should be same as http_username if set
;password=123 ; should be same as http_password if set
;prompt=mysupervisor ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history ; 這個參數和shell中的history類似,我們可以用上下鍵來查找前面執行過的命令
;[program:theprogramname] ; 要管理的進程配置,theprogramname是進程名,可以配置多個program
;command=/bin/cat ; 啟動進程的命令,可帶參數,有一點需要注意的是,我們的command只能是那種在 終端運行的進程,不能是守護進程。這個想想也知道了,比如說command=service httpd start。httpd這個進程被linux的service管理了,我們的supervisor再 去啟動這個命令,這已經不是嚴格意義的子進程了。
;process_name=%(program_name)s ; 這個是進程名,如果我們下面的numprocs參數為1的話,就不用管這個參數,默認 就是上面theprogramname,如果numprocs是多個,建議給每個進程命名
;numprocs=1 ; 啟動進程的數目。當不為1時,就是進程池的概念
;directory=/tmp ; 進程運行前,會前切換到這個目錄
;umask=022 ; umask for process (default None)
;priority=999 ; 子進程啟動關閉優先級,優先級低的,最先啟動,關閉的時候最后關閉
;autostart=true ; 如果是true的話,子進程將在supervisord啟動后被自動啟動
;autorestart=true ; 這個是設置子進程掛掉后自動重啟的情況,有true、false、unexpected三個選 項,false表示無論什么情況都不會被重新啟動,如果為unexpected,只有當進 程的退出碼不在下面的exitcodes里面定義的退出碼的時候,才會被自動重啟。當 為true的時候,只要子進程掛掉,將無條件的重啟
;startsecs=10 ; number of secs prog must stay running (def. 1)
;startretries=3 ; 當進程啟動失敗后,最大嘗試啟動的次數,當超過3次后,supervisor將把此進程 的狀態置為FAIL
;exitcodes=0,2 ; 和上面的的autorestart=unexpected對應
;stopsignal=QUIT ; signal used to kill process (default TERM)進程停止信號,可以為TERM, HUP, INT, QUIT, KILL, USR1, or USR2等信號,默認為TERM。當用設定的信 號去干掉進程,退出碼會被認為是expected
;stopwaitsecs=10 ; 當我們向子進程發送stopsignal信號后,到系統返回信息給supervisord,所等 待的最大時間。 超過這個時間supervisord會向該子進程發送一個強制kill的信 號。
;user=chrism ; setuid to this UNIX account to run the program
;redirect_stderr=true ; 如果為true,則stderr的日志會被寫入stdout日志文件中
;stdout_logfile=/a/path ; 子進程的stdout的日志路徑,可以指定路徑,AUTO,none等三個選項,設置為 none的話,將沒有日志產生。設置為AUTO的話,將隨機找一個地方生成日志文 件,而且當supervisord重新啟動的時候,以前的日志文件會被清空。當 redirect_stderr=true的時候,sterr也會寫進這個日志文件
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; 設置為ture的時候,當子進程由stdout向文件描述符中寫日志的時候,將觸發 supervisord發送PROCESS_LOG_STDOUT類型的event
;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10 ; # of stderr logfile backups (default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A=1,B=2 ; 這個是該子進程的環境變量,和別的子進程是不共享的
;serverurl=AUTO ; override serverurl computation (childutils)
運行
后面第二個開始的命令可以省略“-c supervisor.conf”
supervisord -c supervisor.conf 通過配置文件啟動supervisor
supervisorctl -c supervisor.conf status 查看狀態
supervisorctl -c supervisor.conf reload 重新載入配置文件
supervisorctl -c supervisor.conf start [all]|[x] 啟動所有/指定的程序進程
supervisorctl -c supervisor.conf stop [all]|[x] 關閉所有/指定的程序進程
supervisorctl update 更新新的配置到supervisord
supervisorctl reload 重新啟動配置中的所有程序
supervisorctl start program_name 啟動某個進程(program_name=你配置中寫的程序名稱)
supervisorctl stop program_name 停止某一進程 (program_name=你配置中寫的程序名稱)
supervisorctl restart program_name 重啟某一進程 (program_name=你配置中寫的程序名稱)
supervisorctl 查看正在守護的進程
supervisorctl stop all 停止全部進程
測試demo
# 目錄結構
supervisor_demo
├── logs
├── run.py
└── supervisord.conf
# cat run.py
# -*- coding:utf-8 -*-
import logging
# 創建記錄器Logger #reate logger
logger_name = "example" #設置logger名字
logger = logging.getLogger(logger_name) #創建logger實例
logger.setLevel(logging.DEBUG) #設置logger默認級別
# 創建處理器Handler #create file handler
log_path = "./log.txt" #定義日志文件路徑
fh = logging.FileHandler(log_path, mode='a') #創建文件處理器(存儲到文件中,模式為a追加)
fh.setLevel(logging.WARN) #設置文件日志存儲的級別
# 這里再測試創建一個handler用於輸出到控制台
ch = logging.StreamHandler()
# 創建格式化器Formatter #create formatter
fmt = "%(asctime)-15s %(levelname)s %(name)s %(filename)s %(lineno)d %(process)d %(message)s"
datefmt = "%a %d %b %Y %H:%M:%S" #不使用datefmt也沒問題
formatter = logging.Formatter(fmt, datefmt) #不使用datefmt設置datefmt=None
# logger對象可以添加多個Handler對象 #add handler and formatter to logger
fh.setFormatter(formatter)
logger.addHandler(fh)
ch.setFormatter(formatter)
logger.addHandler(ch)
if __name__ == "__main__":
import time
while True:
logger.debug('debug message')
logger.info('info message')
logger.warn('warn message')
logger.error('error message')
logger.critical('critical message')
logger.critical('critical end !!!')
time.sleep(20)
print('one time run over')
print('continue')
# cat supervisor.conf
[unix_http_server]
file=/var/run/supervisor/supervisor.sock ; (the path to the socket file)
[inet_http_server] ; inet (TCP) server disabled by default
port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface)
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
logfile_backups=10 ; (num of main logfile rotation backups;default 10)
loglevel=info ; (log level;default info; others: debug,warn,trace)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
nodaemon=false ; (start in foreground if true;default false)
minfds=1024 ; (min. avail startup file descriptors;default 1024)
minprocs=200 ; (min. avail process descriptors;default 200)
user=root ; (default is current user, required if root)
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
;serverurl=unix:///var/run/supervisor/supervisor.sock ; use a unix:// URL for a unix socket
serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
[program:my_supervisor_test]
command=/usr/bin/python run.py ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1 ; number of processes copies to start (def 1)
directory=/soft/supervisor_demo ; directory to cwd to before exec (def no cwd)
;umask=022 ; umask for process (default None)
;priority=999 ; the relative start priority (default 999)
;autostart=true ; start at supervisord start (default: true)
autorestart=true ; retstart at unexpected quit (default: true)
startsecs=10 ; number of secs prog must stay running (def. 1)
startretries=3 ; max # of serial start failures (default 3)
;exitcodes=0,2 ; 'expected' exit codes for process (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;user=chrism ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/soft/supervisor_demo/logs/outlog.txt ; stdout log path, NONE for none; default AUTO
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10)
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
;stderr_logfile=/soft/supervisor_demo/logs/error.txt ; stderr log path, NONE for none; default AUTO
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
;stderr_logfile_backups=10 ; # of stderr logfile backups (default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A=1,B=2 ; process environment additions (def no adds)
;serverurl=AUTO ; override serverurl computation (childutils)
[include]
files = supervisord.d/*.ini
# 啟動
# supervisord -c supervisor.conf