在後臺應用中,有時候程序進程會異常停止退出,若是沒有一個守護進程去守護這個應用進程咱們就須要及時發現並重啓進程。若是每個應用進程都寫一個本身的守護進程不免會比較麻煩,而Supervisor能夠解決這種狀況。Supervisor是一個python開發的類unix系統的進程管理系統。python
supervisor管理進程,是經過fork/exec的方式將這些被管理的進程看成supervisor的子進程來啓動,因此咱們只須要將要管理進程的可執行文件的路徑添加到supervisor的配置文件中就行了。此時被管理進程被視爲supervisor的子進程,若該子進程異常中斷,則父進程能夠準確的獲取子進程異常中斷的信息,經過在配置文件中設置autostart=ture,能夠實現對異常中斷的子進程的自動重啓。linux
Supervisor可使用pip安裝:web
pip install supervisor
shell
經過系統包管理工具安裝服務器
CentOS:dom
yum install epel-release
socket
yum install supervisor
ide
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 中止所有進程
# 目錄結構 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