複数のサーバで負荷分散や可用性を確保するには、一般的にはサーバロードバランサを使います。ロードバランサがない環境で、少しでも負荷を分散し、可用性を高める方法の1つが DNS ラウンドロビンです。
この記事では、クライアントからプロキシサーバ2台への接続を DNS ラウンドロビンで分散し、片方のプロキシが止まったときにブラウザ(Microsoft Edge)がどう切り替わるかを、パケットキャプチャと net-export のログで確認します。
- DNS ラウンドロビンで、DNS レスポンスがどう変わるか
- プロキシ1号機の電源 OFF とサービス停止で、ブラウザの切り替わり方がどう違うか
- DNS ラウンドロビンの注意点と、ロードバランサとの違い
DNS ラウンドロビンの仕組み
DNS ラウンドロビンは、1つの名前に複数の IP アドレスを登録し、DNS レスポンスの中のアドレスの並び順を問い合わせのたびに入れ替えることで、接続先を分散する方法です。
今回の DNS サーバは Active Directory の DNS サーバ(ドメイン名 hirotanoblog.local)です。1つの名前 proxy-sv に、A レコードを2つ(10.10.1.100 と 10.10.1.101)登録します。
この記事の画面は、実際の画面ではなく、検証時の画面から見るポイントを抜き出して描いたイメージです。バージョンによって、項目の並びや表記は変わります。
| 名前 | 種類 | データ |
|---|---|---|
| 1proxy-sv | Host (A) | 10.10.1.100 |
| proxy-sv | Host (A) | 10.10.1.101 |
| No. | 表示 | 意味 |
|---|---|---|
| 1 | proxy-sv が2行 | 同じ名前に、2つの A レコード(10.10.1.100 と 10.10.1.101)を登録している |
DNS ラウンドロビンというと、問い合わせのたびにアドレスを1つずつ順番に返すと思われがちです。実際には、登録した A レコードがすべてレスポンスに入り、その並び順が問い合わせのたびに入れ替わります。
クライアントから nslookup で proxy-sv を3回問い合わせた結果が次の画面です。どの回もアドレスは2つ返っていて、並び順だけが変わっています。
C:\Users\administrator>nslookup既定のサーバー: UnKnownAddress: 10.10.1.1 > proxy-svサーバー: UnKnownAddress: 10.10.1.1 名前: proxy-sv.hirotanoblog.local1Addresses: 10.10.1.101 10.10.1.100 > proxy-svサーバー: UnKnownAddress: 10.10.1.1 名前: proxy-sv.hirotanoblog.local2Addresses: 10.10.1.100 10.10.1.101 > proxy-svサーバー: UnKnownAddress: 10.10.1.1 名前: proxy-sv.hirotanoblog.local3Addresses: 10.10.1.101 10.10.1.100
| No. | 表示 | 意味 |
|---|---|---|
| 1 | 1回目 | 10.10.1.101 → 10.10.1.100 の順 |
| 2 | 2回目 | 10.10.1.100 → 10.10.1.101 の順(入れ替わった) |
| 3 | 3回目 | 10.10.1.101 → 10.10.1.100 の順(1回目と同じ並びに戻った) |
クライアントのアプリケーションは、受け取ったアドレスを先頭から順に使うのが一般的です。問い合わせごとに先頭のアドレスが変わるので、クライアントの接続先がプロキシ1号機と2号機に分かれます。
- Windows Server の DNS サーバでは、ラウンドロビンが既定で有効です。DNS サーバのプロパティの[詳細設定]タブで無効にもできます。
- Windows Server の DNS サーバには、ネットマスクの順序付け(netmask ordering)という機能もあり、既定で有効です。クライアントと同じサブネット(既定では /24 単位)のアドレスがあれば、それを先頭に並べます。今回はクライアントも2つのアドレスも 10.10.1.0/24 にあるので、2つのアドレスの間でラウンドロビンが働いています。
- OS によっては、受け取ったアドレスを独自の規則(IPv6 と IPv4 のどちらを優先するか、など)で並べ替えてから使います。このため、どのクライアントでも DNS レスポンスの先頭に接続するとは限りません。
動作確認
今回は、プロキシサーバの負荷分散を DNS ラウンドロビンで実装します。クライアントのプロキシ設定には、IP アドレスではなく名前の proxy-sv(ポート 3128)を指定します。名前で指定するので、ブラウザは DNS で解決したアドレスに接続します。ブラウザは Microsoft Edge を使い、片方のプロキシが止まったときの切り替わりも確認します。
| 1プロキシ サーバーを使う | オン |
| 2アドレス | http://proxy-sv |
| ポート | 3128 |
| No. | 項目 | 設定内容 |
|---|---|---|
| 1 | プロキシ サーバーを使う | オン |
| 2 | アドレス、ポート | http://proxy-sv、3128。プロキシを名前で指定する |
Edge は、この Windows のプロキシ設定を使って通信します。次のキャプチャは、https://www.bing.com へプロキシ1号機経由で接続したあと、プロキシ1号機の電源を OFF にしたときのものです(説明に不要なパケットは省いています)。
| No. | Time | Source | Destination | Protocol | Info |
|---|---|---|---|---|---|
| 11 | 0.000000 | 10.10.1.50 | 10.10.1.1 | DNS | Standard query 0x3c6c A proxy-sv.hirotanoblog.local |
| 2 | 0.000601 | 10.10.1.1 | 10.10.1.50 | DNS | Standard query response 0x3c6c A proxy-sv.hirotanoblog.local A 10.10.1.100 A 10.10.1.101 |
| 23 | 0.007617 | 10.10.1.50 | 10.10.1.100 | HTTP | CONNECT www.bing.com:443 HTTP/1.1 |
| 34 | 60.020586 | 10.10.1.50 | 10.10.1.100 | TCP | 49579 → 3128 [SYN] Seq=0 Win=64240 … |
| 5 | 60.787359 | 10.10.1.50 | 10.10.1.100 | TCP | 51164 → 3128 [SYN] Seq=0 Win=64240 … |
| 6 | 61.051894 | 10.10.1.50 | 10.10.1.100 | TCP | [TCP Retransmission] … 49579 → 3128 [SYN] … |
| 7 | 61.814705 | 10.10.1.50 | 10.10.1.100 | TCP | [TCP Retransmission] … 51164 → 3128 [SYN] … |
| 8 | 69.868707 | 10.10.1.50 | 10.10.1.100 | TCP | 56174 → 3128 [SYN] Seq=0 Win=64240 … |
| 9 | 69.970801 | 10.10.1.50 | 10.10.1.100 | TCP | 55978 → 3128 [SYN] Seq=0 Win=64240 … |
| 10 | 70.647947 | 10.10.1.50 | 10.10.1.100 | TCP | 59694 → 3128 [SYN] Seq=0 Win=64240 … |
| 11 | 70.742838 | 10.10.1.50 | 10.10.1.100 | TCP | 60862 → 3128 [SYN] Seq=0 Win=64240 … |
| 12 | 71.319795 | 10.10.1.50 | 10.10.1.100 | TCP | 54738 → 3128 [SYN] Seq=0 Win=64240 … |
| 13 | 71.412886 | 10.10.1.50 | 10.10.1.100 | TCP | [TCP Retransmission] … 56174 → 3128 [SYN] … |
| 414 | 71.414135 | 10.10.1.50 | 10.10.1.101 | HTTP | CONNECT www.bing.com:443 HTTP/1.1 |
| No. | 表示 | 意味 |
|---|---|---|
| 1 | No.1〜2 DNS | proxy-sv の名前解決。レスポンスは 10.10.1.100、10.10.1.101 の順 |
| 2 | No.3 CONNECT | 先頭のプロキシ1号機(10.10.1.100)に接続 |
| 3 | No.4〜13 SYN | 電源 OFF のプロキシ1号機へ接続を試みるが、応答がない(再送が続く) |
| 4 | No.14 CONNECT | プロキシ2号機(10.10.1.101)に切り替わる |
DNS クエリーとレスポンス(No.1〜2)
クライアントが DNS サーバに proxy-sv を問い合わせます。DNS レスポンスには、10.10.1.100、10.10.1.101 の順でアドレスが2つ入っています。次の画面は、DNS レスポンスの Answers 部分です。
▾ Answers1 ▸ proxy-sv.hirotanoblog.local: type A, class IN, addr 10.10.1.100 ▸ proxy-sv.hirotanoblog.local: type A, class IN, addr 10.10.1.101
| No. | 表示 | 意味 |
|---|---|---|
| 1 | type A が2つ | A レコードが2つ返っている。先頭は 10.10.1.100 |
プロキシ1号機に接続(No.3)
Edge は、先頭のアドレス 10.10.1.100(プロキシ1号機)の 3128 番ポートに接続します。HTTPS のサイトにプロキシ経由でアクセスするときは、ブラウザがプロキシに CONNECT www.bing.com:443 を送り、プロキシに宛先までのトンネルを作ってもらいます。暗号化された通信は、そのトンネルの中を流れます。
プロキシ1号機の電源 OFF(No.4〜13)
プロキシ1号機の電源を OFF にします。Edge はプロキシ1号機の 3128 番ポートに TCP の接続(SYN)を試みますが、電源が切れているので応答が返らず、SYN の再送が続きます。キャプチャでは大量に出るため、一部を省いています。
プロキシ2号機に接続(No.14)
接続先が 10.10.1.101(プロキシ2号機)に切り替わり、Web 通信が復旧します。このキャプチャでは、プロキシ1号機への最初の SYN(No.4)から約11秒後に、プロキシ2号機への CONNECT(No.14)が出ています。
障害時のブラウザの挙動
プロキシサーバに障害が起きたときの Edge の動きを、net-export で取得したログで確認しました。net-export の使い方は、net-export の使い方 を参照してください。
プロキシ1号機の電源を OFF にした場合
プロキシ1号機(10.10.1.100)経由で通信しているところで、電源を OFF にします。Edge は 10.10.1.100:3128 へ TCP 接続を試みますが、応答が返らない状態が続きます。
5087: SOCKEThttps://www.bing.comStart Time: 2022-08-01 19:44:29.303 t=123989 [st= 0] +SOCKET_ALIVE [dt=8015] --> source_dependency = 5086 (SSL_CONNECT_JOB)t=123989 [st= 0] +TCP_CONNECT [dt=8015]1 --> address_list = ["10.10.1.100:3128","10.10.1.101:3128"] --> aliases = [] --> name_resolution_handle = 02t=123989 [st= 0] +TCP_CONNECT_ATTEMPT [dt=8015] --> address = "10.10.1.100:3128"3t=132004 [st=8015] SOCKET_CLOSEDt=132004 [st=8015] -SOCKET_ALIVE
| No. | 表示 | 意味 |
|---|---|---|
| 1 | address_list | 接続先の候補。DNS レスポンスの順に 10.10.1.100、10.10.1.101 が並んでいる |
| 2 | TCP_CONNECT_ATTEMPT | 先頭の 10.10.1.100:3128 に接続を試みる。応答がないまま約8秒(dt=8015)続く |
| 3 | SOCKET_CLOSED | 接続できないまま、このソケットを閉じる |
この接続試行が終わる前(t=130408、試行開始から約6.4秒後)に、Edge は proxy-sv の名前解決をやり直しています。今度は、アドレスの並びが 10.10.1.101、10.10.1.100 の順に入れ替わっています。
5109: HOST_RESOLVER_IMPL_JOBproxy-svStart Time: 2022-08-01 19:44:35.722 t=130408 [st=0] +HOST_RESOLVER_MANAGER_JOB [dt=1] --> dns_query_types = ["A"]1 --> host = "proxy-sv" --> network_isolation_key = "null null" --> secure_dns_mode = 0 --> source_dependency = 5108 (SSL_CONNECT_JOB) ⋮ (中略)t=130408 [st=0] -HOST_RESOLVER_MANAGER_PROC_TASK2 --> address_list = ["10.10.1.101:0","10.10.1.100:0"] --> aliases = [] --> name_resolution_handle = 0t=130408 [st=0] HOST_RESOLVER_MANAGER_ATTEMPT_FINISHED --> attempt_number = 1t=130409 [st=1] -HOST_RESOLVER_MANAGER_JOB
| No. | 表示 | 意味 |
|---|---|---|
| 1 | host | 名前解決する名前。プロキシの名前 proxy-sv |
| 2 | address_list | 結果は 10.10.1.101、10.10.1.100 の順。DNS ラウンドロビンで並びが入れ替わっている |
Edge は新しい並びの先頭 10.10.1.101:3128(プロキシ2号機)へ接続し、CONNECT を送ります。これで Web 通信が復旧します。
5110: SOCKEThttps://www.bing.comStart Time: 2022-08-01 19:44:35.723 t=130409 [st= 0] +SOCKET_ALIVE [dt=14516+] --> source_dependency = 5108 (SSL_CONNECT_JOB)t=130409 [st= 0] +TCP_CONNECT [dt=0]1 --> address_list = ["10.10.1.101:3128","10.10.1.100:3128"] --> aliases = [] --> name_resolution_handle = 02t=130409 [st= 0] TCP_CONNECT_ATTEMPT [dt=0] --> address = "10.10.1.101:3128"t=130409 [st= 0] -TCP_CONNECT --> local_address = "10.10.1.50:62785" --> remote_address = "10.10.1.101:3128"t=130409 [st= 0] +HTTP_TRANSACTION_TUNNEL_SEND_REQUEST [dt=0]t=130409 [st= 0] HTTP_TRANSACTION_SEND_TUNNEL_HEADERS3 --> CONNECT www.bing.com:443 HTTP/1.1 Host: www.bing.com:443 Proxy-Connection: keep-alive
| No. | 表示 | 意味 |
|---|---|---|
| 1 | address_list | やり直した名前解決の結果。先頭が 10.10.1.101 になっている |
| 2 | TCP_CONNECT_ATTEMPT | 10.10.1.101:3128 にすぐ接続できた(dt=0) |
| 3 | CONNECT www.bing.com:443 | プロキシ2号機にトンネルの作成を依頼する |
プロキシ1号機のサービスを停止した場合
次は、電源 OFF ではなく、プロキシ1号機のプロキシサービスだけを停止します。サーバ自体は動いているので、3128 番ポートへの接続はサーバから拒否(RST)されます。Edge は Windows のソケットのエラーで接続の失敗を知り、同じ候補リストの次のアドレス 10.10.1.101 へ接続します。
1970: SOCKEThttps://www.bing.comStart Time: 2022-08-01 20:00:54.201 t= 88745 [st= 0] +SOCKET_ALIVE [dt=29946+] --> source_dependency = 1969 (SSL_CONNECT_JOB)t= 88745 [st= 0] +TCP_CONNECT [dt=2063]1 --> address_list = ["10.10.1.100:3128","10.10.1.101:3128"] --> aliases = [] --> name_resolution_handle = 02t= 88745 [st= 0] +TCP_CONNECT_ATTEMPT [dt=2063] --> address = "10.10.1.100:3128"3t= 90808 [st=2063] -TCP_CONNECT_ATTEMPT --> os_error = 10061t= 90808 [st=2063] SOCKET_CLOSED4t= 90808 [st=2063] TCP_CONNECT_ATTEMPT [dt=0] --> address = "10.10.1.101:3128"t= 90808 [st=2063] -TCP_CONNECT --> local_address = "10.10.1.50:62954" --> remote_address = "10.10.1.101:3128"t= 90809 [st=2064] +HTTP_TRANSACTION_TUNNEL_SEND_REQUEST [dt=0]t= 90809 [st=2064] HTTP_TRANSACTION_SEND_TUNNEL_HEADERS --> CONNECT www.bing.com:443 HTTP/1.1 Host: www.bing.com:443 Proxy-Connection: keep-alive
| No. | 表示 | 意味 |
|---|---|---|
| 1 | address_list | 接続先の候補。10.10.1.100、10.10.1.101 の順 |
| 2 | TCP_CONNECT_ATTEMPT | 先頭の 10.10.1.100:3128 に接続を試みる |
| 3 | os_error = 10061 | Windows ソケットのエラー WSAECONNREFUSED(接続拒否)。このログでは、拒否と判定されるまで約2秒(dt=2063)かかっている |
| 4 | TCP_CONNECT_ATTEMPT | 同じ候補リストの次のアドレス 10.10.1.101:3128 にすぐ接続できた |
電源 OFF とサービス停止で、切り替わり方は次のように違いました。Edge と同じく、Chrome でも同様の動作になりました。
| 障害の種類 | プロキシ1号機の反応 | Edge の動き |
|---|---|---|
| 電源 OFF | 応答なし(SYN の再送が続く) | 1号機への接続を試み続ける間に名前解決をやり直し、入れ替わった並びの先頭(2号機)に接続した |
| サービス停止 | 接続を拒否(RST) | エラー 10061 を受け取り、同じ候補リストの次のアドレス(2号機)にすぐ接続した |
DNS ラウンドロビンの注意点
DNS ラウンドロビンは、DNS サーバの設定だけで始められる手軽な方法ですが、次の点に注意が必要です。
- サーバの生死を見ていない。DNS サーバはプロキシの状態を監視していないので、障害中のサーバのアドレスも DNS レスポンスに含め続けます。そのため、クライアントは障害中のサーバへの接続を試み、切り替わるまで待たされることがあります。
- 切り替え方はアプリケーション次第。複数のアドレスを受け取ったあと、次のアドレスを試すか、どれくらい待つかはアプリケーションの実装で決まります。今回の Edge と Chrome の動きが、ほかのアプリケーションでも同じとは限りません。
- DNS のキャッシュが効く。クライアントやキャッシュ DNS サーバは、TTL の間は DNS レスポンスを保持します。そのため、分散は名前解決の単位になり、接続数やサーバの負荷が均等になるとは限りません。
| 比較項目 | DNS ラウンドロビン | サーバロードバランサ |
|---|---|---|
| 必要なもの | DNS サーバの設定だけ | ロードバランサ(専用機器や仮想アプライアンスなど) |
| サーバの監視 | しない | ヘルスチェックで監視し、障害中のサーバには振り分けない |
| 障害時の切り替え | クライアント(アプリケーション)任せ | ロードバランサが残りのサーバに振り分ける |
| 分散の単位 | 名前解決の単位(キャッシュの影響を受ける) | 接続(セッション)の単位 |
負荷分散と可用性の安定度は、やはりロードバランサのほうが上です。DNS ラウンドロビンを本番環境に適用する場合は、実際に使うアプリケーションで、障害時の動きを十分に検証してください。
まとめ
| 項目 | 内容 |
|---|---|
| DNS ラウンドロビン | 1つの名前に複数の A レコードを登録し、DNS レスポンスの並び順を問い合わせのたびに入れ替える |
| 接続先の決まり方 | クライアントは受け取ったアドレスを先頭から使うのが一般的。並び順が変わるので、接続先が分かれる |
| 電源 OFF の場合 | 応答がなく、SYN の再送が続く。今回の Edge は名前解決をやり直し、プロキシ2号機に切り替わった |
| サービス停止の場合 | RST で接続を拒否され(エラー 10061)、同じ候補リストの次のアドレスにすぐ切り替わった |
| 注意点 | サーバの監視をしない、切り替えはアプリケーション次第、DNS キャッシュの影響を受ける |
コメント