nginx如何避免worker进程的惊群效应
首先看一下事件模块,其初始化工作主要由ngx_event_process_init完成;
Prefork-worker:调用ngx_event_core_module->ngx_event_module_init,只是初始化一些变量;
After-fork:调用ngx_worker_process_init -->
ngx_event_process_init
1 开启accept mutex
2 初始化红黑树定时器ngx_event_timer_rbtree
3 调用epoll模块的init方法ngx_epoll_init,
调用epoll_create
4 设置时间精度timer_resolution
5 预分配cycle->connections/read_events/write_events数组
6 将监听套接字读事件处理方法设置为ngx_event_accept
监听套接字由master初始化,每个worker都继承一份,同时创建各自的epoll结构体和定时器;
问1:如何确保同一时间只有一个worker操纵监听套接字?
答案: accept_mutex,同一时间只有一个worker能获取,
ngx_worker_process_init -->
ngx_event_process_init --> ngx_process_events_add_timers(位于for(;;)循环中)
1 若当前worker负载已超阈值,则不去尝试获取mutex即接收客户端新连接;
2 若当前worker成功获取mutex,则将事件flags设为NGX_POST_EVENTS,epoll_wait返回时将事件handler分别放入accepted队列和post队列,处理完前者后立即释放mutex,然后处理后者, 减少mutex占用时间;
3 若当前worker没有获取mutex,则在epoll_wait返回后当场执行各事件对应的handler;
代码片段
if (ngx_use_accept_mutex) {
if (ngx_accept_disabled
> 0) {
ngx_accept_disabled--;
} else {
if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
return;
}
if (ngx_accept_mutex_held) {
flags |= NGX_POST_EVENTS; --获取到mutex的worker,将flag置为post,epoll_wait返回时不立即执行event->handler,而是将其放入accept和post队列;
} else {
if (timer == NGX_TIMER_INFINITE
|| timer > ngx_accept_mutex_delay)
{
timer = ngx_accept_mutex_delay;
}
}
}
}
.......
(void) ngx_process_events(cycle, timer, flags); --使用epoll时为ngx_epoll_process_events,epoll_wait返回时,根据rev->accept将返回事件分别加入accepted和posted队列
.......
if (ngx_posted_accept_events) { --先执行新建连接事件即accept队列,调用其ev->hander即ngx_event_accept(),然后释放mutex,再接着执行post队列;
ngx_event_process_posted(cycle, &ngx_posted_accept_events);
}
if (ngx_accept_mutex_held) {
ngx_shmtx_unlock(&ngx_accept_mutex);
}
.......
if (ngx_posted_events) {
if (ngx_threaded) {
ngx_wakeup_worker_thread(cycle);
} else {
ngx_event_process_posted(cycle, &ngx_posted_events);
}
}
问2: 为什么获取accept_mutex就能确保有且只有当前worker能监听listening
port?
答案:ngx_try_lock_accept_mutex -->
ngx_enable_accept_events,当worker获取mutex后,通过ngx_enable_accept_events将监听套接口的读事件加入epoll监控;
ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
{
if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
......
if
(ngx_enable_accept_events(cycle) == NGX_ERROR) {
ngx_shmtx_unlock(&ngx_accept_mutex);
return NGX_ERROR;
}
......
}
}
ngx_enable_accept_events(ngx_cycle_t
*cycle)
{
for (i = 0; i < cycle->listening.nelts; i++) {
c = ls[i].connection;
if (c->read->active) {
continue;
}
if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {
if (ngx_add_conn(c) == NGX_ERROR) {
return NGX_ERROR;
}
} else {
if (ngx_add_event(c->read, NGX_READ_EVENT, 0) ==
NGX_ERROR) {
return NGX_ERROR;
}
}
}
........
}
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。