ngx ------ngx_cache_manager_process_cycle
static void
ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data)
{-----------------------------------
/*
* Set correct process type since closing listening Unix domain socket
* in a master process also removes the Unix domain socket file.
*/
ngx_process = NGX_PROCESS_HELPER; ngx_close_listening_sockets(cycle); /* Set a moderate number of connections for a helper process. */
cycle->connection_n = 512;
//work 进程 初始化
ngx_worker_process_init(cycle, -1); ngx_memzero(&ev, sizeof(ngx_event_t));
ev.handler = ctx->handler; //ngx_cache_manager_process_handler ngx_cache_loader_process_handler
ev.data = ident;
ev.log = cycle->log;
ident[3] = (void *) -1; ngx_use_accept_mutex = 0; ngx_setproctitle(ctx->name); ngx_add_timer(&ev, ctx->delay, NGX_FUNC_LINE); //ctx->dealy秒执行ctx->handler; for ( ;; ) { if (ngx_terminate || ngx_quit) {
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
exit(0);
} if (ngx_reopen) {
ngx_reopen = 0;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
ngx_reopen_files(cycle, -1);
}
------------//work 进程 循环处理 fd io 以及 timer------------------------------------------------------
ngx_process_events_and_timers(cycle);
}
}
void
ngx_process_events_and_timers(ngx_cycle_t *cycle)
{
ngx_uint_t flags;
ngx_msec_t timer, delta; ---------------------------------------
ngx_use_accept_mutex = 1;
//ngx_use_accept_mutex表示是否需要通过对accept加锁来解决惊群问题。当nginx worker进程数>1时且配置文件中打开accept_mutex时,这个标志置为1
if (ngx_use_accept_mutex) {
/*
ngx_accept_disabled表示此时满负荷,没必要再处理新连接了,我们在nginx.conf曾经配置了每一个nginx worker进程能够处理的最大连接数,
当达到最大数的7/8时,ngx_accept_disabled为正,说明本nginx worker进程非常繁忙,将不再去处理新连接,这也是个简单的负载均衡
在当前使用的连接到达总连接数的7/8时,就不会再处理新连接了,同时,在每次调用process_events时都会将ngx_accept_disabled减1,
直到ngx_accept_disabled降到总连接数的7/8以下时,才会调用ngx_trylock_accept_mutex试图去处理新连接事件 如果ngx_accept_disabled大于了0,就表示该进程接受的
连接过多,因此就放弃一次争抢accept mutex的机会,同时将 自己减1。然后,继续处理已有连接上的事件。Nginx就借用 此变量实现了进程关于连接的基本负载均衡。
*/
if (ngx_accept_disabled > 0) { //为正说明可用连接用了超过八分之七,则让其他的进程在下面的else中来accept
ngx_accept_disabled--; } else {
/*
如果ngx_trylock_accept_mutex方法没有获取到锁,接下来调用事件驱动模块的process_events方法时只能处理已有的连接上的事件;
如果获取到了锁,调用process_events方法时就会既处理已有连接上的事件,也处理新连接的事件。 如何用锁来避免惊群?
尝试锁accept mutex,只有成功获取锁的进程,才会将listen
套接字放入epoll中。因此,这就保证了只有一个进程拥有
监听套接口,故所有进程阻塞在epoll_wait时,不会出现惊群现象。
这里的ngx_trylock_accept_mutex函数中,如果顺利的获取了锁,那么它会将监听端口注册到当前worker进程的epoll当中 获得accept锁,多个worker仅有一个可以得到这把锁。获得锁不是阻塞过程,都是立刻返回,获取成功的话ngx_accept_mutex_held被置为1。
拿到锁,意味着监听句柄被放到本进程的epoll中了,如果没有拿到锁,则监听句柄会被从epoll中取出。
*/
/*
如果ngx_use_accept_mutex为0也就是未开启accept_mutex锁,则在ngx_worker_process_init->ngx_event_process_init 中把accept连接读事件统计到epoll中
否则在ngx_process_events_and_timers->ngx_process_events_and_timers->ngx_trylock_accept_mutex中把accept连接读事件统计到epoll中;
---------------------------尝试锁accept mutex,只有成功获取锁的进程,才会将listen 套接字放入epoll中。因此,这就保证了只有一个进程拥有 监听套接口,故所有进程阻塞在epoll_wait时,不会出现惊群现象。
*/
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { //不管是获取到锁还是没获取到锁都是返回NGX_OK
return;
} /*
拿到锁的话,置flag为NGX_POST_EVENTS,这意味着ngx_process_events函数中,任何事件都将延后处理,会把accept事件都放到
ngx_posted_accept_events链表中,epollin|epollout事件都放到ngx_posted_events链表中 ---
获取锁的进程,将添加一个NGX_POST_EVENTS标志, 此标志的作用是将所有产生的事件放入一个队列中, 等释放锁后,再慢慢来处理事件。
因为,处理事件可能 会很耗时,如果不先释放锁再处理的话,该进程就长 时间霸占了锁,导致其他进程无法获取锁,这样accept 的效率就低了。
*/
if (ngx_accept_mutex_held) {
flags |= NGX_POST_EVENTS; } else {
/*
拿不到锁,也就不会处理监听的句柄,这个timer实际是传给epoll_wait的超时时间,修改为最大ngx_accept_mutex_delay意味
着epoll_wait更短的超时返回,以免新连接长时间没有得到处理
*/
if (timer == NGX_TIMER_INFINITE
|| timer > ngx_accept_mutex_delay)
{ //如果没获取到锁,则延迟这么多ms重新获取说,继续循环,也就是技术锁被其他进程获得,本进程最多在epoll_wait中睡眠0.5s,然后返回
timer = ngx_accept_mutex_delay; //保证这么多时间超时的时候出发epoll_wait返回,从而可以更新内存时间
}
}
}
} delta = ngx_current_msec; /*
1.如果进程获的锁,并获取到锁,则该进程在epoll事件发生后会触发返回,然后得到对应的事件handler,加入延迟队列中,然后释放锁,然
后在执行对应handler,同时更新时间,判断该进程对应的红黑树中是否有定时器超时,
2.如果没有获取到锁,则默认传给epoll_wait的超时时间是0.5s,表示过0.5s继续获取锁,0.5s超时后,会跟新当前时间,同时判断是否有过期的
定时器,有则指向对应的定时器函数
*/ /*
1.ngx_event_s可以是普通的epoll读写事件(参考ngx_event_connect_peer->ngx_add_conn或者ngx_add_event),通过读写事件触发 2.也可以是普通定时器事件(参考ngx_cache_manager_process_handler->ngx_add_timer(ngx_event_add_timer)),通过ngx_process_events_and_timers中的
epoll_wait返回,可以是读写事件触发返回,也可能是因为没获取到共享锁,从而等待0.5s返回重新获取锁来跟新事件并执行超时事件来跟新事件并且判断定
时器链表中的超时事件,超时则执行从而指向event的handler,然后进一步指向对应r或者u的->write_event_handler read_event_handler 3.也可以是利用定时器expirt实现的读写事件(参考ngx_http_set_write_handler->ngx_add_timer(ngx_event_add_timer)),触发过程见2,只是在handler中不会执行write_event_handler read_event_handler
*/ //linux下,普通网络套接字调用ngx_epoll_process_events函数开始处理,异步文件i/o设置事件的回调方法为ngx_epoll_eventfd_handler
(void) ngx_process_events(cycle, timer, flags); delta = ngx_current_msec - delta; //(void) ngx_process_events(cycle, timer, flags)中epoll等待事件触发过程花费的时间 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "epoll_wait timer range(delta): %M", delta); //当感应到来自于客户端的accept事件,epoll_wait返回后加入到post队列,执行完所有accpet连接事件后,立马释放ngx_accept_mutex锁,这样其他进程就可以立马获得锁accept客户端连接
//* 这里完成对队列中的accept事件的处理,实际就是调用 ngx_event_accept函数来获取一个新的连接,然后放入 epoll中。
ngx_event_process_posted(cycle, &ngx_posted_accept_events); //一般执行ngx_event_accept //释放锁后再处理下面的EPOLLIN EPOLLOUT请求 --------------所有accept事件处理完成,如果拥有锁的话,就赶紧释放了。 其他进程还等着抢了。
if (ngx_accept_mutex_held) {
ngx_shmtx_unlock(&ngx_accept_mutex);
} if (delta) {
ngx_event_expire_timers(); //处理红黑树队列中的超时事件handler
} /*
然后再处理正常的数据读写请求。因为这些请求耗时久,所以在ngx_process_events里NGX_POST_EVENTS标志将事件都放入ngx_posted_events
链表中,延迟到锁释放了再处理。
*/
ngx_event_process_posted(cycle, &ngx_posted_events); //普通读写事件放在释放ngx_accept_mutex锁后执行,提高客户端accept性能
}
https://yikun.github.io/2014/03/26/nginxevent/
ngx ------ngx_cache_manager_process_cycle的更多相关文章
- ngx.lua中遇到的小问题2
用lua+drizzle在数据库中插入数据失败(不能访问数据库) 后面发现原来是nginx配置文件中的drizzle模块部分最后多了一行 content_by_lua 'ngx.say(" ...
- ngx.lua中遇到的小问题
作者: 胡 志伟 分类: ngx_lua, 开发代码 发布时间: 2013-09-26 08:40 ė 6评论关闭 在使用ngx.redirect 到一个新的地址时,错误日志提示: lua entry ...
- ngx.re.match使用示例
s='...12ab345cde...' r, e = ngx.re.match(s,'(\\d+)([a-z]+)(?<num>\\d+)(?<word>[a-z]+)') ...
- ngx.re.match
ngx.re.match syntax: captures, err = ngx.re.match(subject, regex, options?, ctx?, res_table?) contex ...
- ngx.ctx
https://github.com/openresty/lua-nginx-module#ngxctx 要点 生命周期和请求一致 每个请求的ngx.ctx是相互独立的,包括ngx.location. ...
- 由ngx.say和ngx.print差异引发的血案
Jan 16, 2018openresty点击 最近上线一个项目,利用openresty在前面做反向代理,部分地址通过lua的http请求后端接口进行返回,在线下测试都没问题,公司预发灰度测试都通过了 ...
- post请求体过大导致ngx.req.get_post_args()取不到参数体的问题
http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size 该地址对于client_body_buf ...
- ngx_lua_API 指令详解(六)ngx.thread.spawn、ngx.thread.wait、ngx.thread.kill介绍
摘要:通过lua-nginx-module中的ngx.thread同时执行多个任务. ngx_lua中访问多个第三方服务 ngx_lua中提供了ngx.socket API,可以方便的访问第三方网络服 ...
- ngx_lua_API 指令详解(四)ngx.exec指令
https://github.com/openresty/lua-nginx-module#ngxexec 参照:http://blog.csdn.net/weiyuefei/article/deta ...
随机推荐
- Java工程师应该掌握的知识,按重要程度排出六个阶段如下
第一阶段:计算机组成原理.数据结构和算法.网络通信原理.操作系统原理: 第二阶段:Java基础.JVM内存模型和GC算法.JVM性能调优.JDK工具.设计模式: 第三阶段:Spring系列.Myb ...
- Spark核心组件通识概览
在说Spark之前,笔者在这里向对Spark感兴趣的小伙伴们建议,想要了解.学习.使用好Spark,Spark的官网是一个很好的工具,几乎能满足你大部分需求.同时,建议学习一下scala语言,主要基于 ...
- lumen单元测试
phpunit --filter testInfo tests/UserTest.php UserTest.php <?php use Laravel\Lumen\Testing\Databa ...
- UML类图还不懂?来看看这版乡村爱情类图,一把学会!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.码场心得
- <noscript> 实例
实例 JavaScript <body> ... ... <script type="text/javascript"> <!‐‐ ...
- CSDN的Markdown编辑器实用技巧(傻瓜式教程)
markdown编辑器被很多人声称是可以取代word的文字编辑器,其优点我们在这就不再过多赘述了,但对于一些初次接触的人来说,或多或少都有还些不适应,其主要原因在于一些常见的功能突然不知道怎么实现,所 ...
- Nacos注册中心使用
创建两个工程,一个是nacos-provider, 另一个是naocos-consumer: 添加nacos-provider的依赖 <parent> <groupId>org ...
- 自动识别PC端、移动端,并跳转
PC端和移动端代码是分开的,各有一套代码的情况下: 在PC端的HTML文件head标签中间添加一段自动识别移动端的JavaScript代码: <script type="text/ja ...
- Lambda表达式(二)
Lambda表达式是给函数式接口(SAM接口)的变量或形参赋值的表达式.Lambda表达式替代了原来使用匿名内部类的对象给函数式接口(SAM接口)的变量或形参赋值的形式. 匿名内部类:实现了这个接口, ...
- symfony3.4 配置高效的邮箱swiftmailer插件
网站经常需要邮件发送,symfony里面swiftmailerBundle是一个非常并且稳定的发送邮件的第三方插件. 我们来看一下symfony里面的邮件怎么配置. 第一步我们先下载bundle: c ...