Serversman@VPSのネットワーク不調・TCP接続失敗

Serversman@VPSのネットワークが不調でTCP接続確立やコネクション維持に問題が起きている。

サポートに問い合わせても個別事象でしかないそうなので、利用者の方はチェックしてみてほしい。

TCPのSynのドロップ

TCPポートの死活監視をしていると、TCP接続タイムアウトがしばしば発生する。どうやら同一ソースIPアドレスからのTCP synを(おそらくsyn flood対策として)かなり厳しく制限しているようだ。

特に、連続してTCPを張ろうとするとドロップするため低頻度でポーリング監視している普通のモニターツールからは障害が見えにくい。

リモートからApache Benchで小さなファイルにアクセスさせてみたところ、

ab -n 32 -c 4 http://example.com/test.txt

(4並列で32回アクセス) はTCP synの再送中にタイムアウトしてしまった。 念の為 ab -n 32 -c 1 -kに代えてキープアライブ1本なら瞬時に終わる。

Apache Bench中の通信をダンプしてみると、

  • abクライアント側(外部ISP経由)にsyn/ackが返らずsyn再送している。
  • httpdサーバー側(serversman@vps)ではsynの一部が届いておらず、届いている分は正しくackやHTTPレスポンスを返している。

原状synを経路上でsynを数えていて、ある制限を超えると100%落としているように見える。コンテナ内の不具合や、ホストマシンのTCPバッファメモリやコネクション追跡テーブルがあふれているといった個別の事象による問題なら、tcpdumpでsynが見えないのはおかしい。

DDoS対策としてsynフィルタが重要なのはわかるけれど、原状の制限は厳しすぎるように思われる。自分の場合はプライベートRPMリポジトリを置いているため、yumリポジトリDBを取得する一連のlibcurlリクエストが高頻度で失敗するようになっている。

TCP syn flood対策に(動的な)グレーリストで制限をかけるなら、トークンバケツなり乱数なりで確率的に通すよう設定するべきではないだろうか。さもないと、一時的にグレーリストに載ってしまったまともなクライアントはsynを再送しつづけるだけで全く通信できなくなってしまう。

いったいどんなDDoS対策アプライアンスを使っているのかわからないが、DTIのネットワークが定常的に攻撃を受けているとしても、害の方が大きい対策のように思われる。

OpenVZのバッファサイズ制限

TCP不通・切断の件についてサポートに問い合わせると OpenVZによるバッファサイズ制限を超過しているのが理由ではないかと言われた。

Serversman@VPSの提供しているOpenVZ共有カーネルは、実際には仮想マシンではなくLXCと同じLinuxコンテナであり、ゲストカーネルは存在せず個別のVPSのリソースはホストの共有カーネル側が集中管理してカーネルのオーバーヘッドを落としている。

共有カーネル方式の問題として、ファイルディスクリプタやコネクション追跡、各種バッファメモリなど、枯渇しやすいカーネルリソースを一部のコンテナが浪費してしまう危険性があり、OpenVZは独自の方法でコンテナ別制限を加えている。(LXCではcgroupを使っている)

openvzによる制限値は/proc/user_beancountersで見られる。

ServersMan@VPSのEntryプランの制限は次の様になっていた。

# cat /proc/user_beancounters
Version: 2.5
       uid  resource                     held              maxheld              barrier                limit              failcnt
    ?????:  kmemsize                 56793972             91213824  9223372036854775807  9223372036854775807                    0
            lockedpages                     0                    0                  256                  256                    0
            privvmpages                129745               286007  9223372036854775807  9223372036854775807                    0
            shmpages                     3202               134274  9223372036854775807  9223372036854775807                    0
            dummy                           0                    0  9223372036854775807  9223372036854775807                    0
            numproc                        46                  102                  240                  240                    0
            physpages                  214818               262145                    0               262144                    0
            vmguarpages                     0                    0  9223372036854775807  9223372036854775807                    0
            oomguarpages                65858                91180                26112  9223372036854775807                    0
            numtcpsock                     23                  144                  360                  360                    0
            numflock                        1                   13                  188                  206                    0
            numpty                          3                    7                    8                    8                    0
            numsiginfo                      1                   30                  128                  128                    0
            tcpsndbuf                  181072              1731448              1720320              2703360              1779659
            tcprcvbuf                  117200              1728504              1720320              2703360                   91
            othersockbuf                40840              1081208              1126080              2097152                    0
            dgramrcvbuf                     0               261256               262144               262144                   82
            numothersock                   31                  291                  360                  360                    0
            dcachesize               49552266             79544590  9223372036854775807  9223372036854775807                    0
            numfile                       645                 1130                 9312                 9312                    0
            dummy                           0                    0  9223372036854775807  9223372036854775807                    0
            dummy                           0                    0  9223372036854775807  9223372036854775807                    0
            dummy                           0                    0  9223372036854775807  9223372036854775807                    0
            numiptent                      93                   93                  256                  256                    0

個別の意味はOpenVZのwikiをみてもらうとして、このうちtcpsndbuftcprcvbufが1680KBとかなり厳しい。

# sysctl -A | grep mem
...
net.ipv4.tcp_wmem = 4096        16384   4194304
net.ipv4.tcp_rmem = 4096        87380   4194304
...
net.core.wmem_max = 133120
net.core.rmem_max = 133120

TCPのバッファサイズ設定はデフォルトで16KBだが128KBまで増加するようになっていて、最悪14セッションで全て消費してしまう。

送信バッファは書込サイズに応じて自動的に拡大されるので、大きなデータを送信すれば簡単に上限まで消費する。この設定では、普通な使い方をしていてもOpenVZの制限値に一時的に引っかかってしまうのは当たり前だ。 TCPの切断はこれが原因でバッファ割り当てに失敗していた可能性がある。

一方OpenVZのドキュメントによればbarrierを短時間超えるだけなら問題はないとしている。長時間制限を超えていれば新しいコネクションにバッファを割り当てられず接続失敗する、というのはありうるものの、少なくとも自分のコンテナでは超過はごく短時間で、これが原因でTCPが接続確立に失敗するというわけでは無さそうだ。

自分の場合、バッファ制限にかかっていたのはrsync+sshによるバックアップだったので、全てのソケットにSO_SNDBUFSO_RCVBUFをセットしてみた(LD_PRELOADでsocketをフック)ところ、大幅なスループット低下と引き換えにfailcntは増加しなくなった。

が、もちろんTCP接続失敗の問題は解決していない。サポートはOpenVZの制限値をオーバーしているせいだというが、本当かどうかはかなり怪しい。

(ところで、openvzカーネルのバグなのか、net.core.wmem_maxを超えてバッファサイズが増えているようなのだが自分の気のせいだろうか?)

PINGのドロップ

PINGが4%ほどロストしている。 f:id:causeless:20150621202420p:plain

某所からの監視で赤がServersMan@VPSで借りているIPアドレス。 ログを見ると3月ごろから起きていたようだ。だいぶ帯域が逼迫しているようだ。

移行先

料金が倍になってしまうけれど、さくらのVPSあたりか。 国内リージョンのあるLinodeやVulterでもいいけれど、借りようとするたびにストックが無かったりしてあまり試せていない。

IDCFクラウドは最初の1インスタンスは月500円~と安価だけれど、IPv6が使いたいので、Proto41(6in4)を通せないVLAN構成のため移行先選択肢に入らない。