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第一课!
public class Text { public static void main(String[] args) { int a=100; //赋值a=100 System.out.println ...
- 异步编程新方式async/await
一.前言 实际上对async/await并不是很陌生,早在阮大大的ES6教程里面就接触到了,但是一直处于理解并不熟练使用的状态,于是决定重新学习并且总结一下,写了这篇博文.如果文中有错误的地方还请各位 ...
- MeteoInfoLab脚本示例:Streamline流线图
绘制Stramline流线图的函数是streamline,需要两个变量(U/V分量或者风向/风速).脚本程序: f = addfile('D:/Temp/GrADS/model.ctl') u = f ...
- 【C语言编程入门】Do you know 函数?不知道了吧,我来告诉你!
☆ 函数 在前面我们已经讲过了一些简单的函数,如程序的主函数main().标准输出函数printf().在C语言中,大多数功能都是依靠函数来实现的.But,你知道什么是函数吗?我猜你肯定不知道. 那么 ...
- CentOS 6编译安装RabbitMQ
编译安装Python 下载python源文件 [root@localhost src]# tar -xzvf python-2.7.11.tar.gz [root@localhost src]# cd ...
- python web自动化上传文件工具
工具下载地址:链接:https://pan.baidu.com/s/1cHdNHW 密码:56bp说明:1.WinSpy-1.0.2.7z解压即可.2.pywin32的exe程序,根据自己安装的pyt ...
- C++学习---栈的构建及操作
一.顺序栈 #include <iostream> using namespace std; #define MAXSIZE 100 //栈的最大容量 typedef struct { i ...
- 接收某项课程id,通过axios发起get请求,由于携带params出现的问题(已解决)
问题:在最新课程页面(NewBook.vue)点击某一项课程,通过传递该课程的 id 跳转至课程详情页(Bookdetail.vue),采取的跳转方式是声明式导航,即 <router-link ...
- Java 内存级默认DNS缓存
Java 默认的DNS缓存时间,即不设置任一系统属性,如networkaddress.cache.ttl 设置SecurityManager 默认的CachePolicy为Forever,即永久缓存D ...
- vue 404
问题描述:前端同事使用Vue.js框架,利用vue-route结合webpack编写了一个单页路由项目,运维协助在服务器端配置nginx.部署完成后,访问首页没问题,从首页里打开二级页面没问题,但是所 ...