• Linux监控重要进程的实现方法


    Linux监控重要进程的实现方法

    不管后台服务程序写的多么健壮,还是可能会出现core dump等程序异常退出的情况,但是一般情况下需要在无

    人为干预情况下,能够自动重新启动,保证服务进程能够服务用户。这时就需要一个监控程序来实现能够让服务进程自动重新启动。查阅相关资料及尝试一些方法之后,总结linux系统监控重要进程的实现方法:脚本检测和子进程替换。

    1、脚本检测 (1) 基本思路: 通过shell命令(ps -e | grep "$1" | grep -v "grep" | wc -l) 获取 $1 ($1 代表进程的名字)的进程数,脚本根据进程数来决定下一步的操作。通过一个死循环,每隔几秒检查一次系统中的指定程序的进程数,这里也可使用crontab来实现。 (2) 具体实现过程的代码如下: [ supervisor.sh ]

    1. #! /bin/sh  
    2. # supervisor process   
    3.   
    4. LOG_FILE=/var/log/supervisor_sh.log  
    5.   
    6. # log function   
    7. function log() {  
    8.     local t=$(date +"%F %X")  
    9.     echo "[ $t ] $0 : $1 " >> ${LOG_FILE}  
    10. }  
    11.   
    12. # check process number   
    13. # $1 : process name   
    14. function check_process() {  
    15.     if [ -z $1 ]; then  
    16.         log "Input parameter is empty."  
    17.         return 0       
    18.     fi  
    19.       
    20.     p_num=$(ps -e | grep "$1" | grep -v "grep" | wc -l)  
    21.     log "p_num = $p_num"   
    22.     echo $p_num  
    23. }  
    24.   
    25. # supervisor process   
    26. while [ 1 ]  
    27. do   
    28.     declare -i ch_num  
    29.     p_name="apache2"  
    30.     ch_num=$(check_process $p_name)  
    31.     if [ $ch_num -eq 0 ]; then  
    32.         killall $p_name  
    33.         service $p_name start    
    34.     fi  
    35.     sleep 3   
    36. done  
    #! /bin/sh
    # supervisor process 
    
    LOG_FILE=/var/log/supervisor_sh.log
    
    # log function 
    function log() {
    	local t=$(date +"%F %X")
    	echo "[ $t ] $0 : $1 " >> ${LOG_FILE}
    }
    
    # check process number 
    # $1 : process name 
    function check_process() {
    	if [ -z $1 ]; then
    		log "Input parameter is empty."
    		return 0	 
    	fi
    	
    	p_num=$(ps -e | grep "$1" | grep -v "grep" | wc -l)
    	log "p_num = $p_num" 
    	echo $p_num
    }
    
    # supervisor process 
    while [ 1 ]
    do 
    	declare -i ch_num
    	p_name="apache2"
    	ch_num=$(check_process $p_name)
    	if [ $ch_num -eq 0 ]; then
    		killall $p_name
    		service $p_name start  
    	fi
    	sleep 3 
    done

    2、子进程替换 (1) 基本思路:  a. 使用fork函数创建一个新的进程,在进程表中创建一个新的表项,而创建者(即父进程)按原来的流程继续执行,子进程执行自己的控制流程 b. 运用execv函数把当前进程替换为一个新的进程,新进程由path或file参数指定,可以使用execv函数将程序的执行从一个程序切换到另一个程序 c. 当fork启动一个子进程时,子进程就有了它自己的生命周期并将独立运行,此时可以在父进程中调用wait函数让父进程等待子进程的结束 (2) 基本的实现步骤:  a. 首先使用fork系统调用,创建子进程 b. 在子进程中使用execv函数,执行需要自动重启的程序 c. 在父进程中执行wait函数等待子进程的结束,然后重新创建一个新的子进程 (3) 具体实现的代码如下: supervisor.c

    1. /** 
    2.  * 
    3.  * supervisor  
    4.  * 
    5.  * date: 2016-08-10  
    6.  *  
    7.  */  
    8.   
    9. #include <stdio.h>  
    10. #include <unistd.h>  
    11. #include <errno.h>  
    12. #include <string.h>  
    13. #include <sys/types.h>  
    14. #include <sys/wait.h>  
    15. #include <stdlib.h>  
    16. #include <time.h>  
    17.   
    18. #define LOG_FILE "/var/log/supervisor.log"  
    19.   
    20. void s_log(char *text) {  
    21.     time_t      t;  
    22.     struct tm  *tm;  
    23.     char *log_file;  
    24.     FILE *fp_log;  
    25.     char date[128];  
    26.       
    27.     log_file = LOG_FILE;  
    28.     fp_log = fopen(log_file, "a+");  
    29.     if (NULL == fp_log) {  
    30.         fprintf(stderr, "Could not open logfile '%s' for writing ", log_file);  
    31.     }  
    32.       
    33.     time(&t);  
    34.     tm = localtime(&t);  
    35.     strftime(date, 127, "%Y-%m-%d %H:%M:%S", tm);  
    36.       
    37.     /* write the message to stdout and/or logfile */      
    38.     fprintf(fp_log, "[%s] %s ", date, text);  
    39.     fflush(fp_log);  
    40.     fclose(fp_log);  
    41. }   
    42.   
    43. int main(int argc, char **argv) {  
    44.     int ret, i, status;  
    45.     char *child_argv[100] = {0};  
    46.     pid_t pid;  
    47.     if (argc < 2) {  
    48.         fprintf(stderr, "Usage:%s <exe_path> <args...>", argv[0]);  
    49.         return -1;  
    50.     }  
    51.       
    52.     for (i = 1; i < argc; ++i) {  
    53.         child_argv[i-1] = (char *)malloc(strlen(argv[i])+1);  
    54.         strncpy(child_argv[i-1], argv[i], strlen(argv[i]));  
    55.         //child_argv[i-1][strlen(argv[i])] = '0';  
    56.     }  
    57.       
    58.     while(1) {  
    59.         pid = fork();   
    60.         if (pid == -1) {  
    61.             fprintf(stderr, "fork() error.errno:%d error:%s", errno, strerror(errno));  
    62.             break;  
    63.         }  
    64.         if (pid == 0) {  
    65.             s_log(child_argv[0]);  
    66.             ret = execv(child_argv[0], (char **)child_argv);  
    67.             s_log("execv return");  
    68.             if (ret < 0) {  
    69.                 fprintf(stderr, "execv ret:%d errno:%d error:%s", ret, errno, strerror(errno));  
    70.                 continue;  
    71.             }  
    72.             s_log("exit child process");  
    73.             exit(0);  
    74.         }  
    75.         if (pid > 0) {  
    76.             pid = wait(&status);  
    77.             fprintf(stdout, "Child process id: %d ", pid);  
    78.             //fprintf(stdout, "wait return");  
    79.             s_log("Wait child process return");  
    80.         }  
    81.     }  
    82.       
    83.     return 0;  
    84. }  
    /**
     *
     * supervisor 
     *
     * date: 2016-08-10 
     * 
     */
    
    #include <stdio.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define LOG_FILE "/var/log/supervisor.log"
    
    void s_log(char *text) {
    	time_t      t;
    	struct tm  *tm;
    	char *log_file;
    	FILE *fp_log;
    	char date[128];
    	
    	log_file = LOG_FILE;
    	fp_log = fopen(log_file, "a+");
    	if (NULL == fp_log) {
    		fprintf(stderr, "Could not open logfile '%s' for writing
    ", log_file);
    	}
    	
    	time(&t);
    	tm = localtime(&t);
    	strftime(date, 127, "%Y-%m-%d %H:%M:%S", tm);
    	
    	/* write the message to stdout and/or logfile */	
    	fprintf(fp_log, "[%s] %s
    ", date, text);
    	fflush(fp_log);
    	fclose(fp_log);
    } 
    
    int main(int argc, char **argv) {
        int ret, i, status;
        char *child_argv[100] = {0};
        pid_t pid;
        if (argc < 2) {
    		fprintf(stderr, "Usage:%s <exe_path> <args...>", argv[0]);
    		return -1;
        }
    	
        for (i = 1; i < argc; ++i) {
            child_argv[i-1] = (char *)malloc(strlen(argv[i])+1);
            strncpy(child_argv[i-1], argv[i], strlen(argv[i]));
            //child_argv[i-1][strlen(argv[i])] = '0';
        }
    	
        while(1) {
            pid = fork(); 
            if (pid == -1) {
                fprintf(stderr, "fork() error.errno:%d error:%s", errno, strerror(errno));
    			break;
            }
            if (pid == 0) {
    			s_log(child_argv[0]);
                ret = execv(child_argv[0], (char **)child_argv);
    			s_log("execv return");
                if (ret < 0) {
                    fprintf(stderr, "execv ret:%d errno:%d error:%s", ret, errno, strerror(errno));
                    continue;
                }
    			s_log("exit child process");
                exit(0);
            }
            if (pid > 0) {
                pid = wait(&status);
    			fprintf(stdout, "Child process id: %d
    ", pid);
                //fprintf(stdout, "wait return");
    			s_log("Wait child process return");
            }
        }
    	
        return 0;
    }

    (4) 测试验证 a. 假设需要自动重启的程序为demo.c,其代码实现如下所示:

    1. /* 
    2. * demo   
    3. */  
    4.   
    5. #include <stdio.h>  
    6. #include <unistd.h>  
    7. #include <errno.h>  
    8. #include <string.h>  
    9. #include <sys/types.h>  
    10. #include <sys/wait.h>  
    11. #include <stdlib.h>  
    12. #include <time.h>  
    13.   
    14. #define LOG_FILE "/var/log/demo.log"  
    15.   
    16. void demo_log(int num) {  
    17.     time_t      t;  
    18.     struct tm  *tm;  
    19.     char *log_file;  
    20.     FILE *fp_log;  
    21.     char date[128];  
    22.       
    23.     log_file = LOG_FILE;  
    24.     fp_log = fopen(log_file, "a+");  
    25.     if (NULL == fp_log) {  
    26.         fprintf(stderr, "Could not open logfile '%s' for writing ", log_file);  
    27.     }  
    28.       
    29.     time(&t);  
    30.     tm = localtime(&t);  
    31.     strftime(date,127,"%Y-%m-%d %H:%M:%S",tm);  
    32.       
    33.     /* write the message to stdout and/or logfile */      
    34.     fprintf(fp_log, "[%s] num = %d ", date, num);  
    35.     fflush(fp_log);  
    36.     fclose(fp_log);  
    37. }   
    38.   
    39. int main(int argc, char **argv[]) {  
    40.     int num = 0;  
    41.       
    42.     while(1) {  
    43.         sleep(10);  
    44.         num++;  
    45.         demo_log(num);  
    46.     }  
    47. }  
    /*
    *
    * demo  
    *
    */
    
    #include <stdio.h>
    #include <unistd.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define LOG_FILE "/var/log/demo.log"
    
    void demo_log(int num) {
    	time_t      t;
    	struct tm  *tm;
    	char *log_file;
    	FILE *fp_log;
    	char date[128];
    	
    	log_file = LOG_FILE;
    	fp_log = fopen(log_file, "a+");
    	if (NULL == fp_log) {
    		fprintf(stderr, "Could not open logfile '%s' for writing
    ", log_file);
    	}
    	
    	time(&t);
    	tm = localtime(&t);
    	strftime(date,127,"%Y-%m-%d %H:%M:%S",tm);
    	
    	/* write the message to stdout and/or logfile */	
    	fprintf(fp_log, "[%s] num = %d
    ", date, num);
    	fflush(fp_log);
    	fclose(fp_log);
    } 
    
    int main(int argc, char **argv[]) {
    	int num = 0;
    	
    	while(1) {
    		sleep(10);
    		num++;
    		demo_log(num);
    	}
    }

    b. 测试准备和说明:

    b1. 以上相关服务程序编译后的二进制文件为: supervisor 和 demo 

    b2. 执行如下测试命令 ./supervisor ./demo  

    c. 测试的结果:

    c1. execv(progname, arg) 执行成功后,其后的代码不会执行;只有当执行错误时,才会返回 -1。原来调用execv进程的代码段会被progname应用程序的代码段替换。

    c2. 当kill掉子进程时,父进程wait函数会接收到子进程退出的信号,进而循环再启动子进程,此过程实时性非常高。

    c3. 当kill掉父进程时,子进程会被init进程接管,如果此时再kill掉子进程,则子进程会退出。

    c4. 当同时kill掉父子进程,则父子进程都会退出。

  • 相关阅读:
    rest_framework viewsets.ViewSet 的简单使用
    rest_framework django 简单使用(数据库创建数据, 覆盖数据, 其他的大同小异)
    mysql 初始 密码
    centos python No module named '_bz2'
    shell 中的 if-elif-else 注意点
    CENTOS7下安装REDIS
    centos python安装 No module named '_ctypes'
    编译nginx时struct crypt_data’没有名为‘current_salt’的成员:cd.current_salt[0] = ~salt[0];的解决方案
    centos opencv-python libSM.so.6: cannot open shared object file: No such file or directory
    mysql_config not found
  • 原文地址:https://www.cnblogs.com/zxc2man/p/8250209.html
Copyright © 2020-2023  润新知