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 运用在延 ...
随机推荐
- redmine2.6.5 邮件配置
打开configuration.xml (路径:apps/redmine/htdocs/config/) production: email_delivery: delivery_method: :s ...
- 如何修改路由器的登录IP地址?
如何修改路由器的登录IP地址? 因为有多个路由器,为了区分不同路由器,我们可以修改它的登录IP,而且修改后,可以在连接的电脑上直观地知道所连接的是哪一台路由器 买回来的路由器,一般默认的登录地址是19 ...
- 批量远程执行shell命令工具
使用示例(使用了默认用户root,和默认端口号22): ./mooon_ssh --h=192.168.4.1,192.168.4.2 -P=password -c='cat /etc/hosts' ...
- 仿iPhone滑屏操作
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <m ...
- Tensorflow从源代码编译2
https://blog.csdn.net/qq_37674858/article/details/81095101 https://blog.csdn.net/yhily2008/article/d ...
- node express session
在express4.0版本以上,需要单独增加session模块:express-session:https://www.npmjs.com/package/express-session 具体做法是, ...
- CxGrid导出Excel时清除颜色的设置
CxGrid导出Excel时清除颜色的设置 (2011-04-25 16:33:23) 转载▼ 标签: it 分类: Delphi http://www.radxe.com/?p=170 cxgrid ...
- 【TypeScript】TypeScript 学习 3——类
在 EcmaScript 6 中,我们将会拥有原生的类,而不是像现在通过原型链来实现.使用 TypeScript 我们能提前体验这一特性. 首先来看看一个简单的例子: class Greeter { ...
- [LeetCode 总结帖]: 链表专题
链表在笔试面试中都是出镜率极高的一种数据结构. 由于链表具有结构简单,代码量较少,变化多,可以较为全面的考察应聘者的逻辑思考能力以及应变能力的特点,而备受面试官青睐. 在本节中,我将Leetcode中 ...
- C++ - explicit和volatile/const的内容
第一眼见到explicit和volatile可能会一愣一愣的觉得可能是c11或者c14新加的标识符. 其实不是这样,volatile和const两个关键字在C语言的第二个版本KR C的时候就被加入了C ...