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をみてもらうとして、このうちtcpsndbuf
やtcprcvbuf
が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_SNDBUF
、SO_RCVBUF
をセットしてみた(LD_PRELOADでsocketをフック)ところ、大幅なスループット低下と引き換えにfailcntは増加しなくなった。
が、もちろんTCP接続失敗の問題は解決していない。サポートはOpenVZの制限値をオーバーしているせいだというが、本当かどうかはかなり怪しい。
(ところで、openvzカーネルのバグなのか、net.core.wmem_max
を超えてバッファサイズが増えているようなのだが自分の気のせいだろうか?)
PINGのドロップ
PINGが4%ほどロストしている。
某所からの監視で赤がServersMan@VPSで借りているIPアドレス。 ログを見ると3月ごろから起きていたようだ。だいぶ帯域が逼迫しているようだ。
移行先
料金が倍になってしまうけれど、さくらのVPSあたりか。 国内リージョンのあるLinodeやVulterでもいいけれど、借りようとするたびにストックが無かったりしてあまり試せていない。
IDCFクラウドは最初の1インスタンスは月500円~と安価だけれど、IPv6が使いたいので、Proto41(6in4)を通せないVLAN構成のため移行先選択肢に入らない。