因为hadoop集群中datanode是大量存在的,那么多机器,什么事都可能发生,最通常的大概就是进程挂掉了。所以为了省事,参考别人的代码写了这个监控进程的daemon。当然,稍加修改就可以用来监控别的必须常驻的进程。只需start,不用后面跟&或者前面加nohup。
其实很多人都对进程挂掉很头疼,没事半夜得爬起来上服务器启动进程是一件非常痛苦的事情。
每2秒监测一次进程,发现进程消失就重启进程。主要原理是fork出子进程,然后将子进程挂起,并退出父进程。其程序本身作为被监控进程的外壳程序存在。
#!/usr/bin/env python import sys, os, time, atexit, string from signal import SIGTERM class Daemon: def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'): #需要获取调试信息,改为stdin='/dev/stdin', stdout='/dev/stdout', stderr='/dev/stderr',以root身份运行。 self.stdin = stdin self.stdout = stdout self.stderr = stderr self.pidfile = pidfile def _daemonize(self): try: pid = os.fork() if pid > 0: #退出主进程 sys.exit(0) except OSError, e: sys.stderr.write('fork #1 failed: %d (%s)\n' % (e.errno, e.strerror)) sys.exit(1) os.chdir("/") os.setsid() os.umask(0) #创建子进程 try: pid = os.fork() if pid > 0: sys.exit(0) except OSError, e: sys.stderr.write('fork #2 failed: %d (%s)\n' % (e.errno, e.strerror)) sys.exit(1) #重定向文件描述符 sys.stdout.flush() sys.stderr.flush() si = file(self.stdin, 'r') so = file(self.stdout, 'a+') se = file(self.stderr, 'a+', 0) os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) #创建processid文件 atexit.register(self.delpid) pid = str(os.getpid()) file(self.pidfile,'w+').write('%s\n' % pid) def delpid(self): os.remove(self.pidfile) def start(self): #检查pid文件是否存在以探测是否存在进程 try: pf = file(self.pidfile,'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = 'pidfile %s already exist. Daemon already running?\n' sys.stderr.write(message % self.pidfile) sys.exit(1) #启动监控 self._daemonize() self._run() def stop(self): #从pid文件中获取pid try: pf = file(self.pidfile,'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: message = 'pidfile %s does not exist. Daemon not running?\n' sys.stderr.write(message % self.pidfile) return #重启不报错 #杀进程 try: while 1: os.kill(pid, SIGTERM) time.sleep(0.1) os.system('/opt/modules/hadoop/hadoop-0.20.203.0/bin/hadoop-daemon.sh stop datanode') os.system('/opt/modules/hadoop/hadoop-0.20.203.0/bin/hadoop-daemon.sh stop tasktracker') except OSError, err: err = str(err) if err.find('No such process') > 0: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: print str(err) sys.exit(1) def restart(self): self.stop() self.start() def _run(self): while True: datanode = os.popen('ps -fe | grep "java" | grep "datanode" | grep -v "grep" | wc -l').read().strip() tasktracker = os.popen('ps -fe | grep "java" | grep "tasktracker" | grep -v "grep" | wc -l').read().strip() #选出进程中含有java且含有datanode|tasktracker且不含有grep,计算出现行数。修改上面的进程监控语句以适应其他应用需求 if datanode == '0': os.system('/opt/modules/hadoop/hadoop-0.20.203.0/bin/hadoop-daemon.sh start datanode') #修改这里的启动命令 if tasktracker == '0': os.system('/opt/modules/hadoop/hadoop-0.20.203.0/bin/hadoop-daemon.sh start tasktracker') #修改这里的启动命令 time.sleep(2) #修改这里的停留时间 if __name__ == '__main__': daemon = Daemon('/tmp/watch_process.pid') if len(sys.argv) == 2: if 'start' == sys.argv[1]: daemon.start() elif 'stop' == sys.argv[1]: daemon.stop() elif 'restart' == sys.argv[1]: daemon.restart() else: print 'Unknown command' sys.exit(2) sys.exit(0) else: print 'usage: %s start|stop|restart' % sys.argv[0] sys.exit(2)
实际使用中还是比较好用的,把该程序加入到启动文件中,重启服务器,服务器重启后会自动启动其所监控的进程。用到的都是python的基本模块,不会存在依赖缺失问题。
#/bin/sh while true; do count=`ps -fe | grep "java" | grep "datanode" | grep -v "grep"` if [ "$?" != "0" ]; then /opt/modules/hadoop/hadoop-0.20.203.0/bin/hadoop-daemon.sh start datanode fi sleep 2 done
-----------------------------------
#/bin/sh while true; do count=`ps -fe | grep "java" | grep "tasktracker" | grep -v "grep"` if [ "$?" != "0" ]; then /opt/modules/hadoop/hadoop-0.20.203.0/bin/hadoop-daemon.sh start tasktracker fi sleep 2 done
其实作用是一样的,只是一个前台,一个后台。一个占用bash,一个占用python。