UUUM攻殻機動隊(エンジニアブログ)

UUUMのエンジニアによる技術ブログです

ロードバランサーって何?

ロードバランサーってあれでしょ?
いい感じに通信を分散してくれるんでしょ?

くらいの知識しかなかった執筆者、ハトネコエです。

ふわっとしすぎている知識から一歩進んで、もうちょっと詳細を知りたくなったので、
以前から気になっていた部分を調べ、社内勉強会で発表してみました。

〜〜お品書き(ここが謎だよロードバランサー)〜〜

1. ロードってなに? 道?

まずそもそもロードってなんなの?
「イエス マイロード」なの?「なんでもないようなことが幸せだったと思う」の?
いや、ELBって言うんだから少なくとも R oad ではないか、
でも通信の道を選んでるからRoadっぽくもあるよな、とか考えてました。

答えは load です。
load という単語を見ると私は「データを読み込む」って動詞のイメージしかないのですが、
この単語、もともとは荷馬車などに載せる「荷物」「重荷」を意味していたそうです。
「荷物を詰め込む」から始まり、「銃弾を補充する」とか「データを書き入れる」→「データ読み込み」といった意味を持つようになっていったようです。へぇ〜

ここで言う load 、「データ読み込み」の意味で捉えてもいいですが、
「重荷」→「負荷」の意味で理解するほうが、より単語への合点がいきやすいと思います。

ロードバランサーは、
load(負荷)をbalancing(分散)しているわけですね。

2. どんな仕組みで振り分ける先を決めるの?

ロードバランサーがどのサーバーにリクエストを振り分けるか決める方法は、いくらかあります。

  • 単純に順番にサーバーを選んでいく 「ラウンドロビン方式」
    (順番に選んでいく「ラウンドロビン (Round-Robin)」って言葉は、技術系関わりなく見ることの多い言葉なので覚えておくとお得)
  • 比率を定義する 「重みづけ」
  • 現在のコネクション数がもっとも小さいサーバーを選ぶ 「最小接続」

上のほかにもいろいろ分散方式はあります。こちらのサイトが参考になります。
ロードバランサ - ロードバランシングの種類

2-1. DNSラウンドロビン

DNSのAレコードに、同ドメインで複数のIPアドレスを割り当てることで、
ラウンドロビン方式を実現するものです。
ロードバランサーいらずで、DNSサーバーの設定だけです。

ドメイン名 IPアドレス
example.com 123.45.67.89
example.com 124.56.78.90
example.com 125.67.89.01

と、DNSに登録してあるとして、
クライアント(ブラウザを開いてるパソコン)は example.com のIPアドレスを教えてもらおうとします。
すると、DNSは 123.45.67.89 , 124.56.78.90 , 125.67.89.01 のすべてのIPアドレスを教えるのですが、
クライアントとしては1つのIPアドレスだけあればいいので1番目の 123.45.67.89 だけ使います。(クライアントの実装によりますが、ここでは1番目としておきます)

再びクライアントから問い合わせたとします。
ラウンドロビン機能が有効になっているDNSサーバーは、
124.56.78.90 , 125.67.89.01 , 123.45.67.89 と1個ぶん順番をずらしたIPアドレスのリストを返します。
すると、今度はクライアントは1番目の 124.56.78.90 にアクセスします。
つまり先ほどと違うサーバーにアクセスしに行きます。

このようにDNSが教えるIPアドレスのリストの順番を1つずつ変えていくことで、
各サーバーの負荷を均等にしようというのが、DNSラウンドロビンの仕組みです。
(実際はDNSキャッシュの関係もあり均等とはなりませんが)

2-2. RFC 3484 に従ったクライアントに対して従来のDNSラウンドロビンは使えない

DNSに設定するだけで負荷分散できるという、とても単純なDNSラウンドロビンですが、
RFC3484 の仕様に従って実装されたクライアントでは意味をなしません。

2-1. で説明しました方法は、
クライアントが受け取ったIPアドレスの一覧の中から必ず1番目を選ぶ、というものでした。

しかし、RFC3484 に従って実装したクライアントはそうではありません。

クライアントのIPアドレスと、DNSが返してきたIPアドレスの一覧をビットで比較して、
もっとも前方一致するもののうちの最初のIPアドレスを選択します。

こちらのページでわかりやすく解説されています。

クライアント側のIPアドレスを 192.168.0.1 として、DNSが返してきたIPアドレスの一覧を

  • 192.168.0.100
  • 192.168.0.10
  • 192.168.0.11
  • 192.168.0.15
  • 192.168.0.20

とします。

ビットに直すとそれぞれ、

  • クライアント側 192.168.0.1 : 11000000 10101000 00000000 00000001
  • 192.168.0.100 : 11000000 10101000 00000000 01100100
  • 192.168.0.10 : 11000000 10101000 00000000 00001010
  • 192.168.0.11 : 11000000 10101000 00000000 00001011
  • 192.168.0.15 : 11000000 10101000 00000000 00001101
  • 192.168.0.20 : 11000000 10101000 00000000 00010100

最後の8桁だけ並べると

00000001(クライアント側)

01100100
00001010
00001011
00001101
00010100

クライアント側のIPアドレスと前方一致するビット数は

  • 192.168.0.100 : 25bit
  • 192.168.0.10 : 28bit
  • 192.168.0.11 : 28bit
  • 192.168.0.15 : 28bit
  • 192.168.0.20 : 27bit

で 28bit がもっとも長く、その中でリストの一番上にある
192.168.0.10 が選択されます。

このリストがラウンドロビン機能で1つずつずれていったとき、
5回中3回が 192.168.0.10 に接続され、
1回 192.168.0.11、1回 192.168.0.15 にアクセスされるという偏(かたよ)りが生まれます。

じゃあどうしたらいいんだろう、できるだけ前方一致するようなIPアドレス群を所持する……? とか考えていたのですが、
ここを読んで、

複数のIPアドレスをリストにして返すのではなく、リクエストを受けるたびに単独のIPアドレスを動的に応答するようになっていれば良い

と書いてあって、なるほどと感心しました。

なお、DNSが返してきたIPアドレス一覧のうち、応答がない場合はそれでないIPアドレスを使う、という機能がOS側にあるためDNSで複数IPアドレスを返すのはアリという主張もあります。

2-3. コマンドで確認

実際にDNSが返すIPアドレスのリストの順番が変わっていくことを確認してみましょう。 dig コマンドや nslookup コマンドで可能です。
dig コマンドのほうがDNSサーバーの挙動をよりそのまま返してくれるので、今回のように詳しく見たい場合に向いています。

> dig yahoo.com

;; ANSWER SECTION:
yahoo.com.      635    IN  A   206.190.36.45
yahoo.com.      635    IN  A   98.139.180.149
yahoo.com.      635    IN  A   98.138.253.109

> dig yahoo.com

;; ANSWER SECTION:
yahoo.com.      1532   IN  A   98.138.253.109
yahoo.com.      1532   IN  A   98.139.180.149
yahoo.com.      1532   IN  A   206.190.36.45

リストの順番が変わっていることが確認できますね。

また、このような例もあります。

> dig google.com

;; ANSWER SECTION:
google.com.     299    IN  A   216.58.197.206

しばらく時間が経過したのちにもう一度同じコマンドを実行してみます。

> dig google.com

;; ANSWER SECTION:
google.com.     87 IN  A   172.217.26.14

返ってくるIPアドレスが変わりました。 Googleは、2-2. にて触れました、DNSサーバーが1つだけのIPアドレスを返す方式のようです。

2-4. AWSのELBはどの仕組み?

AWSのロードバランサーであるELB(Elastic Load Balancer)は、基本的には
1 : 1 : 1 : 1 : …… の重みづけ(比率)になるように各サーバーにリクエストを流しているようですが、
以下のページの検証によると、サーバーのレスポンス速度によってその比率は変化していくようです。
【ELB】負荷分散とEC2へのリクエスト数との関係について調べてみた | Developers.IO

なかなか興味深いです。

3. 複数のロードバランサを立てたとき、それらへの振り分けは誰がするの?

さて、そのELBですが、噂によると負荷状況に応じて勝手に増減するという話。
ロードバランサーが増えるなら、それのバランシングはどこがするのさ?
という謎があったのですが、そこは先ほどのDNSラウンドロビンのように、DNSサーバーに任せているそうです。

実際、AWSのドキュメントにも以下のようにあります。

クライアントがリクエストをロードバランサーに送信する前に、ドメインネームシステム (DNS) サーバーを使用してロードバランサーのドメイン名を解決します。インスタンスは amazonaws.com ドメインにあるため、DNS エントリは Amazon によって制御されます。Amazon DNS サーバーは、1 つ以上の IP アドレス (ロードバランサー用のロードバランサーノードの IP アドレス) をクライアントに返します。アプリケーションへのトラフィックが時間の経過とともに変化すると、Elastic Load Balancing はロードバランサーをスケーリングして DNS エントリを更新します。DNS エントリでは、有効期限 (TTL) も 60 秒に指定されているため、トラフィックの変化に応じて IP アドレスが迅速に再マップされる点に注意してください。

ELBのIPアドレス一覧はAmazonが持つDNSサーバーに勝手に登録されて、
ELBが増えたり減ったりしたら勝手にDNSサーバーのAレコードを更新している、という仕組みのようです。
(そういうわけでELBのIPアドレスは安定しません)

4. データはどんな道のりでサーバーからクライアントに渡されるの?

これは私が勘違いしていて、ずっと
「ロードバランサー経由してたらロードバランサーの負荷大きすぎるから、サーバーから直接クライアントにデータを返すんだよね?」
と思ってました。それはとても稀(まれ)な例のようです。

このサーバーから直接クライアントにレスポンスを返す方式を DSR構成 (Direct Server Return)と呼びます。
これはデメリットが多くて、サーバーからのレスポンスがロードバランサーを経由しないぶん、
HTTPなどアプリケーション層(Layer7)の情報をロードバランサーが得られず
TCP/UDPなどトランスポート層(Layer4)の情報のみでバランシングしなければならなくなる。
アプリケーション層が取れないからCookieを用いたスティッキーセッション(パーシステンス)もおこなえない。

また、HTTPS通信をする際、SSL証明書を用いた復号処理をサーバーが担わなければならず、
負荷の点でも良くないですし、SSL証明書を各サーバーに置くようにしなければならないコストもかかります。

非DSR構成であれば、レスポンスがロードバランサーを経由するので、
そこで復号処理をおこなうようにすればSSL証明書はロードバランサーにのみ置けばいいですし、
ロードバランサーとサーバー間の通信ではHTTP通信をするというシンプルな仕組みにすることも可能です。

動画配信サービスなど大量のレスポンスをサーバーが返すシステムで、
ロードバランサーのスループット(データ転送)性能が追いつかない、という場合であれば
DSR構成を考える意味は出てきますが、
最近のロードバランサー機器は計算処理性能もスループット性能も優れているため、
DSR構成を使う必要はほぼ発生しないそうです。上述のデメリットがかなり大きいですしね……。

5. 専用の機械を使わなくてもロードバランサーって立てられるの?

ロードバランサーと言うと F5 Networks.Inc の『BIG-IP』シリーズなどが有名です。
ですが……

F5、138万円の負荷分散装置「BIG-IP 800」で低価格市場に参入:ITpro

低価格帯で138万円ですよ!
それ以前の最安値モデルが299万円だったのに大幅な値下げ! みたいな記事なんですが「高いよ!」と(笑)
1990年の記事かな、とかいう気分になってきますが2013年の記事です。

業務用機器って高いですね……。
というわけで最後に、自宅サーバーをロードバランサー化する方法です。

『Linux Virtual Server』 で各サーバーへの分散(ロードバランシング)が実装でき、
『Keepalived』 で各サーバーのヘルスチェック(死活監視)がおこなえ、
2つを組み合わせることで、サーバーを高度なロードバランサー機器みたくすることができます。

Virtual Box で複数サーバーを擬似的に立て、
1つをロードバランサーとすることで試せますので、
ロードバランサーの仕組みをより詳しく知りたくなった方は実験してみるとおもしろいかなと思います。

参考 : 『「Linux Virtual Server」と「Keepalived」で作る冗長化ロードバランサ - さくらのナレッジ』

おわりに

長くなりましたが、ロードバランサーについてでした。
X-Forwarded-For についてとか、ヘルスチェックの仕組みとか、
まだまだ説明が足りていないロードバランサー関連の仕組みですが、
今回は私が気になっていた部分についてだけということで勘弁してください。

AWSのELBはこのような仕組みを詳しく知らなくても
それなりにロードバランサーできるようになってるからすごいねー、みたいな話があがって「たしかにー」という気持ちです。
クラウドの浸透により、インフラエンジニアに必要な専門性は低下したという論を見ることがありますが、
短期的にはそうと言えるものの、障害が起きたときにこういう仕組みを知らないと「詰む」ので、
結局は仕組みを理解していることは必要なのだろうなと感じています。
ライブラリのコードが読めないのにライブラリを使っていると困るときが来る感覚ですね。

インフラは全然わからないので、今後ももっと学んでいきたく思います。
誤りがありましたらコメントにてお教えくださると幸いです。


UUUMでは、「仕組み知りたい!」「機械があったら分解したい!」などの
コドモゴコロあふれるエンジニアを募集中です。

サーバーサイドエンジニア・アプリエンジニアなどなど、幅広く募集しておりますよ!

www.wantedly.com

www.wantedly.com

なんと新卒採用も始めました。

paiza.jp