序文 nginx はマルチプロセス モデルを使用します。リクエストが届くと、システムはプロセスをロックして、1 つのプロセスだけがリクエストを受け入れるようにします。
1. 受け入れロックの実装 1.1 アクセプトロックとは何ですか? Accept Lock について話すとき、Thundering Herd 問題について言及する必要があります。 いわゆる herd-throwing 問題は、Nginx のようなマルチプロセス サーバーに当てはまります。フォーク後に同じポートを同時に listen している場合、外部接続が入ると、休止状態の子プロセスがすべて起動され、最終的に 1 つの子プロセスだけが accept イベントを正常に処理でき、他のプロセスはスリープ状態に戻ります。その結果、多くの不要なスケジュールとコンテキストの切り替えが発生しますが、これらのオーバーヘッドはまったく不要です。 Linux カーネルの新しいバージョンでは、accept 呼び出し自体によって引き起こされる thundering herd 問題は解決されています。ただし、Nginx では、accept は epoll メカニズムによって処理され、epoll の accept によって引き起こされる thundering herd 問題は解決されていません (epoll_wait 自体には、読み取りイベントが Listen ソケットからのものであるかどうかを区別する機能がないため、このイベントを listen しているすべてのプロセスがこの epoll_wait によって起動されるはずです)。そのため、Nginx の accept thundering herd 問題には、依然としてカスタマイズされたソリューションが必要です。 accept ロックは nginx のソリューションです。本質的には、これはプロセス間のミューテックス ロックであり、1 つのプロセスのみが accept イベントをリッスンできることを保証します。 受け入れロックは、実際にはプロセス間ロックです。これは Nginx のグローバル変数であり、次のように宣言されます。 ngx_shmtx_t ngx_accept_mutex; これは、イベント モジュールが初期化されるときに割り当てられ、すべてのプロセスがこのインスタンスにアクセスできるようにするためにプロセス間の共有メモリに配置されるロックです。ロックとロック解除は、Linux アトミック変数を使用して CAS によって行われます。ロックが失敗すると、すぐに戻ります。これは非ブロッキング ロックです。ロック解除コードは次のとおりです。 静的 ngx_inline ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx) { 戻り値 (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)); } #define ngx_shmtx_lock(mtx) ngx_spinlock((mtx)->lock, ngx_pid, 1024) #define ngx_shmtx_unlock(mtx) (void) ngx_atomic_cmp_set((mtx)->lock, ngx_pid, 0) ngx_shmtx_trylock の呼び出しが失敗した後、ブロックせずにすぐに戻ることがわかります。 1.2 受け入れロックはどのようにして 1 つのプロセスだけが新しい接続を処理できるようにするのでしょうか? epoll によって発生する accept lock 問題を解決することも非常に簡単です。 accept epoll イベントを同時に登録するプロセスが 1 つだけであることを確認するだけです。
もちろん、遅延イベントの処理はここでは無視されますが、これについては後で説明します。 受け入れロックの処理と、epoll での受け入れイベントの登録とキャンセルはすべて ngx_trylock_accept_mutex で実行されます。この一連のプロセスは、nginx メイン ループで繰り返し呼び出される void ngx_process_events_and_timers(ngx_cycle_t *cycle) で実行されます。 つまり、各イベント処理ラウンドでは、まず accept ロックを競います。競い合いに成功すると、accept イベントが epoll に登録されます。競い合いに失敗すると、accept イベントは登録解除されます。その後、イベントが処理されると、accept ロックが解放されます。この方法では、1 つのプロセスだけが listen ソケットを listen するため、thundering herd 問題を回避できます。 1.3 イベント処理メカニズムは、受け入れロックが長時間占有されるのを防ぐためにどのような努力を払いますか? 受け入れロックを使用してサンダーリング・ハード問題に対処するという解決策は非常に優れているように見えますが、上記のロジックを完全に使用すると問題が発生します。サーバーが非常にビジーで、処理するイベントが多数ある場合、「すべてのイベントの処理」に非常に長い時間がかかります。つまり、プロセスが受け入れロックを長時間占有し、新しい接続を処理する時間がありません。他のプロセスは受け入れロックを占有せず、新しい接続も処理できません。この時点で、新しい接続は誰も処理していない状態になり、サービスのリアルタイム パフォーマンスにとって間違いなく致命的です。 この問題を解決するために、Nginx はイベント処理を延期します。つまり、ngx_process_events の処理では、イベントは次の 2 つのキューにのみ配置されます。 ngx_thread_volatile ngx_event_t *ngx_posted_accept_events; ngx_thread_volatile ngx_event_t *ngx_posted_events; 戻った後、まず ngx_posted_accept_events を処理し、すぐに accept ロックを解除してから、他のイベントをゆっくり処理します。 つまり、ngx_process_events は epoll_wait のみを処理し、イベントの消費は accept ロックが解放された後に配置され、accept を占有する時間を最小限に抑え、他のプロセスが accept イベントを処理するのに十分な時間を確保できるようにします。 では、具体的にはどのように達成されるのでしょうか?実際には、 これは、イベント消費による accept ロックの長期占有を回避するだけなので、epoll_wait 自体に長い時間がかかる場合はどうなるでしょうか?これが起こる可能性はゼロではない。この点の処理も非常に簡単です。epoll_wait 自体にはタイムアウト期間があるため、その値を制限するだけです。このパラメータは、グローバル変数 ngx_accept_mutex_delay に格納されます。 以下は ngx_process_events_and_timers の実装コードです。これにより、関連する処理の概要がわかります。 空所 ngx_process_events_and_timers(ngx_cycle_t *サイクル) { ngx_uint_t フラグ; ngx_msec_t タイマー、デルタ; /* 時間イベントを処理するためのコードを省略*/ // ここで負荷分散ロックを処理し、ロックを受け入れる if (ngx_use_accept_mutex) { // 負荷分散トークンの値が 0 より大きい場合、負荷がいっぱいで accept が処理されなくなったことを意味します。同時に、値は 1 減少します if (ngx_accept_disabled > 0) { ngx_accept_disabled--; } それ以外 { // 受け入れロックを取得しようとする if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) { 戻る; } // ロックを取得した後、すべてのイベントの処理を延期するためにフラグをポストフラグに追加します // 受け入れロックを長時間占有しないようにします if (ngx_accept_mutex_held) { フラグ |= NGX_POST_EVENTS; } それ以外 { タイマー == NGX_TIMER_INFINITE の場合 || タイマー > ngx_accept_mutex_delay) { timer = ngx_accept_mutex_delay; // 受け入れロックが長時間占有されるのを防ぐために、最大で ngx_accept_mutex_delay ミリ秒待機します} } } } デルタ = ngx_current_msec; // イベント処理モジュールの process_events を呼び出して、epoll_wait メソッドを処理します (void) ngx_process_events(cycle, timer, flags); delta = ngx_current_msec - delta; //イベントの処理にかかった時間を計算 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "タイマーデルタ: %M", デルタ); // 延期された承諾イベントがある場合は、このイベントの処理を延期します if (ngx_posted_accept_events) { ngx_event_process_posted(サイクル、&ngx_posted_accept_events); } // accept ロックを解除する if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex); } // すべてのタイムアウトイベントを処理する if (delta) { ngx_event_expire_timers(); } ngx_log_debug1(NGX_LOG_DEBUG_EVENT、サイクル->ログ、0、 "投稿されたイベント %p", ngx_posted_events); ngx_posted_eventsの場合{ ngx_threadedの場合{ ngx_wakeup_worker_thread(サイクル); } それ以外 { // すべての遅延イベントを処理する ngx_event_process_posted(cycle, &ngx_posted_events); } } } ngx_epoll_process_events の関連処理を見てみましょう。 // イベントを読み取る if ((revents & EPOLLIN) && rev->active) { if ((フラグ & NGX_POST_THREAD_EVENTS) && !rev->accept) { rev->posted_ready = 1; } それ以外 { 回転->準備完了 = 1; } if (フラグ & NGX_POST_EVENTS) { キュー = (ngx_event_t **) (rev->accept ? &ngx_posted_accept_events : &ngx_posted_events); ngx_locked_post_event(rev、キュー); } それ以外 { rev->ハンドラ(rev); } } wev = c->書き込み; // イベントを書き込む if ((revents & EPOLLOUT) && wev->active) { if (フラグ & NGX_POST_THREAD_EVENTS) { wev->posted_ready = 1; } それ以外 { wev->準備完了 = 1; } if (フラグ & NGX_POST_EVENTS) { ngx_locked_post_event(wev、&ngx_posted_events); } それ以外 { wev->ハンドラ(wev); } } 処理も比較的単純です。受け入れロックが取得されると、NGX_POST_EVENTS フラグが立てられ、対応するキューに配置されます。そうでない場合、イベントは直接処理されます。 要約する 上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM を応援していただきありがとうございます。 以下もご興味があるかもしれません:
|
>>: ReactでのsetStateの使用と同期と非同期の使用
1. HTMLページの文字セットを指定する2つの方法方法1: <メタ文字セット="u...
これら 16 のサイトはそれぞれ注意深く読む価値があり、どのサイトでも推奨されている Web サイト...
目次必要:発生した問題:解決する:必要:要素テーブル内の複数の列を並べ替えるには、日付の並べ替えをク...
コンテナが企業の IT インフラストラクチャに欠かせない要素となっていることは間違いありません。コン...
垂直方向では、行の配置を上、中央、下に設定できます。基本的な構文<TR VALIGN=&quo...
非直交マージンマージンを使用するとマージが発生します次のプロパティはマージンの結合を防止します。国境...
デフォルトでは、CentOS 7 上の PHP は apache または nobody として実行さ...
Docker コンテナ内のプログラムは、ホスト ディレクトリ内のデータにアクセスして呼び出す必要があ...
http1.1 プロトコルのデフォルトのリクエスト ヘッダーでは、図に示すように、デフォルトで ke...
ClickHouse は、オープンソースの列指向 DBMS (Yandex によって開発) です。 ...
動作環境: MAC Docker バージョン: Docker version 17.12.0-ce,...
以前は、さまざまな理由により、一部のアラームは真剣に受け止められませんでした。最近、休暇中に、すぐに...
1. 速度制御機能を使用して、トランジション効果(加速、減速など)の速度曲線を制御します。速度制御機...
数日前、CSS で 3 列レイアウトを書いていたときに、突然この方法を思いつきました。このアイデアは...
目次Vuex とは何ですか? Vuex 使用サイクル図私のストアディレクトリvuexの例の実装要約す...