_ 今朝の電車でおっさんが読んでたスポーツ新聞からちょっと見えてた見出し。頭のおかしい人が新幹線で全裸になってタイーホ。春だなぁ。
_ 出社してからニュースサイトを巡回して、それが ファーストサーバの社長だったと知る。あぁ。
_ ち、ちがうよっ、春だから頭のおかしい人が湧いてきたんじゃないよっ。だってレンタルサーバ会社の社長だよ? 頭がおかしいなんてことはないよ。最近のデータセンターは電力問題とか熱問題とかいろいろ大変だからね、きっと陽気がよくなってあったかくなったから熱暴走を起こして、その冷却のために大事なところを放熱してただけなんだよっ。
_ てか、ファーストサーバっていつのまにか yahoo の系列になってたのか。昔はクボタ(もちろん農業機械のクボタのことだ)の子会社だったよね、たしか。
_ メール屋を廃業して1年ほど経ちました。
_ ひさしぶりに sendmail のトラブルの調査をやってたんだけど、ほかの人がログの解釈をおもいっきりを間違ってるのに気がつかなかった。いやそれは違うだろ、と即座にツッコミ入れるぐらいじゃなきゃいかんのに、30分ぐらいその間違った方向に沿って調査を続けていた。その間違った路線での調査のときも、あれー、これどういう意味だっけー、とかそういうのが多くて泣ける。だいぶ鈍ってる。
_ それはおかしいぞと気がついた後の原因究明はわりと迅速にできたのが救いか。access と access.db の内容が食い違ってる上、間違ってる access.db の方がタイムスタンプは新しいなんてふつー起きないし、よほどのことじゃなければ疑わないってば。そういうことが起きちゃうシステムって腐ってるよな。……いや、作ったの自分たちだけど。
_ 職場のそばにドトールが開店したんだが、その呼び込み。「お2階に喫煙席ありまーす」。……えーと、オープンしたばかりの店からこのあたりを歩いてる人へのアピールとしてそれは正しいのか?
_ とあるシステムでのトラブル。サーバはよそのところ。こっちはクライアント。まったく同一の OS、同一の設定なのに、ホストによってあちらのサーバにアクセスできたりできなかったりする。以前から動いていたホストは問題ない。後から追加したホストがダメ。
_ この原因を突き止めるには週単位の時間がかかったんだけど、その究明過程は省いて結論を言うと、サーバ側の Linux が悪うござんした。
_ こちらのホストは複数だけど、NAT を使ってるのでサーバから見える IP アドレスは1個。クライアントであるこちらが TCP の timestamps option (RFC1323) を有効にしてセッションを張りにいくと、こちらのクライアントのそれぞれは一貫したタイムスタンプを付加するけど、複数あるのでサーバからは同じ IP アドレスからのタイムスタンプが増えたり減ったりするように見える。Linux のカーネルは「タイムスタンプっつーのは増えるもんだろ」という前提のもとに、タイムスタンプの巻き戻った(= OS が起動してからの時間が短い方のホストからの)パケットを捨ててしまう。これが顛末。もっと詳しい話は このへん。
_ 問題は、「タイムスタンプっつーのは増えるもんだろ」という前提が正しいものなのかどうか。このオプションは RFC1323 で定義されてるけど、タイムスタンプをパケットに含めて RTT を計測することで、TCP の再送タイムアウトを動的に調整しようという目的で導入されたもの。こちらからのパケットにタイムスタンプを含め、あちらが応答にそのタイムスタンプをそのまま載せると、その応答を受信したときのタイムスタンプの差でパケット単位の RTT が計測できる。もうひとつ、激しくパケットをやりとりする環境では TCP のシーケンス番号があっとゆーまに一周してしまって、遅延パケットがあると同一シーケンス番号が複数存在してしまうことがありうる。そんなときにどっちが古いパケットなのか判定するのにタイムスタンプを使う(PAWS)。
_ つーわけで、どちらの用途でもタイムスタンプが増えることが前提になっているのは確かなんだけど、RTT 計測ではあくまでパケット1個に閉じた話であって、いろんなセッションが入り乱れた中でそれらのパケットが正しく時刻の順番に送出されることを期待しているわけではないし、PAWS に関してはシーケンス番号の重複を発見してからはじめてタイムスタンプの比較をすればいいことであって、常時見張っている必要はない。
_ じゃあ Linux がなんでこんなことをやってるかというと、RFC1323 で想定しているのとはまったく無関係な用途に timestamps option を利用しているから。TIME_WAIT 状態で終了待ちのソケットをとっとと回収してリソースを開放するために、こいつを利用している。この副作用として、タイムスタンプの小さいパケットを落とす。えー。RFC に違反してるといえるかどうかは微妙だけど、本来の想定とはぜんぜん違う使い方をして疎通に支障が出るって、それおかしくね? つーわけで、わしとしての結論は Linux が悪い。
_ まあ、パケットのタイムスタンプが増えたり減ったりしてると こういう問題も起こしそうなので、一方的に悪者扱いするのもアレな気がするけど、でも今回の件には関係ないし、やっぱり Linux が悪いと思うよ。
_ それはそうと、重要なのは悪者探しではなく、つなげたくてもつながらんという目の前の現実をどうにかしてやること。いくつかの回避手段を以下に。
- サーバ側で net.ipv4.tcp_tw_recycle を無効にする
- クライアント側でパケットにタイムスタンプを付加しない
- 今回こちらが取った対応
- どうせ TCP のオプション機能なので、使わなくても通信はできる(使うことによる恩恵は当然受けられない)
- Linux なら net.ipv4.tcp_timestamps を無効に
- FreeBSD なら net.inet.tcp.rfc1323 を無効に
- Win9x はレジストリに設定項目があるのに無視されて常時無効:-)
- クライアント側で NAT をやめる。あるいは、
- NAT 箱で src/dst の IP を書き換えるだけでなく、タイムスタンプも書き換える(そんな酔狂な NAT 箱が存在するかどうかは知らん)
- クライアント - (NAT 箱) - サーバというスルーな構成ではなく、NAT 箱で TCP をいったん終端してクライアント - NAT 箱、NAT 箱 - サーバという2本の TCP セッションができるような構成にする