lvs

2017年09月26日

LVSの高負荷対策 その2 ~障害の再現とその原因~

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

こんにちは。インフラ担当の岡村です。
LVSの高負荷対策 その1 ~障害発生~」の記事で、大量のSYNパケットを受信した際にロードバランサの再起動が発生したことと、その緊急の対策についてご紹介しました。
今回は、再現確認を行い判明した再起動の原因と、LVSに備わっている高負荷対策の機能についてご紹介します。

検証

前回ご紹介した通り、障害発生時のログからメモリ周りが怪しそうでした。 そこで、ロードバランサにSYNパケットを送り、メモリの使用量の推移を観察しながら、再起動が発生するかどうかを確認しました。

検証環境の構成は次のようになります。

検証環境の構成
dsas_lvs_test_environment

パケット送信用サーバを複数台、ロードバランサを1台、Webサーバを1台使用し検証を行いました。
ロードバランサの検証を行う上で、本番環境と同様にロードバランスの処理をさせたかったため、LVSに振り分け先のWebサーバのIPアドレスを複数登録しています。
DSASのロードバランサではDSR(Direct Server Return) 方式を採用しており、Webサーバからの戻りパケットはLVSを経由しません。本検証を行う上ではWebサーバはパケットを返す必要はないので、ロードバランサから振られたパケットはWebサーバでdropしています。
パケット送信にはhping3を使用しました。オプションが豊富で様々なパケットを送信することができます。今回は障害時に検出したパケットに似せて、次のコマンドでwindowサイズ0のSYNパケットをロードバランサのVirtual Service宛に大量に送信しました。

hping3 -S -w 0 “Virtual ServiceのIPアドレス” -p 80 --rand-source --flood

DSASのロードバランサは、64bitOSのものだけではなく、32bitOSのものが残っている状態でした。今回の問題が発生したのは32bitOSの方だったため、まず32bitOSで検証を行いました。

32bitOSでの検証

上述の通りhping3を使用して、複数のサーバからロードバランサに向けて一斉にSYNパケットを送信します。
SYNパケットが届くと、IPVS ( LVSのレイヤー4の負荷分散機能を提供するカーネルモジュール ) はSYN_RECV状態のエントリを作成します。そのためSYN_RECV状態のエントリがどんどん増加していき、それに伴いLowメモリの使用量が増加していきました。
Lowメモリの使用量の推移を確認したところ、パケット送信前の状態では約750MB あったLowメモリの空き容量は刻々と減少し、最終的に枯渇してカーネルパニックが起こり、再起動が発生しました。

Kernel panic - not syncing: Out of memory and no killable processes...

64bitOSではLowメモリの制限がなくなるので耐性は向上すると予想できます。しかしメモリが枯渇すれば同様に再起動が起こりそうです。64bitOSを使用して、もう少し詳しくロードバランサの挙動を追っていきます。

64bitOSでの検証

結論から言うと、IPVSのエントリが増加しメモリが枯渇すると、やはり再起動が発生しました。ログを確認してみると本番環境での再起動の時と同様、再起動の直前でoom-killerが多発しており、また、カーネルのバージョンの違いから若干出力は異なりますが、IPVSのメモリ割り当てのエラーが出ていました。

IPVS: ip_vs_conn_new(): no memory

本番環境で起きた再起動も、IPVSのエントリが増加することによるメモリ枯渇に起因すると考えて良さそうです。
負荷試験中のSYN_RECV状態のエントリ数と消費メモリの推移を確認し、グラフにしました。(グラフ1)
今回の検証で使用したサーバはメモリを8GB搭載しており、負荷をかける前のMemFree値がおよそ7GBであったことから、以下の全てのグラフの「消費メモリ」の値は、「 7GB - 観測したMemFree値 」で算出しています。

dsas_lvs_graph1

負荷をかけ始めてから約49秒で消費メモリが7GB、すなわち、8GBのメモリを使い切り、再起動が発生しました。
さて、IPVSの挙動を確認するため、先の試験より負荷を抑え、再起動が起きなかった場合のグラフを見てみましょう。(グラフ2)

dsas_lvs_graph2

およそ60秒間はエントリ数とメモリ消費量は増え続けますが、それ以降は一定の値で推移しているのがわかります。
これは、SYNパケットが届くとIPVSはSYN_RECV状態のエントリを作成しますが、SYN_RECV状態のままだと60秒でタイムアウトになり、エントリが削除されるためです。
今回の試験では一定の強さの負荷をかけ続けたため、60秒以降は「タイムアウトで削除されるエントリ数」と「新規に作成されるエントリ数」が釣り合い、一定になったと考えられます。
(ピークが60秒から少しずれているのは、複数のサーバからパケットを送って負荷をかけているため、それぞれのサーバで負荷の開始時刻の誤差があったためです)

対策について

64bitOSでも再起動は発生したものの、32bitOSの場合と比較すると大幅に負荷耐性が向上しました。32bitOSでLowメモリが制限されてしまっている環境の場合は、64bitOSに変更することで耐性を上げられます。その上でメモリを追加すれば更に負荷耐性が上がり、再起動の対策になりますね。
では、他に有効な対策はないでしょうか?
調べてみると、LVSは高負荷対策の機能をいくつか備えているようです。(参考)
今回は、そのうちの機能の一つであるdrop entry機能を使用してみたのでご紹介します。

drop entry 機能の紹介

IPVSのエントリをランダムに削除してくれる機能です。
SYN-RECV状態とSYNACK状態のエントリを削除するアルゴリズムは、毎秒IPVSのコネクションハッシュテーブルからランダムに選んだ範囲(全体の32分の1)をスキャンし、その中のSYN-RECV状態、SYNACK状態のエントリを削除する、というもののようです。
ESTABLISHED状態のエントリとUDPのエントリは共に、次の2つの条件を両方とも満たしている場合に削除される可能性があります。
・最後のパケットが届いてから60秒以上経過
・最初のパケットが届いてからの受信パケットの合計数が8以下
受信パケットが8以下の場合でも、受信パケット数が大きくなるに連れて削除される可能性は低くなるようです。

drop entryは、使用可能なメモリ量が設定した閾値を下回ったときに、自動で有効にすることが可能です。その場合は、以下に1(または2)を設定します。

/proc/sys/net/ipv4/vs/drop_entry

メモリの空きが閾値を下回ると自動的に値が2になり、機能が有効になります。
( 閾値を下回っていないときに、2を設定すると、自動で1になります。)
また、閾値によらず常にdrop entryを有効にしたい場合は、3 を設定します。
閾値は以下で設定可能です。

/proc/sys/net/ipv4/vs/amemthresh

単位は memory pageなので、例えばメモリが残り1GB(=1048576KB)を下回った時に有効にしたい場合は、"1048576KB÷(ページサイズの)4KB"を計算して、262144 を設定します。

drop entry有効時の動作確認

閾値を6GB,3GB,1GBとし、SYNパケットを送って負荷をかけたときの、SYN_RECV状態のエントリ数と消費メモリの値の推移をそれぞれグラフにしました。

dsas_lvs_graph3
dsas_lvs_graph4

負荷は上の64bitOSの検証で再起動を発生させたときと同じ強さなので、drop entryなしでは再起動してしまいます(グラフの青線)。しかし、drop entryを有効にすると、3つのどの閾値の場合も消費メモリを抑えることができ、再起動は起こりませんでした!
例えば閾値を3GBに設定したときの推移(グラフの黄線)を見ると、消費メモリが4GB、すなわち残りのメモリが3GBになった時点から、エントリ数とメモリ消費量の増加が緩やかになっているのがわかります。
閾値を大きくすればするほど、消費メモリの最大値は小さくなり、耐性が向上することも見て取れます。

ただ、drop entryを有効にすれば必ずしも再起動を防げるというわけではなく、負荷に対して閾値を小さくし過ぎると、例えば上の環境で閾値を150MBにすると、drop entryが間に合わず再起動が起きました。また、負荷と比較して搭載メモリが少ない場合は、drop entryを常に有効にしていてもメモリが枯渇する可能性がある点も注意が必要です。

しかし、メモリ増強などの追加投資なしで、すぐに耐性を上げることができるので、とても便利な機能です。
もちろんdrop entry有効時には、IPVSを経由するどの接続もエントリ削除の影響を受ける可能性がありますが、ロードバランサが落ちてサービス停止してしまうよりはずっと良いのではないかと思います。LVSを使用されている方は是非お試しください。

次回、LVSの高負荷対策 その3でも、引き続きdrop entryの検証結果を紹介しようと思っています。

okamura_h at 11:57|この記事のURLComments(0)
2017年04月04日

LVSの高負荷対策 その1 ~障害発生~

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

こんにちは。インフラ担当の岡村です。
昨年、あるサービスで使用中のロードバランサが停止してしまうという事件が起こりました。
事の顛末を、数回に分けて紹介していきたいと思います。 もし同様の事象にお困りの場合は、役立てて頂ければと思います。

システム構成

KLabのDSASでは、ロードバランサにLVS (Linux Virtual Server) を使用しています。
ロードバランサはマスタ-バックアップ構成になっており、マスタ側が停止してしまっても、通常はバックアップ側がマスタに昇格し、サービスを継続できるようになっています。 おおまかな構成は下図のようになります。

dsas_lvs_network

障害発生

ある日の晩、突然ロードバランサ(マスタ側)の死活監視のアラート通知が届きます。

(なんだろう..。電源障害? その他HW障害? もしくはカーネルのバグを踏んだ?)

原因調査・復旧はもちろん必要ですが、冗長構成のため、とりあえずサービスは継続可能です...。そのはずでした。
数分後、今度は昇格した新マスタの死活監視アラートが届きます。

(2台揃って落ちた? 208.5日問題のようなバグ? 一体何が起こってる??)

緊張が走ります。
その後も何度かアラートが飛びましたが、サーバにログインする頃には止んでおり、ロードバランサは起動している状態でした。

調査

どうやら、マスタ側のロードバランサで再起動が発生し、バックアップ側がマスタに昇格するのですが、その昇格後にまた再起動が発生する、という事象が繰り返されていたようです。
ロードバランサのログを調査したところ、oom-killerが動いていたりでメモリ周りで問題が起こっていそうでした。

(ロードバランサログ)
・kernel: keepalived invoked oom-killer: gfp_mask=0xd0, order=0, oomkilladj=0
・kernel: IPVS: ip_vs_conn_new: no memory available.

もしメモリの枯渇が起きていたとすれば、32bitカーネルを使用していることが原因の一つである可能性がありました。32bitカーネルでは、カーネルが使用するLowメモリが制限されるためです。
再起動が起こる前に、Webサーバに対するヘルスチェックのエラーが頻発していることもわかりました。

(ロードバランサログ)
・Keepalived_healthcheckers: Timeout connect, timeout server [“WebサーバIP”:”ポート ”].

同時刻に、Webサーバでは次のログが出ていました。

(Webサーバログ)
・kernel : TCP: TCP: Possible SYN flooding on port "ポート番号". Sending cookies. Check SNMP counters.
SYNフラッディングで攻撃された?と頭をよぎりますが、断定はできません。
このログは、正常の通信でもWebサーバが捌ききれない量の通信が来れば出力されます。

「パケットキャプチャが欲しいね」
インフラチーム内からそんな声が聞こえてきました。

再発

> 「パケットキャプチャが欲しいね」
この願いはすぐに叶いました...。

障害の調査中に、またロードバランサが再起動を繰り返し始めたのです。

パケットの特徴

すかさずtcpdumpでパケットを観測したところ、以下の特徴を持つパケットが大半を占めていることがわかりました。

・synパケット
・tcp window size が0
・オプションなし

正常な通信においては、synパケットが大半を占めるのは考えにくく、tcp windows size が0かつオプションがない、というパケットもありえなさそうです。 観測できた範囲では、頻度は1秒間におよそ10万パケットで、送り元のIPアドレスはばらけていました。

緊急の対策

対策を行うために、検証環境でロードバランサに負荷をかけるなどして、ロードバランサが落ちた原因を究明したいところでした。しかし、さらなる再発に備えて、取り急ぎ対応を行う必要がありました。

Amazon CloudFront の利用

KLabではオンプレ環境だけではなく、AWSを使用してのサービス提供も行っており、クラウドチームから、CloudFront を間に挟んでみてはどうか、という提案をもらいました。 (DDoSに対するAWSのベストプラクティス) Amazon CloudFront も既に運用の実績があったため、スムーズに実現できました。

対策の効果

CloudFrontを挟んで以降、しばらく経過を観察したのですが、上で観測したような大量のパケットはLVSに届かなくなりました。観察は、特徴に当てはまるパケットが来たらカウントするように、ロードバランサに以下の設定を投入して行いました。

# iptables -t mangle -A PREROUTING -p tcp -m u32 --u32 "0x20&0xffff=0x0" -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m length --length 40
tcp window size が0という特徴は、u32モジュール(参考)を使用し、オプションがないという特徴は、--length 40 とすることで、マッチさせています。CloudFrontを挟んでもなおパケットが届く場合は、更にDROPターゲットを指定すれば、netfilterでのフィルタリングもできそうです。

今回の場合、CloudFrontによってフィルタリングされているのか、そもそも観測したようなパケットがもう飛んできていないのか、その判断はできないのですが、以後ロードバランサが落ちることはありませんでした。

めでたし、めでたし!


...ではなく、
次回は、ロードバランサ再起動の原因と、その対策をご紹介します!

2007年10月09日

特集記事『Linuxロードバランサ構築・運用ノウハウ』を公開します

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

Linuxロードバランサ構築・運用ノウハウ』を公開します!

これはWEB+DB PRESS Vol.37の特集記事としてDSASチームが執筆したもので、技術評論社様の許可を得て今回公開するはこびとなりました。

一口でいうと、「Linux+IPVS+keepalivedを使って、冗長構成(Active/Backup)のロードバランサを作るまで」の解説記事で、

  1. サーバ負荷分散一般についてのはなし
  2. Linuxでロードバランサを作ってみる
  3. ロードバランサを冗長化

といった構成になっています。

みなさんがLinuxロードバランサを導入・構築・運用する際の一助になれば、DSASチームとしてもうれしい限りですので、是非、ご覧になってください!


klab_gijutsu2 at 00:07|この記事のURLComments(10)TrackBack(2)
2007年06月01日

Keepalivedのヘルスチェックを強化するパッチ

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

keepalived は MISC_CHECK を利用すると、標準の機能でサポートされていないヘルスチェックをすることができますが、MISC_CHECKの注意点でご紹介したように、安全に運用するためには結構気を使わなければいけません。また、比較的短い周期で繰り返さなければならないヘルスチェックでは「チェックの度に別プロセスを起動する」というアプローチは、できるだけ避けたいと考えるかもしれません。

というわけで、それなりにニーズがあると思われるヘルスチェック機能を keepalived-1.1.13 に組み込んでみましたのでパッチを公開します。
  • keepalived-extcheck.patch (46080bytes)
  • ただしこのパッチ、まだDSASの本番環境には適用していません。
    つまり稼働実績がありません。今は開発環境での試験運用中ですので、その点をご理解の上でご利用下さい。不具合報告などいただけると、とてもとても嬉しいです。

    追加した機能
  • FTP_CHECK: FTPサーバがNOOPコマンドに応答できるかをチェックする
  • DNS_CHECK: DNSサーバがレスポンスを返すことができるかをチェックする
  • SSL_HELLO: サーバがSSLハンドシェイクに応答できるかをチェックする


  • 続きを読む
    klab_gijutsu2 at 16:49|この記事のURLComments(0)TrackBack(0)
    2007年05月18日

    知っていても損はしないkeepalivedの話 〜 notification_emailの罠

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

    このブログではすでにお馴染みとなっている keepalived ですが、設定ファイルの書き方には少し癖があります。 今回は、keepalived を設定する上での注意点を紹介したいと思います。 なお、この内容は現在の最新バージョン(1.1.13)のものですのでご注意下さい。

    続きを読む
    klab_gijutsu2 at 21:01|この記事のURLComments(0)TrackBack(0)
    2007年02月23日

    パソコン1台ではじめるロードバランサ体験

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

    昨日書いたの通り,記事を寄稿したWEB+DB PRESS Vol.37が,今日発売になりました.それを記念して(?),記事の内容が簡単に実験できるパッケージを公開します.
    これは,VMWareを使って,だれでも直ぐにロードバランサの実験を始められるパッケージになっています.何台もマシンを集めたり,Linux をインストールする必要は一切ありません.無償配布されているVMWare Playerがあれば,いつでもどこでも実験ができます.

    もちろん,このブログで去年の夏に公開した4つのエントリ

    の実験もできます.

    ダウンロードはこちらからどうぞ(75MB程です).

    使い方は,ダウンロードしたパッケージに付属の ReadMe.txt をご覧下さい.また,同じ内容を以下に引用しておきます.続きを読む

    klab_gijutsu2 at 13:25|この記事のURLComments(0)TrackBack(3)
    2007年02月22日

    LVSロードバランサの作り方について雑誌記事を書きました! (WEB+DB PRESS Vol.37)

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

    WEB+DB PRESS Vol.37

    手前味噌ですが―
    WEB+DB PRESS Vol.37に寄稿しました!


    こんな内容です。

    特集2 Linuxロードバランサ構築・運用ノウハウ

    • 第1章 サーバ負荷分散概論
    • 第2章 LVSで実現するロードバランサ
    • 第3章 ロードバランサの冗長化
    • 第4章 負荷分散システム運用のコツ

    このブログの過去のエントリ、

    をより詳しく丁寧に説明し、加えて運用のコツについても書いた感じに仕上がっております。
    LVSやkeepalivedについて書かれた雑誌記事はあまり見かけないので、参考になるのではないかと思います!

    あとですね、この連載の内容に関連した「とあるもの」を後日プレゼントする予定です。準備ができたらこのブログで告知しますのでお楽しみに〜

    klab_gijutsu2 at 14:04|この記事のURLComments(0)TrackBack(0)
    2006年10月05日

    keepalivedの運用ノウハウお見せします 〜 割当管理を簡単にしたい

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

    keepalivedの設定ファイルは、以下のようなエントリをひたすら並べなくてはいけないので、規模が大きくなるほど可読性が落ちます。


    virtual_server_group SITE1 {
    a.b.c.d 80
    }

    virtual_server group SITE1 {
    delay_loop 3
    lb_algo wlc
    lb_kind DR
    nat_mask 255.255.252.0
    protocol TCP
    persistence_timeout 0
    real_server 192.168.8.1 80 {
    weight 1
    inhibit_on_failure
    HTTP_GET {
    url {
    path /s/health.jsp
    status_code 200
    }
    connect_port 80
    connect_timeout 5
    nb_get_retry 1
    delay_before_retry 2
    }
    real_server 192.168.8.2 80 {
    weight 1
    inhibit_on_failure
    HTTP_GET {
    url {
    path /s/health.jsp
    status_code 200
    }
    connect_port 80
    connect_timeout 5
    nb_get_retry 1
    delay_before_retry 2
    }
    }



    RealServerが10台以上もあるような大きなサイトだと、ひとつのサーバグループの設定だけでも1画面に収まり切らないほどの量になってしまうんです。こんな巨大な設定ファイルを人間が書き換えなければならないなんてとてもとても我慢できません。サイトを増やそうとしてどっかの設定をコピペしたままうっかり書き換え忘れるような事故が起きることは容易に想像がつきます。

    DSASの特徴のひとつとして、「サーバの増減が容易である」というものがあります。
    その実体が 「keepalived.confの編集」だと「どこが容易やねん!」という突っ込みが入ることは目に見えていますよね(笑

    DSASでは、設定ファイルの編集ミスによる事故を防止するためと、管理者の負担を軽くするために、様々な工夫をしています。

    続きを読む
    klab_gijutsu2 at 22:47|この記事のURLComments(0)TrackBack(0)
    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構成にすべし

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

    続きを読む
    klab_gijutsu2 at 10:26|この記事のURLComments(14)TrackBack(1)
    2006年08月30日

    こんなに簡単! Linuxでロードバランサ (3)

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

    前回はkeepalivedを使ってWebサーバを冗長化してみました。
    今回はkeepalivedのもう一つの機能であるVRRPを使って、ロードバランサ自身を冗長構成にしてみたいと思います。

    続きを読む
    klab_gijutsu2 at 13:07|この記事のURLComments(7)TrackBack(1)
    2006年08月28日

    こんなに簡単! Linuxでロードバランサ (2)

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

    前回までで、

    • 複数のWebサーバにロードバランスする

    というところまではできました。

    これでリアルサーバへ負荷分散することができたのですが、冗長性がありませんでした。つまり、リアルサーバがダウンしても、ロードバランサはそれを認識できず、ダウンしているリアルサーバなのにパケットを送ってしまっていました。

    このとき、クライアントから見ると、たまにサーバから応答がないように見えてしまいます。

    というわけで今回は冗長化のお話、

    • リアルサーバのヘルスチェック

    を紹介したいと思います。
    続きを読む
    klab_gijutsu2 at 10:01|この記事のURLComments(5)TrackBack(2)
    2006年08月24日

    こんなに簡単! Linuxでロードバランサ (1)

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

    DSASのロードバランサは高価なアプライアンス製品ではなく、LinuxのLVS (Linux Virtual Server)を利用しています。

    安価、というか、ハードウエア以外は金銭的コストがゼロなので、一般のクライアントからのアクセスを受ける外部ロードバランサのほかに、内部サービス用のロードバランサも配置しています。それぞれactive, backupで2台ずつあるので合計で4台もロードバランサがあることになります。(こんな構成を製品を使って組んだら数千万円すっとびますね)

    また、ネットワークブートでディスクレスな構成にしているので、ハードディスが壊れてロードバランサがダウンした、なんてこともありません。

    ですので「ロードバランサは高くてなかなか導入できない」という話を耳にする度にLVSをお勧めしているのですが、どうも、

    • なんか難しそう
    • ちゃんと動くか不安
    • 性能が出ないんじゃないか

    等々の不安の声も聞きます。

    そこでこれから数回に渡って、How toスタイルでLinuxでロードバランサを作ってみたいと思います。

    今回は初回ということで、ごくごく基本的な

    • 複数のWebサーバにロードバランスする

    というところまでやってみたいと思います。

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