php-cgi 重启,自动监测和重启 FastCGI 服务
昨天有個(gè)服務(wù)器出了點(diǎn)小問(wèn)題,PHP FastCGI 進(jìn)程無(wú)緣無(wú)故就死在那里了,造成 Nginx 不能和 FastCGI 通信,不能解析 PHP 頁(yè)面,只能看到 Nginx 的 默認(rèn) HTML 頁(yè)面。登錄到服務(wù)器檢查日志也沒(méi)有找到原因,重啟 FastCGI 后恢復(fù)正常。服務(wù)器上裝了 monit,如果服務(wù)關(guān)閉的話會(huì)自動(dòng)重啟,但是這里 FastCGI 服務(wù)并沒(méi)有關(guān)閉,只不過(guò)由于某種原因不能和 Nginx 通信,所以 monit 誤認(rèn)為 FastCGI 運(yùn)行正常沒(méi)有執(zhí)行重啟 FastCGI 的命令。
今天寫了一個(gè) Python 腳本用來(lái)后臺(tái)監(jiān)測(cè) nginx 的日志,如果在日志里發(fā)現(xiàn) 111: Connection refused 或者 104: Connection reset by peer 等錯(cuò)誤就 kill 掉所有 php-cgi 進(jìn)程后重啟服務(wù)。程序有幾個(gè)地方需要說(shuō)明:
1、如果不先 kill 直接運(yùn)行 /etc/init.d/php-cgi restart 重啟服務(wù)有時(shí)候不管用,因?yàn)檫@時(shí)候 php-cgi 只是駐留在內(nèi)存里的死進(jìn)程而而已不能執(zhí)行任何命令,所以需要 kill 全部 php-cgi 進(jìn)程后再啟動(dòng);
2、讀 nginx 的 log 文件的時(shí)候要小心,log 文件通常很大,如果用 python 的普通讀文件函數(shù)會(huì)把整個(gè)文件讀出來(lái)后再處理,速度很慢,也會(huì)占用大量?jī)?nèi)存,所以最好用 tail 截取文件,我們只需要分析最后部分(也是最近)的記錄即可;
3、程序通過(guò) /var/run/php_cgi.pid 來(lái)判斷 PHP FastCGI 是否正在運(yùn)行,通過(guò) /var/log/nginx/error.log 來(lái)判斷 Nginx/FastCGI 是否工作正常,每600秒檢查一次,如果工作不正常 sleep 2秒后重啟 php-cgi;
4、本程序可擴(kuò)展到重啟其他服務(wù),比如通過(guò) /var/run/lighttpd.pid 來(lái)判斷 lighttpd 是否需要重啟;
5、程序中 daemonize 函數(shù)來(lái)自 Python Cookbook(O’Reilly ) 一書。
程序使用
拷貝下面代碼做一定修改以后保存為 checkphpcgi,增加文件可執(zhí)行權(quán)限后用 root 運(yùn)行程序:
# chmod +x checkphpcgi
# ./checkphpcgi
usage: ./checkphpcgi start|stop|restart
# ./checkphpcgi start
如果想要停止程序:
# ./checkphpcgi stop
程序代碼
#!/usr/bin/python
# Monitoring PHP/FastCGI processes, restart FastCGI if they:
# 1. crashed or
# 2. simply cannot communicate with Nginx
#
# written by http://www.vpsee.com
import sys, os, time
from signal import SIGTERM
pidfile = '/var/run/checkphpcgi.pid'
phpcgi_pidfile = '/var/run/php_cgi.pid'
phpcgi_command = '/etc/init.d/php_cgi restart'
nginx_logfile = '/var/log/nginx/error.log'
kill_phpcgi = 'killall -9 php-cgi'
def main():
argc = len(sys.argv)
if argc != 2:
print "usage: ./checkphpcgi start|stop|restart"
sys.exit(0)
action = sys.argv[1]
if action == 'start':
start()
elif action == 'stop':
stop()
elif action == 'restart':
stop()
start()
def start():
daemonize()
while True:
try:
f = file(phpcgi_pidfile, 'r')
pid = int(f.read().strip())
f.close()
except IOError:
pid = None
if not pid:
os.system(phpcgi_command)
elif pid > 0:
log = '/usr/bin/tail ' + nginx_logfile + ' > /tmp/nginx.log'
os.system(log)
f = file('/tmp/nginx.log')
text = f.read()
if text.find("111: Connection refused") or text.find("104: Connection reset by peer"):
os.system(kill_phpcgi)
time.sleep(2)
os.system(phpcgi_command)
f.close
os.remove('/tmp/nginx.log')
time.sleep(600)
def stop():
try:
f = file(pidfile, 'r')
pid = int(f.read().strip())
f.close()
except IOError:
pid = None
return
try:
os.kill(pid, SIGTERM)
os.remove(pidfile)
except OSError, err:
sys.stderr.write("not found checkphpcgi\n")
def daemonize(stdin = '/dev/null', stdout = 'dev/null', stderr='/dev/null'):
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError, e:
sys.stderr.write("fork failed\n")
sys.exit(1)
os.chdir("/")
os.umask(0)
os.setsid()
try:
pid = os.fork()
if pid > 0:
sys.exit(0)
except OSError, e:
sys.stderr.write("fork failed\n")
sys.exit(1)
sys.stdout.flush()
sys.stderr.flush()
si = file(stdin, 'r')
so = file(stdout, 'a+')
se = file(stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
f = open(pidfile, "w")
f.write("%d" % os.getpid())
f.close()
if __name__=="__main__":
main()
總結(jié)
以上是生活随笔為你收集整理的php-cgi 重启,自动监测和重启 FastCGI 服务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《日长》第六句是什么
- 下一篇: centos 下安装mysql,linu