Nginx中的驚羣現象解決方法

*什麼是驚羣現象?Nginx中用了什麼方法來避免這種問題的發生?本篇就解決這兩個問題。。。→_→*

  1. 驚羣現象的定義與危害

    • 在Nginx中,每一個worker進程都是由master進程fork出來的。master進程創建socket後進行listen、bind操作,fork出來的worker繼承了socket,調用accpet開始監聽等待網絡連接

    • 如果這時有多個worker進程都在等待事件的發生。當事件發生時,這些worker進程被同時喚醒,但最終只有一個worker進程可以處理事件成功,其他的worker進程就會重新進入阻塞狀態

    • 當驚羣現象發生時,內核會依次喚醒所有的worker進程,這種操作會導致系統在瞬時佔用極大的資源,但最後卻只有一個worker進程處理事件成功,這就造成了極大的資源浪費

    • Nginx中的master-worker架構

  2. Nginx中解決驚羣現象的方法

    • Nginx中規定同一時刻只能有唯一一個的worker進程監聽Web端口,這樣就不會發生驚羣了,此時新連接事件只能喚醒唯一正在監聽端口的worker進程
  3. 源碼剖析

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;
}

*本篇只分析了Nginx中如何保證不發生驚羣現象的解決方法,後面其實還有worker進程何時釋放ngx_accept_mutex鎖的問題。。其超出了本篇的範圍。。。就不在這裏繼續討論了。。明天加油。。。→_→*

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章