NGINXのリロードはどのように機能するのか?なぜNGINXはホットリロードしないのか?
Wei Liu
September 30, 2022
最近、Redditに「なぜNGINXはホットリロードをサポートしていないのか?」という投稿があるのを見かけました。奇妙なことに、世界最大のウェブサーバーであるNGINXがホットリロードをサポートしていないのでしょうか?これは、私たちが皆nginx -s reload
を誤って使っているということなのでしょうか?この疑問を解消するために、NGINXのリロードがどのように動作するのかを確認してみましょう。
NGINXとは
NGINXは、C言語で開発されたクロスプラットフォームのオープンソースウェブサーバーです。統計によると、トラフィックが最も多い上位1000のウェブサイトのうち、40%以上がNGINXを使用して膨大なリクエストを処理しています。
なぜNGINXはこれほど人気があるのか
NGINXには、他のウェブサーバーを凌駕し、常に高い利用率を維持するためのどのような利点があるのでしょうか?
主な理由は、NGINXが高並列処理の問題に対処するために設計されていることです。そのため、NGINXは膨大な同時リクエストを処理しながら、安定した効率的なサービスを提供できます。さらに、ApacheやTomcatなどの同時代の競合製品と比較して、NGINXには高度なイベント駆動型アーキテクチャ、ネットワークIOを処理する完全な非同期メカニズム、非常に効率的なメモリ管理システムなど、多くの優れた設計があります。これらの優れた設計により、NGINXはサーバーのハードウェアリソースを完全に活用し、NGINXをウェブサーバーの代名詞にしています。
上記以外にも、以下のような理由があります:
- 高度にモジュール化された設計により、NGINXは豊富な公式およびサードパーティのモジュールを所有しています。
- 最も自由なBSDライセンスにより、開発者がNGINXに貢献しやすくなっています。
- ホットリロードのサポートにより、NGINXは24時間365日のサービスを提供できます。
上記の理由の中でも、ホットリロードが今日の主なトピックです。
ホットリロードの役割
私たちが期待するホットリロードとは何でしょうか?まず、クライアント側のユーザーがサーバーのリロードを意識しないことです。次に、サーバーやアップストリームサービスが動的にロードされ、ダウンタイムなしですべてのユーザーリクエストを成功裏に処理できることです。
どのような状況でホットリロードが必要なのでしょうか?クラウドネイティブの時代において、マイクロサービスが非常に人気を博しており、サーバー側の変更が頻繁に必要となるアプリケーションシナリオが増えています。これらの変更には、ドメインのオンライン/オフラインのリバースプロキシ、アップストリームアドレスの変更、IP許可リスト/ブロックリストの変更などがあり、ホットリロードに関連しています。
では、NGINXはどのようにホットリロードを実現しているのでしょうか?
NGINXホットリロードの原理
ホットリロードコマンドnginx -s reload
を実行すると、NGINXのマスタープロセスにHUPシグナルが送信されます。マスタープロセスがHUPシグナルを受信すると、順番にリスニングポートを開き、新しいワーカープロセスを開始します。そのため、新旧の2つのワーカープロセスが同時に存在することになります。新しいワーカープロセスが起動した後、マスタープロセスは古いワーカープロセスにQUITシグナルを送信して、正常にシャットダウンします。古いワーカープロセスがQUITシグナルを受信すると、まずリスニングハンドラを閉じます。これにより、すべての新しい接続は新しいワーカープロセスにのみ入り、サーバーは残りの接続をすべて処理した後に古いプロセスをシャットダウンします。
理論的には、NGINXのホットリロードは私たちの要件を完全に満たすことができるのでしょうか?残念ながら、答えはノーです。では、NGINXのホットリロードにはどのような欠点があるのでしょうか?
NGINXリロードによるダウンタイム
-
ホットリロードが頻繁すぎると、接続が不安定になり、ビジネスデータが失われる可能性があります。
NGINXがリロードコマンドを実行すると、古いワーカープロセスは既存の接続を処理し続け、すべての残りのリクエストを処理した後に自動的に切断されます。しかし、クライアントがすべてのリクエストを処理していない場合、残りのリクエストのビジネスデータが永久に失われる可能性があります。もちろん、これはクライアント側のユーザーの注意を引くことになります。
-
一部の状況では、古いワーカープロセスの回収に時間がかかりすぎて、通常のビジネスに影響を与えることがあります。
例えば、WebSocketプロトコルをプロキシする場合、NGINXはヘッダーフレームを解析しないため、リクエストが処理されたかどうかを知ることができません。そのため、ワーカープロセスがマスタープロセスから終了コマンドを受信しても、これらの接続が例外を発生させるか、タイムアウトするか、切断されるまで終了できません。
別の例として、NGINXがTCPやUDPのリバースプロキシとして機能する場合、リクエストが最終的にシャットダウンされる前にどのくらいの頻度でリクエストされているかを知ることができません。
そのため、古いワーカープロセスの回収には通常、長時間かかります。特に、ライブストリーミング、メディア、音声認識などの業界では、古いワーカープロセスの回収時間が30分以上かかることもあります。一方、ユーザーが頻繁にサーバーをリロードすると、多くのシャットダウンプロセスが作成され、最終的にNGINXのOOM(Out Of Memory)を引き起こし、ビジネスに深刻な影響を与える可能性があります。
# 古いワーカープロセスに常に存在する:
nobody 6246 6241 0 10:51 ? 00:00:00 nginx: worker process
nobody 6247 6241 0 10:51 ? 00:00:00 nginx: worker process
nobody 6247 6241 0 10:51 ? 00:00:00 nginx: worker process
nobody 6248 6241 0 10:51 ? 00:00:00 nginx: worker process
nobody 6249 6241 0 10:51 ? 00:00:00 nginx: worker process
nobody 7995 10419 0 10:30 ? 00:20:37 nginx: worker process is shutting down <= ここ
nobody 7995 10419 0 10:30 ? 00:20:37 nginx: worker process is shutting down
nobody 7996 10419 0 10:30 ? 00:20:37 nginx: worker process is shutting down
まとめると、nginx -s reload
を実行することでホットリロードを実現できますが、これは過去には十分でした。しかし、マイクロサービスとクラウドネイティブの急速な発展により、このソリューションはもはやユーザーの要件を満たしていません。
もしあなたのビジネスの更新頻度が週次や日次であれば、このNGINXのリロードはまだあなたのニーズを満たすことができます。しかし、更新頻度が時間単位や分単位になった場合はどうでしょうか?例えば、100台のNGINXサーバーがあり、1時間に1回リロードする場合、1日に2400回のリロードが必要になります。もしサーバーが1分ごとにリロードする場合、1日に8,640,000回のリロードが必要になり、これは受け入れられません。
プロセスの切り替えなしで、即座にコンテンツを更新できるソリューションが必要です。
メモリ内で即座に効果を発揮するホットリロード
Apache APISIXが誕生したとき、NGINXのホットリロード問題を解決するために設計されました。APISIXはNGINXとLuaの技術スタックに基づいて開発されており、etcdをコア設定センターとして使用するクラウドネイティブで高性能な完全動的マイクロサービスAPIゲートウェイです。新しいサーバー設定をリロードするためにサーバーを再起動する必要はなく、アップストリームサービス、ルート、またはプラグインの変更があってもサーバーを再起動する必要はありません。しかし、APISIXはNGINXの技術スタックに基づいて開発されているにもかかわらず、どのようにNGINXの制限を排除して完璧なホットリロードを実現できるのでしょうか?
まず、Apache APISIXのソフトウェアアーキテクチャを見てみましょう:
APISIXは、すべての設定をAPISIX CoreとPlugin Runtimeに配置し、動的な割り当てを使用できるようにすることで、完璧なホットリロードを実現できます。例えば、NGINXが設定ファイル内のパラメータを設定する必要がある場合、各変更はリロード後にのみ有効になります。ルートを動的に設定するために、Apache APISIXは特定の単一サーバーに1つのロケーションのみを設定します。このロケーションをメインエントリとして使用し、すべてのリクエストが最初にこれを通過し、その後APISIX Coreが特定のアップストリームを動的に割り当てます。Apache APISIXのルートモジュールは、サーバーの実行中にルートの追加/削除、変更、削除をサポートします。言い換えれば、動的なリロードを実現できます。これらの変更のいずれもユーザーの注意を引くことなく、通常のビジネスに影響を与えません。
次に、典型的なシナリオを紹介します。例えば、新しいドメインのリバースプロキシを追加したい場合、APISIXでアップストリームを作成し、新しいルートを追加するだけです。このプロセス中にNGINXを再起動する必要はありません。プラグインシステムの例として、APISIXはIP-restrictionプラグインを使用してIP許可リスト/ブロックリスト機能を実現できます。これらの機能更新はすべて動的であり、サーバーの再起動は必要ありません。etcdのおかげで、設定戦略はアドオンを使用して即座に更新でき、すべての設定が即座に有効になり、最高のユーザーエクスペリエンスを提供します。
結論
NGINXのホットリロードは、一部の状況で新旧のワーカープロセスが存在し、追加のリソース浪費を引き起こします。また、ホットリロードが頻繁すぎると、ビジネスデータが完全に失われる可能性がわずかにあります。クラウドネイティブとマイクロサービスの背景において、サービスの更新がますます頻繁になり、APIを管理する戦略も多様化しているため、ホットリロードに対する新しい要件が生まれています。
NGINXのホットリロードはもはやビジネス要件を満たしていません。クラウドネイティブ時代において、より高度なホットリロード戦略を持つAPIゲートウェイであるApache APISIXに切り替える時が来ています。さらに、APISIXに切り替えた後、ユーザーはAPIサービスの動的で統一された管理を行うことができ、管理効率を大幅に向上させることができます。