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 * ) / ) : (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;
php-fpm定时器的更多相关文章
- 纯PHP实现定时器任务(Timer)
纯PHP实现定时器任务(Timer) 定时器任务,在WEB应用比较常见,如何使用PHP实现定时器任务,大致有两种方案:1)使用Crontab命令,写一个shell脚本,在脚本中调用PHP文件,然后 ...
- PHP-max_execution_time与fpm.request_terminate_timeout介绍
前段时间一位同事跟我说php脚本超时时间以fpm配置优先.经过自己测试后,其实不然,前面的观点只是在某些情况下成立. php脚本超时时间可以在php.ini的max_execution_time和fp ...
- Fpm启动机制及流程分析———详细
FPM(FastCGI Process Manager)是PHP FastCGI运行模式的一个进程管理器,从它的定义可以看出,FPM的核心功能是进程管理,那么它用来管理什么进程呢?这个问题就需要从Fa ...
- Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用
OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...
- 微信小程序中利用时间选择器和js无计算实现定时器(将字符串或秒数转换成倒计时)
转载注明出处 改成了一个单独的js文件,并修改代码增加了通用性,点击这里查看 今天写小程序,有一个需求就是用户选择时间,然后我这边就要开始倒计时. 因为小程序的限制,所以直接选用时间选择器作为选择定时 ...
- [Java定时器]用Spring Task实现一个简单的定时器.
今天做一个项目的的时候需要用到定时器功能.具体需求是: 每个月一号触发一次某个类中的方法去拉取别人的接口获取上一个月份车险过期的用户.如若转载请附上原文链接:http://www.cnblogs.co ...
- Node+fs+定时器(node-schedule)+MySql
目标:将本人写博客时候的截图保存到桌面的图片 执行保存到指定文件进行整理 并写入数据库 先看最终的目录结构: package.json文件: { "name": "zqz ...
- 深入理解定时器系列第一篇——理解setTimeout和setInterval
× 目录 [1]setTimeout [2]setInterval [3]运行机制[4]作用[5]应用 前面的话 很长时间以来,定时器一直是javascript动画的核心技术.但是,关于定时器,人们通 ...
- 前端开发:setTimeout与setInterval 定时器与异步循环数组
前端开发:setTimeout与setInterval 定时器与异步循环数组 前言: 开通博客园三个月以来,随笔记录了工作中遇到的大大小小的难题,也看过无数篇令人启发的文章,我觉得这样的环境是极好的, ...
- 转载---javascript 定时器总结
转载:http://www.jb51.net/article/40193.htm JS里设定延时: 使用SetInterval和设定延时函数setTimeout 很类似.setTimeout 运用在延 ...
随机推荐
- linux下 C程序 参数和内存
#include <stdio.h> int main(argc, argv) int argc;char *argv[]; { printf("argc=%d \n&q ...
- 2018.07.29~30 uoj#170. Picks loves segment tree VIII(线段树)
传送门 线段树好题. 维护区间取两种最值,区间加,求区间两种历史最值,区间最小值. 自己的写法调了一个晚上+一个上午+一个下午+一个晚上并没有调出来,90" role="prese ...
- StackView实现叠加在一起的图片循环移动像循环队列一样
MainActivity.java public class MainActivity extends Activity { StackView stackView; int[] imageIds ...
- ArcGIS Desktop Python add-ins 插件类型
Python可以在ArcGIS 桌面程序中创建如下的插件类型: 插件类型 描述 按钮(button) 是一个简单功能定制形式,可以在点击情况下执行一些业务逻辑.它会执行一个或一系列的动作.按钮可以放在 ...
- 201709012工作日记--一台电脑创建两个Github账户上传代码
1. 在一台主机上面使用多个GitHub账号 有时候,我们需要将个人账号和公司账号区分,这时候我们就会需要在一台电脑上使用2个不同的git账号. 2. 上传文件 http://blog.csdn.ne ...
- 《Python3网络爬虫开发实战》PDF+源代码+《精通Python爬虫框架Scrapy》中英文PDF源代码
下载:https://pan.baidu.com/s/1oejHek3Vmu0ZYvp4w9ZLsw <Python 3网络爬虫开发实战>中文PDF+源代码 下载:https://pan. ...
- 菜鸟——springboot+mybatis+maven
网上找了很多资料,学习如何搭建springboot,由于刚刚接触springboot,不是很熟练,通过参考网上别人搭建的例子,自己也搭建了一个简单的springboot+mybaits+maven 网 ...
- 集合(四)HashMap
之前的List,讲了ArrayList.LinkedList,最后讲到了CopyOnWriteArrayList,就前两者而言,反映的是两种思想: (1)ArrayList以数组形式实现,顺序插入.查 ...
- [label][politic-video]李锡锟的政治学视频下载链接
李锡锟政治学 1.http://r15---sn-p5qlsn7y.googlevideo.com/videoplayback?initcwndbps=1471000&signature=09 ...
- Grafana安装及配置
安装 sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-2.1.3-1.x86_64.rpm 启动 sudo se ...