zoukankan      html  css  js  c++  java
  • php-fpm定时器

    php-fpm有三种定时器

    1)主进程接收到用户的信号,例如sigusr,主进程执行kill(子进程号,sigquit),的同时,设置定时器,在一个无限循环里如果当前时间 大于或等于 该定时器的过期时间,则主进程执行kill(子进程号,sigterm);

    2)对于在php-fpm里设置了request_terminate_timeout 和request_slowlog_timeout

      注:set_time_limit()和max_execution_time只影响脚本本身执行的时间。

      (这两个参数在php.ini中)任何发生在诸如使用system()的系统调用,流操作,数据库操作等的脚本执行的最大时间不包括其中.

      建立定时器是在函数fpm_event_loop中的fpm_pctl_heartbeat函数,调用前有个判断条件 fpm_globals.heartbeat需要大于0

    在解析php-fpm.conf文件中,fpm_globals.heartbeat最终为request_terminate_timeout和request_slowlog_timeout较小的一个

    static int fpm_conf_process_all_pools(){
        //省略无关代码 
    
        if (wp->config->request_terminate_timeout) {
            fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_terminate_timeout * 1000) / 3) : (wp->config->request_terminate_timeout * 1000) / 3;
        }
    
        if (wp->config->request_slowlog_timeout) {
            fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_slowlog_timeout * 1000) / 3) : (wp->config->request_slowlog_timeout * 1000) / 3;
    
        }  
    }

    /* a minimum of 130ms heartbeat for pctl */

    #define FPM_PCTL_MIN_HEARTBEAT (130)

    void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
    {
        static struct fpm_event_s heartbeat;
        struct timeval now;
    
        if (fpm_globals.parent_pid != getpid()) {
            return; /* sanity check */
        }
    
        if (which == FPM_EV_TIMEOUT) {
            fpm_clock_get(&now);
            fpm_pctl_check_request_timeout(&now);
            return;
        }
    
        /* ensure heartbeat is not lower than FPM_PCTL_MIN_HEARTBEAT */      //这里又和默认的相比,取最大的
        fpm_globals.heartbeat = MAX(fpm_globals.heartbeat, FPM_PCTL_MIN_HEARTBEAT);
    
        /* first call without setting to initialize the timer */
        zlog(ZLOG_DEBUG, "heartbeat have been set up with a timeout of %dms", fpm_globals.heartbeat);
        fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_heartbeat, NULL);
        fpm_event_add(&heartbeat, fpm_globals.heartbeat);
    }

    3)对于dynamic方式的子进程,需要定时检查,例如:当空闲的子进程个数小于允许最小的空闲子进程个数时,需要fork;当空闲的子进程个数大于允许的最大的空闲子进程个数时,需要kill掉

    /* 1s (in ms) heartbeat for idle server maintenance */
    #define FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT (1000)

      即每1S执行一次

      假设当前时间为10:00:00,那么超时时间为10:01:00, 在fpm_event_loop这个无限循环中,当 当前 时间 大于或等于这个超时时间时,会触发fpm_pctl_perform_idle_server_maintenance这个函数,当空闲的子进程个数小于允许最小的空闲子进程个数时,需要fork;当空闲的子进程个数大于允许的最大的空闲子进程个数时,需要kill掉,执行完函数后,假设当前时间为10:05:00,那么下一次超时时间为10:06:00,依次类推 ,参考这里

      建立定时器是在函数fpm_event_loop中的fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL)

      

    void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
    {
        static struct fpm_event_s heartbeat;
        struct timeval now;
    
        if (fpm_globals.parent_pid != getpid()) {
            return; /* sanity check */
        }
    
        if (which == FPM_EV_TIMEOUT) {
            fpm_clock_get(&now);
            if (fpm_pctl_can_spawn_children()) {
                fpm_pctl_perform_idle_server_maintenance(&now);
    
                /* if it's a child, stop here without creating the next event
                 * this event is reserved to the master process
                 */
                if (fpm_globals.is_child) {
                    return;
                }
            }
            return;
        }
    
        /* first call without setting which to initialize the timer */
        fpm_event_set_timer(&heartbeat, FPM_EV_PERSIST, &fpm_pctl_perform_idle_server_maintenance_heartbeat, NULL);
        fpm_event_add(&heartbeat, FPM_IDLE_SERVER_MAINTENANCE_HEARTBEAT);
    }

    因为是第一次调用 ,所以直接走到倒数第二,第三行, FPM_EV_TIMEOUT 为1 

    #define FPM_EV_TIMEOUT  (1 << 0)
    #define FPM_EV_READ     (1 << 1)
    #define FPM_EV_PERSIST  (1 << 2)
    #define FPM_EV_EDGE     (1 << 3)

    fpm_event_set_timer其实是个宏,
    #define fpm_event_set_timer(ev, flags, cb, arg) fpm_event_set((ev), -1, (flags), (cb), (arg))

    fpm_event_set中的fd参数传的是-1,因为是定时器,故没有文件描述符,并且调用回调函数
    得到现在当前时间,由于是每1分钟执行一次,所以超时时间是当前时间+1分钟

    int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
    {
        if (!ev || !callback || fd < -1) {
            return -1;
        }
        memset(ev, 0, sizeof(struct fpm_event_s));
        ev->fd = fd;
        ev->callback = callback;
        ev->arg = arg;
        ev->flags = flags;
        return 0;
    }
    /* }}} */
    
    int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
    {
        struct timeval now;
        struct timeval tmp;
    
        if (!ev) {
            return -1;
        }
    
        ev->index = -1;
    
        /* it's a triggered event on incoming data */
        if (ev->flags & FPM_EV_READ) {
            ev->which = FPM_EV_READ;
            if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != 0) {
                return -1;
            }
            return 0;
        }
    
        /* it's a timer event */
        ev->which = FPM_EV_TIMEOUT;
    
        fpm_clock_get(&now);
        if (frequency >= 1000) {
            tmp.tv_sec = frequency / 1000;
            tmp.tv_usec = (frequency % 1000) * 1000;
        } else {
            tmp.tv_sec = 0;
            tmp.tv_usec = frequency * 1000;
        }
        ev->frequency = tmp;
        fpm_event_set_timeout(ev, now);  //#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout);
    
        if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != 0) {
            return -1;
        }
    
        return 0;
    }
    
    
    

    将该定时器放到定时器专属的队列中

    static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
    {
        struct fpm_event_queue_s *elt;
    
        if (!queue || !ev) {
            return -1;
        }
    
        if (fpm_event_queue_isset(*queue, ev)) {
            return 0;
        }
    
        if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
            zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
            return -1;
        }
        elt->prev = NULL;
        elt->next = NULL;
        elt->ev = ev;
    
        if (*queue) {
            (*queue)->prev = elt;
            elt->next = *queue;
        }
        *queue = elt;
    
        /* ask the event module to add the fd from its own queue */ //定时器不会走到这里
        if (*queue == fpm_event_queue_fd && module->add) {
            module->add(ev);
        }
    
        return 0;    
    }
    
    

    定时器队列结构体, static struct fpm_event_queue_s *fpm_event_queue_timer = NULL; 是个全局变量

    typedef struct fpm_event_queue_s {
        struct fpm_event_queue_s *prev;
        struct fpm_event_queue_s *next;
        struct fpm_event_s *ev;
    } fpm_event_queue;





  • 相关阅读:
    在Linux下运行YY,WINE方式,主要注册表修改点及字体文件列表
    安卓so下,cmake编译系统,如何仅导出指定符号
    AutoHotKey脚本模板:初始化、配置、退出
    资源ID管理插件:VS6/VS.NET
    ListView控件,表格模式下,如何调整行高
    通过wscript运行的JS脚本,如何引入另一个JS文件
    64位编译器下,将指针转换成UINT32,不需要修改编译选项的编码方式
    视频帧双缓冲区的两个版本
    opencv、numpy中矩阵转置,矩阵内的固定位置相应的坐标变换
    CMake下,某些选项的后调整
  • 原文地址:https://www.cnblogs.com/taek/p/6398871.html
Copyright © 2011-2022 走看看