Server上のtail-fがいつの間にか切れる †
晴れ。細かいタスクがいっぱいでテニスには参加できなかった。
SSHを使ってサーバーにログインし、たまに流れる系のLogをTailしっぱなしにしておいた。しばらくしていざそのログ画面を見てみてもログは流れていない。エンターキーを何度かカチャカチャしているとしばらくしてConnection closedなんて言われることないだろうか?これは大抵ルーターのNATがタイムアウトしたテーブルを削除することによって起こる。
NATの話はまた今度にするとして、NATはしばらく使っていないマップテーブルを勝手に消してしまうことがある。これはNATの機能を考えたときには自然な発想で、NAT変換テーブルは割りと限られたリソースなので占有されるといろいろ困ったことになる、ネットワークの規模によっては深刻な問題になるのでなるべく早くタイムアウトを検知して変換テーブルを開けようとする。HTTPの様な短いライフサイクルの物が主流になった現在このタイムアウトはさほど問題にはならないが、ソケットを長い間開放しっぱなしにし、ある程度の無通信時間もありえるようなプロトコルには向いていない。コネクションプーリングや、SSHがまさにそうだ。
ネット上には同じ悩みを抱えている人がいっぱいいて、対策も紹介されている。要は無通信時も定期的に対象TCPソケット上でパケットを流してNATテーブルのタイムアウトカウントをリセットすることにある。なので、SSHクライアントサーバー間で無害な制御文字を定期的に送るだけでことは足りる。ポートフォーワーディング時に"ping -i 300"などで生存確認ができるのは、Ping自体はICMP、第3レイヤーの話なので本来SSHには関係ないが、トンネルの先にPingした場合、トンネルを通過して通信が発生するので結果的にカウントリセットができるという意味だろう。TCPのKeep Aliveもこの用途で使って構わないだろう。最近のOSはsetsockoptとかでKeep Aliveの送信間隔を指定できるのか、いいね。
OpenSSHにはクライアントの設定でServerAliveIntervalという指定ができる。これはアプリレベルでKeep Aliveする、前述の無害な制御文字を送る方法に近い。これだけ家庭用ルーターが一般的になるとスタンダードになりそうな設定だね。
~/.ssh/config
ServerAliveInterval 60
ServerAliveCountMax 3
これでLogのTailを放置してもちゃんと生きるようになったよ。やったぁやったぁ^0^