Nginx惊群处理

惊群:是指在多线程/多进程中,当有一个客户端发生链接请求时,多线程/多进程都被唤醒,然后只仅仅有一个进程/线程处理成功,其他进程/线程还是回到睡眠状态,这种现象就是惊群。

惊群是经常发生现在server端,父进程fork很多子进程,当有客户端有链接请求时,所有子进程都被唤醒,可是只有一个子进程处理请求,其他子进程就继续休眠。

Nginx  处理集群的方法:

  ngx_postd_events:是监听套接口上的事件

  ngx_posted_accept_events:是新建连接事件(也就是监听套接口上发生的可读事件)

  ngx_accept_mutex_held:看是否拥有锁

  Nginx中统一时刻,监听套接口只可能被一个进程监控,并且在建立新连接时,通过获得锁,来确定那个子进程进行监控。当当前工作进程负载较小时,即当前活动连接数 < 最大可承受连接数的*7/8,就可以将监听套接口加入到自身的时间监控机制中,从而带来新的请求,如果当前进程的负载很大,则将该监听套接口从自身的事件中删除,避免带来的新的客户端的请求而带来更大的负载。

  关于锁,持锁者必须缩短自身拥有锁的事件,所以Nginx是将很多时间延迟到释放锁之后进行处理,把锁释放,尽量释放拥有锁的时间,让其他进程有机会获得锁。

  

 1 if (ngx_use_accept_mutex)
 2 {
 3          //
 4 当前的连接数是否超过最大可承受连接数的 7/8
 5         if (ngx_accept_disabled > 0) 
 6         {
 7             ngx_accept_disabled--;
 8         } 
 9         else
10          {
11     //获得锁
12                 if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) 
13                 {
14                     return;
15                 }
16     //获得锁,表明新建连接后,将所有事件延后处理,先释放锁,是的拥有锁的事件最小化
17                 if (ngx_accept_mutex_held) 
18                 {
19                         flags |= NGX_POST_EVENTS;
20     } 
21     else 
22     {
23                     //没有获得锁传给epoll_wait使得epoll_wait 使得返回时间剪短防止长时间连接没有返        //
24         if (timer == NGX_TIMER_INFINITE|| timer > ngx_accept_mutex_delay)
25                     {
26                             timer = ngx_accept_mutex_delay;
27                     }
28             }
29   }
30 
31        ngx_accept_disabled = ngx_cycle->connection_n / 8
32  - ngx_cycle->free_connection_n;
33 
34 
35     delta = ngx_current_msec;
36 
37     (void) ngx_process_events(cycle, timer, flags);
38 
39     delta = ngx_current_msec - delta;
40 
41     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
42                    "timer delta: %M", delta);
43 
44 //新建链接缓存
45     ngx_event_process_posted(cycle, &ngx_posted_accept_events);
46 
47 //释放锁
48     if (ngx_accept_mutex_held) {
49         ngx_shmtx_unlock(&ngx_accept_mutex);
50     }
51 
52     if (delta) {
53         ngx_event_expire_timers();
54     }
55     ngx_event_process_posted(cycle, &ngx_posted_events);
56 /*
57     此处释放锁并没有将监听套接字从时间监控机制中删除,在接下来的ngx_posted_events缓存事件时,互斥锁被另一个进程争取,并且把监听套接字加入到事件监听机制中,而同一时间,一个监听套接字被多个程序占有,因此进程在处理完ngx_posted_events后去争取锁,发现锁被其他进程占用而失败,所以将该监听套接口从自身的事件监听机制中删除,然后才进行事件监控。
58 */
原文地址:https://www.cnblogs.com/chenyang920/p/5527078.html