*什么是惊群现象?Nginx中用了什么方法来避免这种问题的发生?本篇就解决这两个问题。。。→_→*
惊群现象的定义与危害
在Nginx中,每一个worker进程都是由master进程fork出来的。master进程创建socket后进行listen、bind操作,fork出来的worker继承了socket,调用accpet开始监听等待网络连接
如果这时有多个worker进程都在等待事件的发生。当事件发生时,这些worker进程被同时唤醒,但最终只有一个worker进程可以处理事件成功,其他的worker进程就会重新进入阻塞状态
当惊群现象发生时,内核会依次唤醒所有的worker进程,这种操作会导致系统在瞬时占用极大的资源,但最后却只有一个worker进程处理事件成功,这就造成了极大的资源浪费
Nginx中解决惊群现象的方法
- Nginx中规定同一时刻只能有唯一一个的worker进程监听Web端口,这样就不会发生惊群了,此时新连接事件只能唤醒唯一正在监听端口的worker进程
源码剖析
ngx_int_t
ngx_trylock_accept_mutex(ngx_cycle_t *cycle)
{
//使用worker进程间同步锁——ngx_accept_mutex,ngx_shmtx_trylock返回1表示成功获取锁,返回0表示获取锁失败。ngx_shmtx_trylock是非阻塞的,如果此时ngx_accept_mutex被其他worker进程占有,那么ngx_shmtx_trylock会立即返回
if (ngx_shmtx_trylock(&ngx_accept_mutex)) {
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"accept mutex locked");
//ngx_accept_mutex_held为1时表示当前worker进程已经获取到了锁,那么就立即返回
if (ngx_accept_mutex_held
&& ngx_accept_events == 0
&& !(ngx_event_flags & NGX_USE_RTSIG_EVENT))
{
return NGX_OK;
}
//将所有监听连接的读事件添加到当前的epoll等事件驱动模块中
if (ngx_enable_accept_events(cycle) == NGX_ERROR) {
//如果将所有监听连接的读事件添加到当前的epoll等事件驱动模块中失败,那么就必须释放ngx_accept_mutex锁
ngx_shmtx_unlock(&ngx_accept_mutex);
return NGX_ERROR;
}
//此时需要把ngx_accept_mutex_held置为1,方便本进程的其他驱动模块它已经获取到了锁
ngx_accept_events = 0;
ngx_accept_mutex_held = 1;
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"accept mutex lock failed: %ui", ngx_accept_mutex_held);
//此时ngx_shmtx_trylock返回了0,表示获取ngx_shmtx_trylock锁失败。但是此时ngx_accept_mutex_held还为1,即当前worker进程还在占有ngx_accept_mutex锁,就说明有问题
if (ngx_accept_mutex_held) {
//将所有监听连接的读事件从事件模块中移出
if (ngx_disable_accept_events(cycle) == NGX_ERROR) {
return NGX_ERROR;
}
//没有获取到ngx_accept_mutex锁时,将ngx_accept_mutex_held置为0
ngx_accept_mutex_held = 0;
}
return NGX_OK;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
*本篇只分析了Nginx中如何保证不发生惊群现象的解决方法,后面其实还有worker进程何时释放ngx_accept_mutex锁的问题。。其超出了本篇的范围。。。就不在这里继续讨论了。。明天加油。。。→_→*