Linux入门教程:Nginx解决惊群现象,运维每天看什么日志 Nginx通过控制


惊群现象:所有的工作进程都在等待一个socket,当socket客户端连接时,所有工作线程都被唤醒,但最终有且仅有一个工作线程去处理该连接,其他进程又要进入睡眠状态。

Nginx通过控制争抢处理socket的进程数量和抢占ngx_accept_mutex锁解决惊群现象。只有一个ngx_accept_mutex锁,谁拿到锁,谁处理该socket的请求。

如果当前进程的连接数>最大连接数*7/8,则该进程不参与本轮竞争。

while(true)
{
    //工作进程抢占锁,抢占成功的进程将ngx_accept_mutex_held变量置为1。拿到锁,意味着socket被放到本进程的epoll中了,如果没有拿到锁,则socket会被从epoll中取出。  
    if(pthread_mutex_trylock(&ngx_accept_mutex))
    {
        ngx_accept_mutex_held = 1;
    }
    else
    {
        //设置time时间,使得没有拿到锁的worker进程,去拿锁的频繁更高
        timer = 500;
        ngx_accept_mutex_held = 0;
    }

     //拿到锁的话,置flag为NGX_POST_EVENTS,这意味着ngx_process_events函数中,任何事件都将延后处理,会把accept事件都放到ngx_posted_accept_events链表中,epollin|epollout事件都放到ngx_posted_events链表中  
    if (ngx_accept_mutex_held) 
    {   
        flags |= NGX_POST_EVENTS;
    }

    //继续epoll_wait等待处理事件
    int num = epoll_wait(epollfd, events, length, timer);
    for(int i=0; i<num; ++i)
    {
        ......
        //如果是读事件
        if (revents & EPOLLIN)
        {
            //有NGX_POST_EVENTS标志的话,就把accept事件放到ngx_posted_accept_events队列中,把正常的事件放到ngx_posted_events队列中延迟处理
            if (flags & NGX_POST_EVENTS)
            {
                queue = rev->accept ? 
                    &ngx_posted_accept_events:&ngx_posted_events;

                ngx_post_event(rev, queue);
            }
            else//处理
            {
                rev->handler(rev);
            }
        }

        //如果是写事件
        if (revents & EPOLLOUT)
        {
            //同理,有NGX_POST_EVENTS标志的话,写事件延迟处理,放到ngx_posted_events队列中 
            if (flags & NGX_POST_EVENTS) 
            {
                ngx_post_event(rev, &ngx_posted_events);
            }
            else//处理
            {
                rev->handler(rev);
            }
        }

      //先处理新用户的连接事件
      ngx_event_process_posted(cycle, &ngx_posted_accept_events);

      //释放处理新连接的锁
      if(ngx_accept_mutex_held)
      {
          pthread_mutex_unlock(&ngx_accept_mutex);
      }

      //再处理已建立连接的用户读写事件
      ngx_event_process_posted(cycle, &ngx_posted_events);
    }

相关内容