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

吾爱主题 阅读:129 2024-04-05 13:53:45 评论:0

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

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

1、脚本检测

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

(2) 具体实现过程的代码如下: [ supervisor.sh ]

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #! /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 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 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 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\n" , 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\n" , 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\n" , pid);        //fprintf(stdout, "wait return");        s_log( "Wait child process return" );      }    }        return 0; }

(4) 测试验证

a. 假设需要自动重启的程序为demo.c,其代码实现如下所示:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 /* * * 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\n" , 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\n" , 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掉父子进程,则父子进程都会退出。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/lcy4599/article/details/52267517

可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

【腾讯云】云服务器产品特惠热卖中
搜索
标签列表
    关注我们

    了解等多精彩内容