地方エンジニアの学習日記

興味ある技術の雑なメモだったりを書いてくブログ。たまに日記とガジェット紹介。

【Nginx】nginx -s reloadの実装を見てみる

nginx -s reloadはgraceful restartできるっていうけど実際どんな実装なんだろって思ったのでチラ見してみる。

公式にはどう書いてある?

nginxが設定ファイルを再読込みするには、HUPシグナルがマスタープロセスに送られる必要があります。マスタープロセスはまず文法的な検証をチェックし、それから新しい設定を適用しようとします。つまり、ログファイルと新しいlistenソケットを開こうとします。もし失敗すれば、変更を巻き返し、古い設定で動作し続けます。成功した場合は、新しいworkerプロセスを開始し、古いworkerプロセスにグレースフルにシャットダウンするようにメッセージを送信します。. 古いworkerプロセスはlistenソケットを閉じ、古いクライアントへの提供を続けます。全てのクライアントへの提供が終了した後で、古いworkerプロセスはシャットダウンされます。

つまりこんな感じ

① masterプロセスへSIGHUPを送信
② masterプロセスがconfigの文法チェック
③ masterプロセスがconfigの内容を反映したcycleを生成
④ 新しいworkerプロセスを起動
⑤ 既存のworkerプロセスへgracefull shutdownの指示を出す

という感じ。nginxの設定がリロードされる度に、新しいサイクルが新しいnginx設定から生成され古いサイクルは通常新しいものがうまく生成された後で削除されます。

mogile.web.fc2.com

ソースを追う

さっとみるくらいでいくのでmasterプロセスのサイクル内のみを見ていきます。workerでのgraceful shutdownは過去に追っているので気になる方は見てみてください

ryuichi1208.hateblo.jp

<200c>#define ngx_get_conf(conf_ctx, module)  conf_ctx[module.index]

volatile ngx_cycle_t  *ngx_cycle;

void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
/ * 省略 * /
        // nginx -s reloadを実行されるとここに入る
        if (ngx_reconfigure) {
            ngx_reconfigure = 0;

            // USR2などのバイナリ置き換え時に入る。今回は範囲外
            if (ngx_new_binary) {
                ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_RESPAWN);
                ngx_start_cache_manager_processes(cycle, 0);
                ngx_noaccepting = 0;

                continue;
            }

            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");

            // configのテストやポートのlistenやログファイルのopenなどを行う。ここで失敗したらgraceful reload自体を行わない
            cycle = ngx_init_cycle(cycle);
            if (cycle == NULL) {
                // 失敗時もcontinueするだけなので出力等は確認することができないので操作自体の成功可否はプロセスの起動時間になる
                cycle = (ngx_cycle_t *) ngx_cycle;
                continue;
            }

            // グローバル宣言されているngx_cycleへ新規作成したcycleを代入
            ngx_cycle = cycle;

            // マクロになっていてngx_core_moduleのconfigを読み取っている。
            ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                   ngx_core_module);
            // workerプロセスを起動させる処理。worker_processes分のworkerが生成される
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_JUST_RESPAWN);  // NGX_PROCESS_JUST_RESPAWNフラグを指定

            // キャッシュマネージャーを起動させる処理
            ngx_start_cache_manager_processes(cycle, 1);

            /* allow new processes to start */
            ngx_msleep(100);

            live = 1;
            // 子プロセスのうち古いプロセスのみNGX_SHUTDOWN_SIGNALを送る。
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }

ngx_init_cycleも大事ですが非常に巨大なので今度読みます。

github.com