驚異的な問題.


定義#テイギ#
  • 驚きのグループ問題とは、マルチスレッド(またはマルチプロセス)シーンで、あるリソースが利用可能になるのを待っている複数のスレッドがあり、このリソースが利用可能になると、このリソースを待っているすべてのスレッドが呼び出されますが、リソースは1つしかありません.他のスレッドは
  • に失敗します.
  • の驚きのグループ問題は、不要なスレッドの起動を招き、実際には1つのスレッドだけがこのリソースを取得できるので、理想的には1つのスレッドだけを起動すればよい.一方、複数のスレッドを起動することは、不要なスレッドスケジューリングをもたらし、システムオーバーヘッド
  • をもたらす.
    古典的なaccept驚群問題
  • Linuxの初期バージョンではaccept関数に驚異的な問題がありました
  • は、親プロセスがsocket、bind、listenを介してリスニング記述子を作成し、forkが複数のサブプロセスを生成し、すべてのプロセスがacceptというリスニング記述子を有し、新しい接続が来ないときにブロックに陥るシーンを考慮する.新しい接続が来るたびに、acceptにブロックされているすべてのプロセスが起動し、そのうちの1つのプロセスacceptが正常に戻り、他のプロセスはEAGAINエラー
  • を返します.
  • 上のシーンは古典的なaccept驚群問題
  • です.
  • 現在のLinuxバージョンでは、このようなaccept驚きの問題は存在しません.つまり、複数のプロセスがacceptにブロックされている場合、新しい接続の到来は1つのプロセスを呼び覚ますだけです.しかし、これは驚くべき問題が
  • 解決されたという意味ではない.
    epoll驚きの群れ
  • 上記のようにacceptシステム呼び出しには驚きの問題は存在しないが、epollには驚きの問題も存在する.
  • 親プロセスがepoll_を介してリスニング記述子を作成するシーンを考慮ctlはこのリスニングソケットをepollに追加し、forkは複数のサブプロセスを出し、各サブプロセスはepoll_にある.waitでは、リスニング記述子を待つ読み取り可能なイベント(新しい接続が到来する)がブロックされ、新しい接続が到来すると、すべてのサブプロセスが起動します.
  • Linuxカーネルはaccept驚き現象を処理したが、epoll驚き現象を処理しなかったのは、acceptが1つのプロセスでしか処理できないためかもしれない.epollが傍受する記述子は、ファイルが複数のプロセスによって読み書きされるなど、複数のプロセスによって処理される可能性があります.したがって、カーネルはepollの驚異的な群現象
  • を処理する必要があるか否かを判断できない.
    Nginxによる驚きのグループ問題の処理
  • Nginxのポリシーは、同じ時点で唯一のworkerサブプロセスがWebポートを傍受することしかできないことを規定している.このとき、新しい接続イベントは1つのプロセスを呼び覚ますことしかできず、驚くべき現象は
  • ではない.
  • accept_を具体的に使用mutexロック方式
  • を実現
    ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t* cycle)
    {
        /*     accept_mutex ,      ,  1;         0,     */
        if(ngx_shmtx_trylock(&ngx_accept_mutex)) {
            /* accept_mutex         ,     */
            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) {
                /*          */
                ngx_shmtx_unlock(&ngx_accept_mutex);
                return NGX_ERROR;
            }
    
            /*      ,        */
            ngx_accept_events = 0;
            ngx_accept_mutex_held = 1;
    
            return NGX_OK;
        }
    
        if(ngx_accept_mutex_held) {
            /*           epoll    */
            if(ngx_disable_accept_events(cycle) == NGX_ERROR) {
                return NGX_ERROR;
            }
            ngx_accept_mutex_held = 0;
        }
        return NGX_OK;
    }
    
  • 上記のコードから、任意の時点でaccept_を取得できるプロセスは1つしかないことがわかります.mutexロック、accept_を取得mutexロックのプロセスはwebポートを傍受することができる.accept_を取得できませんでしたmutexロックのプロセスは、リスニングソケットをepollから
  • 削除します.