首页 技术 正文
技术 2022年11月21日
0 收藏 544 点赞 3,156 浏览 4900 个字

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 * ) / ) : (wp->config->request_terminate_timeout * ) / ;
} if (wp->config->request_slowlog_timeout) {
fpm_globals.heartbeat = fpm_globals.heartbeat ? MIN(fpm_globals.heartbeat, (wp->config->request_slowlog_timeout * ) / ) : (wp->config->request_slowlog_timeout * ) / ; }
}

/* 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 < -) {
return -;
}
memset(ev, , sizeof(struct fpm_event_s));
ev->fd = fd;
ev->callback = callback;
ev->arg = arg;
ev->flags = flags;
return ;
}
/* }}} */int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
{
struct timeval now;
struct timeval tmp; if (!ev) {
return -;
} ev->index = -; /* 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) != ) {
return -;
}
return ;
} /* it's a timer event */
ev->which = FPM_EV_TIMEOUT; fpm_clock_get(&now);
if (frequency >= ) {
tmp.tv_sec = frequency / ;
tmp.tv_usec = (frequency % ) * ;
} else {
tmp.tv_sec = ;
tmp.tv_usec = frequency * ;
}
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) != ) {
return -;
} return ;
}

将该定时器放到定时器专属的队列中
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 -;
} if (fpm_event_queue_isset(*queue, ev)) {
return ;
} if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
return -;
}
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 ;
}

定时器队列结构体, 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;

    					
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,027
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,518
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,365
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,146
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,780
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,857