Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】Building Your Own Load Balancer in Node.js

2025年09月18日に「Dev.to」が公開したITニュース「Building Your Own Load Balancer in Node.js」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Node.jsでロードバランサーを構築し、アクセス集中によるサーバーダウンを防ぐ方法を解説。トラフィックを複数サーバーへ分散させ負荷を軽減。DNSベースルーティングは高速・軽量で柔軟だ。Node.jsライブラリを使えば、ユーザー位置やサーバー稼働状況に応じ、動的に最適なサーバーへ誘導できる。

出典: Building Your Own Load Balancer in Node.js | Dev.to公開日:

ITニュース解説

ウェブサイトが急に人気になり、何百、何千ものユーザーが同時に訪れるようになった状況を想像してほしい。もし全てのアクセスがたった1台のサーバーに集中したら、そのサーバーは処理能力を超えてしまい、動作が非常に遅くなったり、最悪の場合は停止してしまう可能性がある。これは、せっかく多くの人に利用してもらえるようになったサービスにとって、大きな問題となる。

この問題を解決する自然な方法は、複数のサーバーを用意し、それらのサーバーにアクセスを分散させることである。たとえば、2台、3台、あるいは10台のサーバーを準備し、ユーザーからのリクエストをそれぞれのサーバーに均等に、あるいは適切に振り分ける。このとき、どのユーザーをどのサーバーに送るかを決定し、トラフィックを適切に「交通整理」する役割を担うのが、ロードバランサーである。ロードバランサーは、特定の1台のサーバーに全ての負担がかからないようにすることで、サービスの安定稼働とパフォーマンス維持に貢献する。

ロードバランシングにはいくつかの異なるアプローチがある。それぞれの方式には特徴があり、メリットとデメリットが存在する。

一つ目の方法は「リバースプロキシ」と呼ばれる。この方式では、全てのユーザーからのアクセスはまず1台のメインサーバー(リバースプロキシ)を通過する。このプロキシサーバーが全てのリクエストを受け取り、その後ろにある複数のバックエンドサーバーのいずれかに転送する。これは、TCPのような通信の基本層で行うことも、HTTPのようなアプリケーション層で行うことも可能だ。例えば、NginxというソフトウェアがHTTPリクエストのリバースプロキシとしてよく利用される。この方法の利点は、設定が比較的シンプルであること、どんなアプリケーションにも適用できること、そしてTLS(暗号化通信)の終端処理やWebSocket、ヘッダー操作といった追加機能を簡単に組み込める点にある。しかし、欠点として、全てのリクエストがこの「ゲートキーパー」となるプロキシサーバーを通過するため、もしこのプロキシサーバー自体が過負荷になったり、ユーザーから物理的に遠い場所にあったりすると、パフォーマンスが低下する可能性がある。さらに、プロキシサーバーが停止してしまうと、全てのアクセスが途絶えてしまう「単一障害点」になりうるリスクも存在する。

二つ目の方法は「リダイレクターサーバー」である。リバースプロキシのように全てのリクエストを継続的に転送し続けるのではなく、メインサーバーは最初のアクセスだけを受け付け、その後、クライアント(ユーザーのブラウザなど)を別の特定のサーバーやサブドメインに「リダイレクト」する。例えば、プロキシサーバーが最初のリクエストを受け取った際、ユーザーがヨーロッパからのアクセスだと判断し、eu.example.comのようなヨーロッパ地域のサーバーへ接続するようにクライアントに指示する。すると、クライアントはそれ以降、直接その指定されたサーバーと通信するようになる。Node.jsサーバーを使って、ユーザーのIPアドレスから地域を判別し、適切なサーバーのURLを返信するような処理がこれにあたる。この方法のメリットは、最初の一歩以降はメインプロキシを介さずにトラフィックが流れるため、メインプロキシの負荷を軽減できる点だ。一方で、ユーザーは最初の接続を中央のサーバーに依存するため、そのサーバーが混雑していたり、停止していたりすると、新しいセッションを正しくルーティングできないという欠点がある。

三つ目の方法は「Anycast / IPレベルルーティング」である。これはCloudflareやGoogleのような大規模なプロバイダーで利用されている非常に高度な技術だ。複数の地理的な拠点から同じIPアドレスをインターネットにアナウンスすることで、インターネットのルーティング(経路制御)の仕組みが自動的にユーザーを最も近い拠点に誘導する。例えば、1.2.3.4というIPアドレスがアムステルダムとニューヨークの両方からアナウンスされていれば、BGPというプロトコルによって、クライアントからのトラフィックは自動的に最も近いサーバーへ送られる。この方法の最大のメリットは、非常に高速で自動的、そして耐障害性が高いことだ。しかし、BGPのアナウンスやAS(自律システム)の管理といった専門的な知識と環境が必要で、小規模な企業や一般的な開発者にとっては実現が難しいという大きな欠点がある。

四つ目の方法は「DNSベースルーティング」である。これは、ウェブサイトのドメイン名からIPアドレスを解決する「DNS(Domain Name System)」の仕組みを利用するものだ。権威DNSサーバーは、ユーザーからの問い合わせに応じて、様々な情報(例えば、ユーザーのIPアドレスの場所など)を判断材料にして、異なるIPアドレスを返すことができる。これにより、TCP接続が開始されるよりも前の段階で、ユーザーを異なるデータセンターやサーバーに効果的にルーティングすることが可能になる。例えば、example.comへのアクセスに対して、アメリカからのユーザーには192.0.2.10というIPアドレスを、ヨーロッパからのユーザーには198.51.100.20というIPアドレスを返すといった具合だ。この方法のメリットは、非常に軽量でスケーラブルであること、そして単一のボトルネックとなるポイントを回避できる点にある。しかし、DNSのキャッシュの仕組みや、DNSリゾルバーの動作によっては、IPアドレスの変更が即座に反映されず、多少の遅延が生じる可能性があるという欠点がある。

これらのアプローチの中で、高価なハードウェアや複雑なAnycastやBGPといった設定なしに、現実的にトラフィックを分散させる最も実用的な方法は、この「DNSベースルーティング」である。インターネット上の全ての接続は、ドメイン名からIPアドレスを調べるDNSルックアップから始まる。つまり、このDNSの応答をコントロールできれば、ユーザーがどこに接続するかをコントロールできることになる。DNSはHTTPに比べて非常に軽量な通信だ。クライアントが「example.comのIPアドレスは何ですか?」と問い合わせると、あなたの権威DNSサーバーは「203.0.113.10に接続してください」とシンプルに答える。この非常に小さなリクエストとレスポンスの間に、重いプロキシサーバーが介入する必要はない。

このDNSの仕組みを上手く利用することで、以下のような動的な判断をリアルタイムで行うことが可能になる。

  • 地理ルーティング: ユーザーに最も近いサーバーはどれか(ユーザーのIPアドレスから地域を判別し、物理的に近いデータセンターのサーバーへ誘導する)。
  • ヘルスアウェアルーティング: 現在、正常に稼働していてアクセスを受け入れられるサーバーはどれか(定期的なヘルスチェックでサーバーの状態を監視し、故障しているサーバーにはトラフィックを送らない)。
  • 重み付けルーティング: 複数のサーバー間でどのようにトラフィックを分割するか(例えば、特定のサーバーに多くのアクセスを集中させたり、新しいバージョンのアプリケーションを一部のユーザーにだけ試してもらう「カナリアテスト」を行ったりする)。

このようにDNSは、インターネットの基盤に組み込まれた「交通整理役」として機能し、高速で軽量、そして驚くほど柔軟な制御を可能にする。しかし、一般的なDNSソフトウェアの多くは、あらかじめ設定されたゾーンファイルに基づいて静的なIPアドレスを返すだけである。ここでNode.jsの出番だ。Node.jsを使えば、権威DNSサーバー自体をプログラムで構築し、ユーザーごと、クエリごと、瞬間ごとに変化する動的な応答を生成できる。数行のJavaScriptコードで、あなたの権威DNSサーバーを完全に制御し、アプリケーションのロジックに組み込むことができるのだ。

Node.jsを使ってDNSベースのロードバランサーを実際に構築するには、権威DNSサーバーとして機能できるライブラリが必要となる。Node.jsのエコシステムには「dnssec-server」というライブラリがあり、これを使うことで動的なDNS応答の生成が可能になる。このライブラリは、従来のDNSソフトウェアが静的なゾーンファイルに依存するのとは異なり、Node.jsのHTTPモジュールのようなシンプルな方法で、プログラムによってDNSの応答を生成できる。つまり、あなたのアプリケーションがリアルタイムにどのIPアドレスを返すかを決定できるのだ。このライブラリは、動的な制御とDNSSECサポートを標準で提供するNode.js唯一のライブラリである。

dnssec-serverを使った基本的な仕組みは次のようになる。まず、ウェブサイトへのアクセスに伴い、DNSクエリ(例えばexample.comのAレコードを要求する問い合わせ)があなたのDNSサーバーに届く。次に、サーバーに設定されたハンドラ関数が実行される。この関数の中で、あなたはクエリの内容を調べたり、ユーザーのGeoIP(地理情報)を確認したり、サーバーの健全性マップを参照したり、独自のカスタムロジックを適用したりできる。そして最後に、そのロジックに基づいて1つまたは複数の応答(IPv4アドレス用のAレコード、IPv6アドレス用のAAAAレコードなど)を、それぞれにキャッシュ保持時間(TTL)を設定してクライアントに返す。

具体的な例を見てみよう。

最初の例は「Geoベースの応答」だ。 dnssec-serverライブラリとgeoip-liteというGeoIPヘルパーライブラリをインポートし、あらかじめ地域ごとのサーバーIPアドレスのマップ(EDGES)を用意する。pickRegion関数では、ユーザーのIPアドレスから国コードを特定し、それがEU加盟国であれば「eu」地域、そうでなければ「us」地域と判断する。 DNSサーバーのハンドラ関数では、req.nameが対象ドメイン(example.com.)の場合にのみ処理を行う。ユーザーのIPアドレス(req.remoteAddress)からpickRegion関数で地域を判別し、その地域のIPv4アドレス(Aレコード)とIPv6アドレス(AAAAレコード)を、要求されたレコードタイプに応じて応答データに追加する。ttlは30秒と設定されており、これは応答が30秒間キャッシュされることを意味する。このコードにより、example.comへのクエリごとにユーザーのIPアドレスがチェックされ、ユーザーがアメリカに近いかヨーロッパに近いかに応じて、それぞれの地域のサーバーIPアドレスが返される。

二つ目の例は「ヘルスアウェアな応答」だ。 ここでもdnssec-serverライブラリをインポートする。healthというオブジェクトで各地域のサーバーが現在健全であるか(truefalseか)を管理する。この情報は、バックグラウンドで定期的に行われるヘルスチェックによって更新されることを想定している。EDGESオブジェクトは同様に地域ごとのIPアドレスを定義する。bestRegion関数は、まずEU地域のサーバーが健全であれば「eu」を返し、そうでなければUS地域のサーバーが健全であれば「us」を返す。どちらも健全でない場合は、フォールバックとして「us」を返すようにしている。 DNSサーバーのハンドラ関数では、example.com.へのクエリに対して、bestRegion関数を呼び出して最も良い健全な地域を決定する。その後は、Geoベースの例と同様に、要求されたレコードタイプに応じて、決定された地域のIPv4およびIPv6アドレスを応答データに追加して送信する。このコードにより、各地域のサーバーの稼働状況が監視され、もしEU地域のサーバーがダウンしていても、自動的にUS地域のサーバーにトラフィックを振り分けることで、ウェブサイトの継続的なサービス提供が可能になる。

構築したNode.jsのDNSサーバーを実際に利用するためには、あなたのドメインがそのサーバーを権威DNSサーバーとして認識するように設定する必要がある。通常、あなたのドメインのDNSサービスは、ドメインレジストラ(NamecheapやGoDaddyなど)やクラウドプロバイダー(AWS Route 53やCloudflare DNSなど)、あるいはBINDのような従来のDNSソフトウェアによって提供されている。 もし明示的に自分の権威DNSサーバーを設定していなければ、デフォルトでこれらのサービスがあなたのDNSを担当しているはずだ。 あなたのドメインのネームサーバー(NS)レコードを、あなたが構築したNode.js DNSサーバーのIPアドレスを指すように設定する必要がある。例えば、ドメイン登録サービスのダッシュボードで、「カスタムDNS」を選択し、ns1.example.comns2.example.comといったネームサーバー名とそのIPアドレスを、あなたのNode.js DNSサーバーのIPアドレスに設定する。 この設定が保存され、インターネット全体に伝播すると、あなたのドメインへのDNSクエリは、あなたが構築したNode.jsサーバーに到達するようになる。そこから先は、あなたがプログラムでDNSの応答を完全に制御できるため、DNS層があなたのアプリケーションロジックの一部となり、外部サービスに依存することなく、ニーズに合わせて柔軟かつ迅速にトラフィックを制御できるようになる。

関連コンテンツ

関連IT用語