2006年09月04日

高トラフィックに対応できるLinuxロードバランサを目指して 〜 LVSをNATからDSRへ

はてなブックマークに登録

「こんなに簡単! Linuxでロードバランサ」のシリーズでは、

こんなに簡単! Linuxでロードバランサ (1) 〜 LVS + NATで負荷分散をしてみよう
こんなに簡単! Linuxでロードバランサ (2) 〜 keepalivedでWebサーバのヘルスチェック
こんなに簡単! Linuxでロードバランサ (3) 〜 VRRPでロードバランサを無停止にする

こんな流れでNATによる負荷分散システムを構築してきました。
今回はこれを DSR(Direct Server Return) 方式に変更してみます。

「DSRとはなんぞや?」という方は、

ロードバランサの運用.DSRって知ってますか?
L4スイッチはDSR構成にすべし

こちらでわかりやすく説明されていますので参考にしてみてください。

NATによる負荷分散では、パケットの書き換えコストがロードバランサに集中してしまいますが、リアルサーバに特殊な設定をしなくてもよいという手軽さがあります。DSRの場合はロードバランサとリアルサーバが協調しあって分散環境を構成するため、リアルサーバ側にも若干の小細工が必要になってしまいます。

一般的(?)に大規模システムを構築する場合は、「ネットワーク機器の整備はこの部門」、「サーバの調達はこのベンダーさん」、「インストールはあのグループ」みたいに役割が組織の壁で仕切られている事が多いのではないでしょうか。そうすると「L4スイッチでDSRするからサーバ側の設定もよろしくね☆」みたいな事は実際問題として難しいのかもなあと思っていたりします。サーバをインストールして設定してローカルでの接続が確認できたからといって、DSRで外部から繋がるとは限らないので、トラブルシューティングというか切り分けが面倒になってしまいがちなんです。

KLabのようなベンチャー企業では、限られているリソースをフル活用して全力でシステムを組み上げなければなりません。「検証用」と称して高額な機器を買うことはなかなかできませんが、システム全体で最も効率がよいと思われる方法を模索しながらじっくりと組み上げていける楽しみがあります。日頃からそんな事をやっている物好きなお兄さん達にとって、「Linuxでロードバランサ」という題材は絶好のオモチャだったりするわけです。

前置きが長くなってしまいましたが、そろそろ作業に取りかかりましょうか(^^;

ネットワーク構成は前回と一緒になります。
まずは、各マシンにおいて以下のコマンドを実行します。

lv1とlv2の設定変更



eth0に割り当ててあったWEBサービス用の仮想IPアドレス(10.10.31.100)を削除します。


# ip addr del 10.10.31.100 dev eth0



ちょっとしたおまじないをかけます(説明は後述)


# iptables -t mangle -A PREROUTING -d 10.10.31.100 -j MARK --set-mark 1
# ip rule add prio 100 fwmark 1 table 100
# ip route add local 0/0 dev lo table 100
# echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter



w101とw102の設定変更



こちらにもちょっとしたおまじないをかけます(やっぱし説明は後述)


# iptables -t nat -A PREROUTING -d 10.10.31.100 -j REDIRECT




keepalived.confを変更


lv1,lv2 の /usr/klab/etc/keepalived.conf の lvs_method を DR にします。


(変更前)
lvs_method NAT




(変更後)
lvs_method DR



keepalivedを起動


lv1 と lv2 の keepalived を起動します。


# /usr/klab/sbin/keepalived -n -f /usr/klab/etc/keepalived.conf --check --vrrp



設定は以上です。
client から今まで通り example.org にアクセスしてみてください。
きっと今までと同じ結果が返って来ると思います。


client:~$ curl -H 'Host: example.org' http://10.10.31.100
w101 nano
client:~$ curl -H 'Host: example.org' http://10.10.31.100
w102 desu



はい、これで DSR のできあがりです。おつかれさまでしたあぁ〜
・・・って終わってしまうのは少し寂しすぎますね(^^;

とりあえず、ちゃんと DSRとして動いているかどうか tcpdump でパケットを追ってみましょう。
流れを追いやすいように client からtelnetで 10.10.31.100 の 80 番ポートに接続する様子を追ってみます。

※tcpdumpの使い方は 「ネットワークパケットを覗いちゃえ」 も参考にしてください。


client:$ telnet 10.10.31.100 80



すると、lv1(lv2)ではこんな結果になります。


root@lv1:~# tcpdump -n -i eth0 port 80 and host 10.10.31.200
IP 10.10.31.200.54546 > 10.10.31.100.80: S 2507165666:2507165666(0)
IP 10.10.31.100.80 > 10.10.31.200.54546: S 3509055605:3509055605(0) ack
IP 10.10.31.200.54546 > 10.10.31.100.80: . ack

root@lv1:~# tcpdump -n -i eth1 port 80 and host 10.10.31.200
IP 10.10.31.200.48185 > 10.10.31.100.80: S 2923294161:2923294161(0)
IP 10.10.31.100.80 > 10.10.31.200.48185: S 3928787480:3928787480(0) ack
IP 10.10.31.200.48185 > 10.10.31.100.80: . ack



同様に w101(w102)ではこうなります。


root@w101:~# tcpdump -n -i eth0 port 80 and host 10.10.31.200
IP 10.10.31.200.48185 > 10.10.31.100.80: S 2923294161:2923294161(0)
IP 10.10.31.100.80 > 10.10.31.200.48185: S 3928787480:3928787480(0) ack
IP 10.10.31.200.48185 > 10.10.31.100.80: . ack



10.10.31.200 から送られた 10.10.31.100 宛のパケットが アドレス変換されないまま w101 に到達していることがわかると思います。また、w101 ではこのパケットに対する ACK をちゃんと返しているので TCP接続が正常に完了できていることもわかるかと思います。

意外とあっさり終わって拍子抜けしてしまいましたか?
このシステム上には 10.10.31.100 という IPアドレスを持ってるマシンがいないにも関わらず、WEBサービスとしてこのアドレスを利用できるのがこの構成の特徴というか面白いところだと思います。
 
 
さて、それでは説明を後回しにしていた各設定の意味を順に追っていくことにしましょう。
 
 
lv1:# ip addr del 10.10.31.100 dev eth0

ここでは、NAT構成で使っていた WEBサービス用の仮想IPアドレスを削除しています。
DSR構成では、リアルサーバがこのアドレスをソースとしたパケットを返すわけですが、lv1でこのアドレスを割り当てたままだと、「自分のIPアドレスを他人が偽装している」とみなして破棄してしまうようです。今回のようにリアルサーバからの戻りパケットがlv1を経由するような構成の場合は要注意です。もちろん、リアルサーバのデフォルトゲートウエイを別のルータに向ける場合はこの限りではありません。
 
 
  
lv1:# iptables -t mangle -A PREROUTING -d 10.10.31.100 -j MARK --set-mark 1

lv1 に届いた 10.10.31.100 宛のパケットに対して mark 値を 1 にセットするように netfilterを設定します。
 
 
 
lv1:# ip rule add prio 100 fwmark 1 table 100

mark 値が 1 のパケットは 100 番の経路テーブルを適用させるようにします。
 
 
 
lv1:# ip route add local 0/0 dev lo table 100
 
全てのパケットをローカルデバイスにルーティングするような設定を 100番の経路テーブルに追加します。


さて、Linuxにはポリシールーティングという機能があることをご存じでしょうか。
カーネル構築時に CONFIG_IP_MULTIPLE_TABLES=y とする事で有効になる機能ですが、その名の通り複数の経路テーブルを持つことができる機能です。通常 route コマンドで参照や設定をしているテーブルは、256個あるテーブルの中の1つに過ぎなかったりします。興味のある方は、以下のコマンドを実行してみてください。


ip route list table 0
ip route list table 254
ip route list table 255


この辺の詳しい話はまた別の機会にでもしたいと思います。
参考程度ですが メンテナンス回線の経路(Linuxのポリシールーティングの活用) でも若干触れています。

とりあえず今は

「ある条件にマッチしたパケットを特定の経路テーブルで評価させる事ができる」


ということだけ理解してください。

で、話を戻すと・・・ここでは、

1) 10.10.31.100 宛のパケットに mark=1をセットする(netfilterの機能)
2) mark=1 のパケットは 100番の経路テーブルを使う(ポリシールーティングの機能)
3) 100番の経路テーブルでは すべてのパケットをローカルデバイスに流すように定義しておく

これらの設定によって、10.10.31.100を IPエイリアスで割り当てなくても LVS の処理に流すという芸当ができてしまうわけです。
 
 
 
lv1:# echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter

rp_filterを無効にします。これが有効のままだと、カーネルのソースアドレス認証(Source Address Verification)という機能が働いてしまうため、リアルサーバからの応答パケットをフィルタしてしまいます。
 
 
 
w101:# iptables -t nat -A PREROUTING -d 10.10.31.100 -j REDIRECT

しつこいですが、リアルサーバにも 10.10.31.100 というアドレスを割り当てていません。
しかし、LVS の機能によって 10.10.31.100 宛のパケットがリアルサーバに届きます。
その場合、Linuxはフォワーディングするなり破棄するなりの動作をしますが、-j REDIRECT を指定されたパケットは送信先アドレスが自分自身のIPアドレスに変換されてローカルデバイスに渡されます。各リアルサーバの内部でこっそりとアドレス変換(DNAT)をしてくれるようになるんです。

また、「リアルサーバがVIPを意識するのいやじゃあ」という方には、

lv1:# iptables -t mangle -A POSTROUTING -d 10.10.31.100 -j TOS --set-tos 2



とした上で、上記のコマンドの代わりに


w101:# iptables -t nat -A PREROUTING -m tos --tos 2 -j REDIRECT



とかすると、LVSマシン上のiptablesだけで VIPを管理できるようになるのでお手軽かもしれません。ただし、この方法は思わぬ落とし穴もありますので「動けばいいや」的な方にはあまりお勧めできません(^^;
 
 
今回紹介した手法以外にも、

● iptables -j REDIRECT を使わずに VIP を IP Alias でリアルサーバに割り当てる
  ※リアルサーバのarp応答をなんらかの方法で抑制する必要があるかもしれません。

● ポリシールーティングとMARKを使わずに VIP を IP Alias で LVSマシンに割り当てる
※応答パケットを処理するために、カーネルに特殊なパッチ(forward_shared)をあてる必要があります

● リアルサーバの戻りのパケットは LVSマシンじゃない別のルータを経由させる
※ naoyaさんがこの構成を試しているようです


などでも構築可能です。
仕組みさえ理解できれば様々な運用形態が考えられるのも DSR の大きな特徴です。
DSASでは IP Alias を使わずに構成し、リアルサーバの応答パケットをLVSマシンに返すようにしていますが、それは以下のような背景があったためです。

●サービス追加(IPアドレスを追加)する度にノードに新IPアドレスを割り当てたくない
 DSASは共用プラットフォームなのでIPアドレスの数が膨大になってしまいます
 稼働しているサーバ上でipコマンドやifconfigコマンドでIPアドレスを追加するのは超怖いです
 iptablesだけでVIPを追加できるならそのほうがラクチンなんです(運用上の事情もあり)

●リアルサーバからの応答パケットもLVSマシンを経由させたい
 DSASのロードバランサはルータとファイアウォールも兼ねています。
 外部との通信制御(フィルタリングポリシ)をLVSマシン上で一元管理したかったのです。
 DSRであればLVSマシンの仕事は転送だけなので、ボトルネックになるほどの負荷はかかりません。
 上流回線が100Mbpsなら、ギガビットスイッチとGNIC付きのサーバでワイヤーレート出せます。
 そのため、あえて応答用のGWを別立てする必要がなかったのです。
 もし別に立てるのであれば、そこも冗長化しないといけなくなります。


いかがでしたでしょうか。
「ロードバランサを入れたいけどちょっと・・・」と思っている方の参考になれば幸いです。
不明な点などがあれば、遠慮なくコメントなりトラックバックなり頂けるとモチベーションがあがるかもしれません(笑)

負荷分散環境って、データセンターだけで構築すれば良いというものじゃなく、開発者の手元にも必要なものだと思います。Webアプリを開発したのはいいけれど、負荷分散環境にもっていったら動作がおかしくなったなんて事ありませんか?高負荷に耐えられるシステムを開発するには、開発環境にもロードバランサを置くべきです。しかしながら、コストの都合上でそれができない現場も少なくないはずです。

そんな時に Linux でさくっと負荷分散環境を作ることができれば、開発効率や製品品質の向上が期待できるのではないでしょうか。ちなみにKLabでは、開発環境として、mini-DSAS というシステムを構築しており、開発者が自由に負荷分散システムに触れる事ができる体制になっています。

参考


Manpage of IPTABLES

Linux Advanced Routing & Traffic Control HOWTO

Iptables Tutorial

Iptablesチュートリアル 日本語訳

Julian's Software and Patches page.
LVSの開発者の一人 Julian さんが作っているカーネルパッチがいっぱいあります。
かなりトリッキーというか通好みのパッチがいっぱいあるので結構オススメです。

iptablesによる負荷分散とDoS対策
klab_gijutsu2 at 10:26│Comments(14)TrackBack(1)network | lvs

トラックバックURL

この記事へのトラックバック

DSAS開発者の部屋:高トラフィックに対応できるLinuxロードバランサを目指して 〜 LVSをNATからDSRへ

この記事へのコメント

1. Posted by LVS試してみた人(1)   2006年11月12日 03:34
5 #文字数が多すぎると出るため、2回に分けて書きます。

質問です!!
DSRの冗長構成(lvsサーバ2台、keepavliedでVRRP構成)で
redirectを実webサーバ(w101,w102)に設定した状態で、

( #iptables -t nat -A PREROUTING --dport 80 -j REDIRECT
#iptables -t nat -A PREROUTING --dport 443 -j REDIRECT
上記設定をw101,w102に設定、http,httpsポートだけをREDIRECTさせる。)

http通信、https通信をさせる場合

vip: 192.168.0.1
lv1: 192.168.0.2
lv2: 192.168.0.3
w101: 192.168.0.101
w102: 192.168.0.102

とIPを設定したとして、


2. Posted by LVS試してみた人(2)   2006年11月12日 03:37
#2回目のコメントです。

vip 経由の通信(192.168.0.1 → w101,w102)
:http通信 OK(vipからw101,w102への通信可)
:https通信 OK(vipからw101,w102への通信可)

lv1 経由の通信(192.168.0.2 → w101,w102)
:http通信  NG(lv1からw101,w102への通信不可)
:https通信 NG(lv1からw101,w102への通信不可)

lv2 経由の通信(192.168.0.3 → w101,w102)
:http通信 NG(lv2からw101,w102への通信不可)
:https通信 NG(lv2からw101,w102への通信不可)

と、vipを経由しての通信は問題ないのですが、
(lv1→lv2、lv2→lv1へのVIPの切り替えが発生しても、vip経由では問題無し。)
lv1,lv2を経由しての通信は出来ませんでした。
3. Posted by LVSを試してみた人(3)   2006年11月12日 03:37
#すいません、3ページになってしまいました。

と、vipを経由しての通信は問題ないのですが、
(lv1→lv2、lv2→lv1へのVIPの切り替えが発生しても、vip経由では問題無し。)
lv1,lv2を経由しての通信は出来ませんでした。

もちろん、vipを経由しての通信が出来れば、OKといえばOKなのですが、
lv1,lv2のリアルサーバを経由すると何でNGとなってしまうのか、(正確に
言うとサーバ側からresetが送信され強引にコネクションが切られる。)
がわからなく、ちょっと困っています。
もし、ご存知でしたらご教授頂きたく。
暇な時でかまいませんので、どうぞよろしくお願いします。
4. Posted by LVSを試してみた人(4)   2006年11月12日 03:55
先ほど、コメント3つもしたものですが、原因わかりました。ipvsadmでリアルIP(lv1,lv2)の振り分け設定をしていないためでした。 すいません。先ほどのコメントは無かったことにしてください。 これからも、ブログ書き続けてください。応援してます。 以上、取り急ぎ。 
5. Posted by fumiyas   2006年11月13日 11:29
5 参考になりました。ありがとうございました。

ところで、「ロードバランサの運用.DSRって知ってますか?」と「L4スイッチはDSR構成にすべし」へのリンクが切れていましたのでお知らせしておきます。
6. Posted by DSASの中の人   2006年11月13日 11:47
>Posted by LVSを試してみた人さん
お返事遅れましたが解決できてよかったです!

>fumiyasさん
ご指摘ありがとうございました! 早速、修正しましたー


8. Posted by 伊東   2006年12月25日 16:16
5 記事、大変参考になりました。
ところで、どうにも解せない部分が一点あります。

> eth0に割り当ててあったWEBサービス用の仮想IPアドレス(10.10.31.100)を削除します。

この状態で、10.10.31.100宛に流れてきたパケットが10.10.31.11に到達するからくりがわかりません。
上位のルータで静的ルート設定してるんでしょうか?

9. Posted by DSASの中の人   2006年12月25日 17:59
伊東さん、コメントありがとうございます。
ここで使っている環境は「こんなに簡単! Linuxでロードバランサ (3)」をベースに・・・というかそのまま使っていまして、実はこの記事の中で client(10.10.31.200)で
# route add -host 10.10.31.100 gw 10.10.31.10
をしています。
イメージとしては、上位ルータで静的ルートを設定したような構成と思って頂いて間違いありません。
説明不足でごめんなさい。

こちらの記事も参考にして頂けると助かります。
http://dsas.blog.klab.org/archives/50675098.html
10. Posted by 伊東   2006年12月25日 19:36
ありがとうございます、
(3)の中でやっていたんですね、(1)とこの記事を行ったり来たりして悩んでおりました

悩みが解決しました。こちらもいろいろ試して他の方にフィードバックできるようにがんばります!
13. Posted by とっとこ   2008年05月19日 17:24
5 先日質問させていただいたとっとこです。現在DSRでkeepalivedの冗長構成をしているのですが、不思議な点があるのでお尋ねしたいと思います。
1.vrrp_instanceの定義で片方をmaster、一方をbackupにして、master、backupの順にkeepalivedを起動させるとなぜかbackupのほうがmasterになってしまうのですが、どうしてでしょうか?

2.virtual addressを定義して、keepalivedをmaster、backupそれぞれ起動させると、ip addr showコマンドでどちらのサーバででもvirtual addressが見えるのですが、これは仕様でしょうか?
※Linuxアドバンストネットワークサーバ構成ガイド HAサーバ構築編という書籍には両方のkeepalivedを起動しても片方のサーバにのみ仮想IPが割り当てられると記載していました。もっともこの現象でLVS+keepalivedが正常に動作していない、ということはないのですが。

よろしくお願いします。
14. Posted by DSASの中の人   2008年05月19日 20:55
とっとこさん、状況から推測するに、VRRPが正常に動作していないため、両方ともマスタになっているように見受けられます。

まずは、keepalived.confのvrrp_instanceの設定が食い違っていないかどうか確認してみてください。

vrrp_instanceブロックの設定は、priority以外の項目はマスタとバックアップで同じにしたほうがよいです。

正常に動いていれば、virtual addressはマスタにしか振られません。おそらく、この状況は「backupのほうがmasterになっている」のではなく「backupもmasterになっている」のだと思います。

あと、考えられる原因としてはマルチキャストを使えないようになっているといったところでしょうか。



15. Posted by とっとこ   2008年05月20日 12:58
ご回答ありがとうございます。

vrrp_instanceの設定は確認しましたが、stateとpriority以外は一緒でした。

>あと、考えられる原因としてはマルチキャストを使えないようになっているといったところでしょうか。

これですが、具体的にどのようにすればよろしいでしょうか?
16. Posted by DSASの中の人   2008年05月20日 16:36
>とっとこさん

マルチキャストについては、ご利用のネットワーク環境やサーバ環境がわからないのでなんともいえませんが、VRRPは224.0.0.18を利用して死活確認するので、バックアップのマシンでtcpdumpするなどしてパケットが届いているかどうかを確認するという手があります。
また、keepalivedの起動時にsyslogになにかエラーなどがでてないかを確認してみてはいかがでしょうか。
17. Posted by とっとこ   2008年06月03日 12:39
5 すいません。回答が遅れましたが解決しました。
理由はvirtual_router_idが1のときにうまく動作していなかったからです。エラー内容でぐぐったら同様の事象を見つけました。
お手数かけました。ありがとうございました。

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント