X

Oracle Solaris, Oarcle ハードウェア製品に関する情報

  • Sun
    November 19, 2009

IPMP でネットワークの負荷を分散する

Guest Author


はじめに

Solaris の IPMP には送信パケットの負荷を分散するアウトバウンド・ロード・スプレッディングという機能があります。マニュアル にも記載されていますので、ご存知の方も多いと思いますが、この機能を利用するとサーバからの返信時(アウトバウンド)のネットワークの負荷(ロード)を複数のインターフェイスに分散(スプレッディング)する事が可能になり、結果としてスループットを上げることができる場合があります。今回の記事ではその挙動をご覧頂きたいと思います。


検証環境

検証用に次の図の様な環境を用意しました。サーバには igb1 と igb2 という 1 Gigabit のネットワークインターフェイスがあり、どちらも同じネットワークセグメントに接続されています。この 2 つのインターフェイスに負荷を分散することができれば、最大で 2 Gigabit の帯域を使用出来ることになります。

igb1 の IP アドレスは 192.168.10.1/24 で、igb2 の IP アドレスは 192.168.10.2/24 です。サーバと同じセグメントにはクライアントマシンが 2 台接続されています。クライアント A の IP アドレスは 192.168.10.3/24, クライアント B の IP アドレスは 192.168.10.4/24 です。なお、サーバにはテスト用に lighttpd をインストールしてあります。サーバもクライアントも OS は Solaris 10 10/09 です。

   +-----------------+                 o Switching Hub 192.168.10.0/24
| | |
| | 192.168.10.1 |
| igb1 +-----------------+
| | | 192.168.10.3 +----------+
| Server | +-----------------+ Client A |
| | 192.168.10.2 | +----------+
| igb2 +-----------------+
| | | 192.168.10.4 +----------+
| | +-----------------+ Client B |
+-----------------+ | +----------+
o

サーバ側のネットワークの設定は以下の通り行いました。

 # ifconifg igb1 plumb
# ifconfig igb1 inet 192.168.10.1/24 broadcast + up
# ifconfig igb2 plumb
# ifconfig igb2 inet 192.168.10.2/24 broadcast + up

なお、ルーティングは停止してあります。

 # routeadm 
Configuration Current Current
Option Configuration System State
---------------------------------------------------------------
IPv4 routing disabled disabled
IPv6 routing disabled disabled
IPv4 forwarding disabled disabled
IPv6 forwarding disabled disabled
...

SPARC マシンで試す場合は local-mac-address? を true に設定して下さい。

 # eeprom local-mac-address?=true
# reboot


[検証1] IPMP を組んでいない場合の挙動

この検証環境を使って、まずは IPMP を組んでいない場合の挙動から見て行きましょう。


HTTP で接続する

テストには HTTP を使用しました。2 台のクライアントからサーバの HTTP ポートに telnet コマンドで同時に接続し、返信パケットの負荷分散が行われるかを確認します。クライアントからの送信時もネットワーク帯域を有効に利用するため、クライアントはそれぞれ別のネットワークインターフェイスを目指して接続する事にします。クライアント A の接続先は 192.168.10.1 の 80 番ポートで、クライアント B の接続先は 192.168.10.2 の 80 番ポートです。これは丁度、複数のウェブサーバの手前にロードバランサーを置いて負荷分散している構成と似ています。今回の構成はサーバが一台だけで済んでいると言う点だけが異なります。

物理構成上はサーバとクライアント A の間の通信と、サーバとクライアント B の間の通信は、全く重複しない経路を通る事が可能です。それぞれの通信が完全に別々の経路を通った場合、ネットワーク帯域は最大 2 Gigabit となります。実際にどういう動きになるか見てみましょう。

 <<クライアント A から HTTP で接続>>
# telnet 192.168.10.1 80
<<クライアント B から HTTP で接続>>
# telnet 192.168.10.2 80

クライアントから接続したら、意図した通りの接続になっているかを netstat -a コマンドで確認します。コマンドの出力結果を見ると、クライアント A は 192.168.10.3 から 192.168.10.1 の 80 番ポートへ、クライアント B は 192.168.10.4 から 192.168.10.2 の 80 番ポートへきちんと接続されている事が分かります。サーバ側でも同じ IP アドレスのペアで接続を受け取っている事が確認出来ます。

 <<クライアント A>>
# netstat -a | grep 80
192.168.10.3.42881 192.168.10.1.80 49640 0 49640 0 ESTABLISHED
<<クライアント B>>
# netstat -a | grep 80
192.168.10.4.37305 192.168.10.2.80 49640 0 49640 0 ESTABLISHED
<<サーバ>>
# netstat -a | grep 80
192.168.10.1.80 192.168.10.3.42881 49640 0 49640 0 ESTABLISHED
192.168.10.2.80 192.168.10.4.37305 49640 0 49640 0 ESTABLISHED


HTTP の通信が実際にどの経路を通るかを確認する

次に HTTP の通信を発生させて、実際にどのネットワークインターフェイスを通ってデータがやり取りされるかを確認します。HTTP の通信はクライアント側からファイルを GET する事で発生させます。

 <<クライアント A>>
# telnet 192.168.10.1 80
Trying 192.168.10.1...
Connected to 192.168.10.1.
Escape character is '\^]'.
GET /001.txt HTTP/1.0

<<クライアント B>>
# telnet 192.168.10.2 80
Trying 192.168.10.2...
Connected to 192.168.10.2.
Escape character is '\^]'.
GET /001.txt HTTP/1.0

ネットワークインターフェイスの使用状況は、サーバ側で dladm コマンドを使用して確認します。dladm コマンドの出力は rbytes がそのインターフェイスに於ける受信バイト数、obytes が送信バイト数です。この値が 0 以外であればデータ通信が発生している事を示しています。

下記の出力結果を見ると igb1 は受信も送信もデータのやり取りが発生しています。一方、igb2 は受信バイト数は上がっていますが、送信バイト数は 0 になっており、データの送信には使われていない事が分かります。igb2 で受け付けた接続の返信パケットはどうなってしまったのでしょうか。

 # dladm show-dev -s -i 1 igb1
ipackets rbytes ierrors opackets obytes oerrors
igb1 503 32192 0 1893 2797601 0
ipackets rbytes ierrors opackets obytes oerrors
igb1 389 24896 0 1975 2931778 0
ipackets rbytes ierrors opackets obytes oerrors
igb1 416 26624 0 1644 2438276 0
# dladm show-dev -s -i 1 igb2
ipackets rbytes ierrors opackets obytes oerrors
igb2 386 24704 0 0 0 0
ipackets rbytes ierrors opackets obytes oerrors
igb2 469 30016 0 0 0 0
ipackets rbytes ierrors opackets obytes oerrors
igb2 628 40192 0 0 0 0


パケットの中身を確認する

もう少し詳しく状況を調査するため、igb1 を通るパケットを snoop コマンドでキャプチャします。snoop コマンドに -o オプションを付けて、保存先のファイル名を指定するとパケットを保存する事が出来ます。保存したファイルから読み込む場合は -i オプションでファイルを指定します。また、snoop コマンドに port 80 オプションを付けると、80 番ポートを通ったパケットだけを抽出する事が出来ます。同じく src 192.168.10.3 オプションを付けた場合は、送信元アドレスが 192.168.10.3 のパケットだけを抽出します。snoop コマンドのデフォルトの出力は一つのパケットに付き一行ずつ表示されます。出力の内容は、一番左がパケットに順番に振られる通し番号、続いて前のパケットを受け取ってからの経過時間、送信元 IP アドレス、宛先 IP アドレス、残りは通信プロトコル毎の出力です。

snoop コマンドを使用して igb1 上で port 80 番のパケットを見ると、192.168.10.2 から送信されるパケットも igb1 を通って外へ出て行っている事が分かります("->" の左側の送信元アドレスが 192.168.10.2 になっているパケットがあります)。src オプションで抽出すると、受信パケットは 192.168.10.3 から送信された物だけです。これで先ほどの dladm コマンドの出力で送信パケットが片方のインターフェイスしか使っていなかった理由が分かりました。サーバに入ってくるパケットは別々のインターフェイスを通っていますが、サーバから出て行くパケットは igb1 のインターフェイスしか使っていない様です。しかし、これでは返信パケットは片方のインターフェイスの帯域しか使用する事が出来ません。また 192.168.10.2 は igb2 に設定された IP アドレスなのに何故 igb1 から出て行っているのでしょうか。

 <<サーバ>>
# snoop -d igb1 -o /var/tmp/snoop01.dump
...
\^C
# snoop -i /var/tmp/snoop01.dump port 80
1 0.00000 192.168.10.3 -> 192.168.10.1 HTTP C port=42875
2 0.00012 192.168.10.1 -> 192.168.10.3 HTTP R port=42875
3 0.00010 192.168.10.3 -> 192.168.10.1 HTTP C port=42875
4 2.21303 192.168.10.2 -> 192.168.10.4 HTTP R port=37300
5 16.15477 192.168.10.3 -> 192.168.10.1 HTTP GET /001.txt HTTP/1.0
...
# snoop -i /var/tmp/snoop01.dump src 192.168.10.3
1 0.00000 192.168.10.3 -> 192.168.10.1 HTTP C port=42875
2 0.00023 192.168.10.3 -> 192.168.10.1 HTTP C port=42875
3 18.36780 192.168.10.3 -> 192.168.10.1 HTTP GET /001.txt HTTP/1.0
4 2.85314 192.168.10.3 -> 192.168.10.1 HTTP (body)
5 0.00014 192.168.10.3 -> 192.168.10.1 HTTP C port=42875
...
# snoop -i /var/tmp/snoop01.dump src 192.168.10.4


経路情報を確認する

送信元アドレスが 192.168.10.2 のパケットが何故 igb1 から送り出されるのかを調べる為にサーバ側でルーティングテーブルを確認します。netstat -ar コマンドの出力を見ると、クライアント A(192.168.10.3) 宛の経路もクライアント B(192.168.10.4) 宛の経路も igb1 になっている事が分かります。192.168.10.4 宛のパケットの送信元アドレスは igb2 に割り当てた 192.168.10.2 ですが、192.168.10.4 宛の経路は igb1 が選択されています。これが送信元アドレスが 192.168.10.2 のパケットが igb1 から送信されていた原因です。

 <<サーバ>>
# netstat -ar | egrep '192.168.10.3|192.168.10.4'
192.168.10.3 -- UHA 1 1 igb1
192.168.10.4 -- UHA 1 1 igb1

たまたま経路情報が偏っていたという可能性も考えられますので、念の為にルーティングのキャッシュを消去して何度も接続をテストしてみます。結果は以下の通り、何度接続し直しても経路は片方のネットワークインターフェイスにまとめられてしまいます。これが IPMP を使用しない場合の挙動です。

 <<サーバ側でルーティングテーブルのエントリを消去する>>
# arp -d 192.168.10.3; arp -d 192.168.10.4
192.168.10.3 (192.168.10.3) deleted
192.168.10.4 (192.168.10.4) deleted
# arp -d 192.168.10.3; arp -d 192.168.10.4
192.168.10.3 (192.168.10.3) -- no entry
192.168.10.4 (192.168.10.4) -- no entry
<<再びクライアントから接続した後にルーティングテーブルを確認>>
# netstat -ar | egrep '192.168.10.3|192.168.10.4'
192.168.10.3 -- UHA 2 6 igb1
192.168.10.4 -- UHA 2 6 igb1


まとめ

単純にネットワークにインターフェイスを繋いだ場合、クライアントから送られて来たパケットは宛先 IP アドレスの通りのインターフェイスを通り、サーバから返信されるパケットは常に一つのインターフェイスだけを通る事が分かりました。言い換えれば、受信パケットは 2 つのインターフェイスの帯域を有効に利用しているのに対し、返信パケットが使用出来る帯域はポート 1 つ分しかないことになります。


[検証2] IPMP を組んだ場合の挙動

ご覧頂きました通り、ここまでの構成では返信パケットは常に片方のポートしか通りませんでした。これでは帯域の利用効率は良くありません。IPMP のアウトバウンド・ロード・スプレッディングを使用する事で両方のポートを利用する様に変更する事が可能です。見てみましょう。


構成

これまでの構成に加えて、サーバの igb1 と igb2 で IPMP を組みます。IPMP の構成は簡単です。ifconfig の group オプションに適当な IPMP グループ名を指定するだけで完了します。グループ名は ipmp としましたが、その他の文字列でも構いません。

 # ifconfig igb1 group ipmp
# ifconfig igb2 group ipmp

IPMP を組んで ifconfig でインターフェイスの一覧を見ると groupname ipmp と表示され、インターフェイスが IPMP に参加している事が分かります。

 # ifconfig -a
...
igb1: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 3
inet 192.168.10.1 netmask ffffff00 broadcast 192.168.10.255
groupname ipmp
ether 0:14:4f:cb:16:b1
igb2: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 4
inet 192.168.10.2 netmask ffffff00 broadcast 192.168.10.255
groupname ipmp
ether 0:14:4f:cb:16:b2


HTTP で接続する

先ほどと同じ様に HTTP で接続してテストを行います。クライアント A は 192.168.10.1 に、クライアント B は 192.168.10.2 に、同時に接続します。返信パケットが負荷分散されるかどうか確認しましょう。


経路情報を確認する

netstat コマンドで経路情報を見てみると、今度はクライアント A(192.168.10.3) への接続は igb1 を、クライアント B(192.168.10.4) への接続は igb2 を通る様になっている事が分かります。IPMP を組む前は両方とも igb1 を通る様になっていましたが、IPMP を組むと別々のインターフェイスを使う様になりました。

 <<サーバ>>
# netstat -ar | egrep '192.168.10.3|192.168.10.4'
192.168.10.3 -- UHA 1 1 igb1
192.168.10.4 -- UHA 1 1 igb2


実際にどの経路を通っているかを確認する

続いて dladm コマンドを使用して、実際にどの経路を通って通信が行われているのかを見てみます。以下の出力結果を見ると、igb1 の opackets も igb2 の opackets も 0 以外の数値になっています。IPMP を組んだことにより、返信のパケットも 2 つのネットワークインターフェイスに股がって分散される様になりました。

 <<サーバ>>
# dladm show-dev -s -i 1 igb1
ipackets rbytes ierrors opackets obytes oerrors
igb1 369 23616 0 718 1067024 0
ipackets rbytes ierrors opackets obytes oerrors
igb1 384 24576 0 746 1107084 0
ipackets rbytes ierrors opackets obytes oerrors
igb1 384 24576 0 746 1104508 0
# dladm show-dev -s -i 1 igb2
ipackets rbytes ierrors opackets obytes oerrors
igb2 542 34688 0 1056 1555293 0
ipackets rbytes ierrors opackets obytes oerrors
igb2 414 26496 0 806 1189420 0
ipackets rbytes ierrors opackets obytes oerrors
igb2 452 28928 0 882 1308835 0

igb1 を snoop すると、igb1 のインターフェイスはクライアント A(192.168.10.3) と 192.168.10.1 の間の通信のみに使われている事が分かります。

 # snoop -d igb1 -o /var/tmp/snoop_igb1.dump
# snoop -i /var/tmp/snoop_igb1.dump host 192.168.10.1
1 0.00000 192.168.10.3 -> 192.168.10.1 HTTP C port=42878
2 0.00002 192.168.10.1 -> 192.168.10.3 HTTP R port=42878
3 0.00010 192.168.10.3 -> 192.168.10.1 HTTP C port=42878
4 7.98546 192.168.10.3 -> 192.168.10.1 HTTP GET /001.txt HTTP/1.0
5 0.00001 192.168.10.1 -> 192.168.10.3 HTTP R port=42878
...
# snoop -i /var/tmp/snoop_igb1.dump host 192.168.10.2 <-- 192.168.10.2 との通信には使用されていない
# snoop -i /var/tmp/snoop_igb1.dump host 192.168.10.3
1 0.00000 192.168.10.3 -> 192.168.10.1 HTTP C port=42878
2 0.00002 192.168.10.1 -> 192.168.10.3 HTTP R port=42878
3 0.00010 192.168.10.3 -> 192.168.10.1 HTTP C port=42878
4 7.98546 192.168.10.3 -> 192.168.10.1 HTTP GET /001.txt HTTP/1.0
5 0.00001 192.168.10.1 -> 192.168.10.3 HTTP R port=42878
...
# snoop -i /var/tmp/snoop_igb1.dump host 192.168.10.4 <-- 192.168.10.4 との通信には使用されていない

一方 igb2 はクライアント B(192.168.10.4) と 192.168.10.2 の間の通信にのみ使用されている事が分かります。

 # snoop -d igb2 -o /var/tmp/snoop_igb2.dump
# snoop -i /var/tmp/snoop_igb2.dump host 192.168.10.1 <-- 192.168.10.1 との通信には使用されていない
# snoop -i /var/tmp/snoop_igb2.dump host 192.168.10.2
1 0.00000 192.168.10.4 -> 192.168.10.2 HTTP C port=37303
2 0.00001 192.168.10.2 -> 192.168.10.4 HTTP R port=37303
3 0.00009 192.168.10.4 -> 192.168.10.2 HTTP C port=37303
4 6.40605 192.168.10.4 -> 192.168.10.2 HTTP GET /001.txt HTTP/1.0
5 0.00001 192.168.10.2 -> 192.168.10.4 HTTP R port=37303
...
# snoop -i /var/tmp/snoop_igb2.dump host 192.168.10.3 <-- 192.168.10.3 との通信には使用されていない
# snoop -i /var/tmp/snoop_igb2.dump host 192.168.10.4
1 0.00000 192.168.10.4 -> 192.168.10.2 HTTP C port=37303
2 0.00001 192.168.10.2 -> 192.168.10.4 HTTP R port=37303
3 0.00009 192.168.10.4 -> 192.168.10.2 HTTP C port=37303
4 6.40605 192.168.10.4 -> 192.168.10.2 HTTP GET /001.txt HTTP/1.0
5 0.00001 192.168.10.2 -> 192.168.10.4 HTTP R port=37303
...


まとめ

IPMP を使用すると、サーバからの返信時もネットワーク負荷が複数のインターフェイスに分散される事が分かりました。これで複数のネットワークインターフェイスの帯域を最大限に有効利用する事が出来ます。


チューニングパラメータ

一度クライアントまでの経路が決定されると、その後の接続はキャッシュを元に経路が選択される様になります。既に見た通り、キャッシュは netstat -ar で確認、arp -d で削除する事が可能です。このキャッシュの有効期限は ip_ire_arp_interval と arp_cleanup_interval パラメータで設定する事が出来ます。もし経路に偏りが発生していた場合は有効期限を短く設定すると経路選択の機会が増えて偏りが解消されるかもしれません。ip_ire_arp_interval と arp_cleanup_interval の確認方法と設定方法は以下の通りです。

 # ndd -get /dev/ip ip_ire_arp_interval
1200000
# ndd -set /dev/ip ip_ire_arp_interval 60000
# ndd -get /dev/arp arp_cleanup_interval
300000
# ndd -set /dev/arp arp_cleanup_interval 30000


おわりに

今回は IPMP のアウトバウンド・ロード・スプレッディング機能による負荷分散をご紹介しました。要件次第では、簡単にネットワークの実行帯域を増やす事が可能です。特にウェブサーバやファイルサーバは、IPMP のアウトバウンド・ロード・スプレッディングだけで十分かもしれません。サンのサーバの多くは最小構成でもネットワークインターフェイスを4ポート装備しています。Solaris の機能を活用し、是非それらのポートを有効利用して下さい。


補足


  • IPMP の作成は簡単でしたが、削除も簡単に出来ます。ifconfig コマンドの group オプションに空文字を指定してください。groupname エントリが消えていれば IPMP も解除されています。
  •  # ifconfig igb1 group ''
    # ifconfig igb2 group ''

  • IPMP のアウトバウンド・ロード・スプレッディングでどの経路を通るかはラウンドロビンで決定されます。例えば igb1, igb2 の 2 つのインターフェイスを使用した IPMP で、2 台のクライアントからコネクションが張られていた場合、最初のクライアントからの接続が igb1 を経由して返ったなら、次のクライアントからの接続は igb2 を経由して返ります。この時、クライアントからの接続を受けたインターフェイスとは別のインターフェイスを経由してクライアントに返る事もあります。また、ラウンドロビンで経路が決まるのは、コネクションが一本しか無い場合も例外ではありません。igb1 で受け取ったコネクションが igb2 から出て行くというケースも普通に発生します。その場合も、返信パケットの送信元 IP アドレスが書き変わったりする事はありません。

  • コネクション数が少ない場合は通信が片方のインターフェイスに偏る事があります。例えば 3 台のクライアントから接続があり、その内 2 台への返信パケットが igb1 を通り、残りの 1 台が igb2 を通っていた場合、igb2 を使用していたコネクションが終了すると、クライアントは 2 台あるのに、インターフェイスは片方しか使用されていない状態になります。アウトバウンド・ロード・スプレッディングは、インターフェイスの負荷を監視してロードバランスするのではなく、単純にラウンドロビンでロードスプレッドしているだけなので、インターフェイスの数に対してクライアントの数が多ければ多いほど効率よく帯域を使用する事が出来ます。

  • IPMP のアウトバウンド・ロード・スプレッディングは片方のインターフェイスにのみ IP アドレスを振った場合にも有効になります。構成の仕方は こちら をご参照下さい。以下の例では、igb2 には IP アドレスが設定されていませんが、192.168.10.4 宛の経路には igb2 が選択されています。サーバ側で受信用の帯域がそれ程必要とされておらず、使用する IP アドレスを減らしたい場合は、この構成が便利です。
  •  # ifconfig -a
    ...
    igb1: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 3
    inet 192.168.10.1 netmask ffffff00 broadcast 192.168.10.255
    groupname ipmp
    ether 0:14:4f:cb:16:b1
    igb2: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 5
    inet 0.0.0.0 netmask ff000000
    groupname ipmp
    ether 0:14:4f:cb:16:b2
    # netstat -ar | egrep '192.168.10.3|192.168.10.4'
    192.168.10.3 -- UHA 2 25 igb1
    192.168.10.4 -- UHA 2 25 igb2

  • アウトバウンド・ロード・スプレッディングによる負荷分散はクライアントの IP アドレス毎です。コネクション毎ではありません。

  • クライアントとサーバの間にルータを挟んだ場合もアウトバウンド・ロード・スプレッディングは有効です。パケットの送信に使われるインターフェイスはクライアントの IP アドレス毎に決定されます。以下の例はクライアント A(192.168.11.2) とクライアント B(192.168.12.2) が、ルータ (192.168.10.3) を経由して、IPMP を構成したサーバへアクセスした際の、サーバのルーティングテーブルです。クライアントへの経路が igb1 と igb2 に分かれている事が分かります。
  •  <<サーバ>>
    # netstat -ar | egrep '192.168.11.2|192.168.12.2'
    192.168.11.2 192.168.10.3 UHA 1 1 igb2 <-- ルータ経由のクライアント A
    192.168.12.2 192.168.10.3 UHA 1 1 igb1 <-- ルータ経由のクライアント B

  • IPMP に参加出来るポートの数は 2 つに限定されている訳ではありません。オンボードのインターフェイスを全て同一の IPMP に入れる事も可能ですし、もっと多くのポートを参加させる事も可能です。

  • arp -d で ARP のエントリを削除するとルーティングの情報も削除され、即座に経路が変更されます。netstat -ar で表示される一番上のエントリが経路として使用され、arp -d で一番最初に消去されます。

  • サーバ側からコネクションを張る場合は IP ソースアドレス・セレクションという別の機能を使って負荷分散されます。サーバがクライアントにコネクションを張る際に、送信元 IP アドレスを自分の複数のインターフェイスからラウンドロビンで決定する事で、クライアントが返信する先の IP アドレスを操作する事が出来、結果的にサーバが受信する際の負荷分散になります。これは IPMP の機能ではなく IP の機能です。コネクションを張る時に IP モジュールより上位で送信元 IP アドレスが設定されていない事が条件です。

  • IPMP のアウトバウンド・ロード・スプレッディングはリンクアグリゲーション (dladm(1M)) と併用する事も可能です。また、OpenSolaris の ILB(Integrated Load Balancer) と組み合わせて使うと更に便利かもしれません。


参考文献

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.