概要
netstat
やss
コマンドにより、あるホストと他のホストとのコネクションを一覧表示できる。しかし、Webシステムの場合、クライアントが並行接続するため、 同一ホストから複数のポートを介してコネクションを確立しているケースが多い。コネクション数が大きい場合は、1万以上のコネクションが表示され、ホスト間のコネクション状況を人間の目で概観することが難しかった。
そこで、同一ホストとのコネクションを集約表示し、コネクション状況を概観する 「lstf」 (「えるえすてぃーえふ」)コマンドをつくった。
lstfの特徴は以下の通り。
- コマンド実行ホストを起点に、active openコネクションかpassive openコネクションを判定する。つまり、接続をする側かされる側かを判定する。
- 各ホストフローごとにコネクション数を表示する
- Goで実装されているポータビリティ。i386バイナリであれば、CentOS5でも動作する。*1
- JSONサポート
実行結果
コマンド実行結果をみてみよう。
$ lstf -n Local Address:Port <--> Peer Address:Port Connections 10.0.1.9:many --> 10.0.1.10:3306 22 10.0.1.9:many --> 10.0.1.11:3306 14 10.0.2.10:22 <-- 192.168.10.10:many 1 10.0.1.9:80 <-- 10.0.2.13:many 120 10.0.1.9:80 <-- 10.0.2.14:many 202
ローカルホスト(10.0.1.9)はWebサーバでポート80番で待ち受けており、10.0.2.13と10.0.2.14からHTTPリクエストを受け付けていることがわかる。逆にローカルホストから10.0.1.10と10.0.1.11のMySQLサーバのポート3306番へ接続していることがわかる。ホスト同士の接続状況を知るためだけであれば、クライアントソケットが利用するポート番号を表示する意味はないため、many
として集約している。
--json
オプションでJSON表示もできるため、他のツールと連携し、利用できる。
$ lstf -n --json | jq -r -M '.' [ { "direction": "active", "local": { "Addr": "localhost", "Port": "many" }, "peer": { "addr": "10.0.100.1", "port": "3306" }, "connections": 20 }, { "direction": "passive", "local": { "addr": "localhost", "port": "80" }, "peer": { "addr": "10.0.200.1", "port": "many" }, "connections": 27 }, ... ]
実装
/proc/net/tcp
をパースする部分は、GitHub - shirou/gopsutil: psutil for golang を使わせてもらってる。
active openかpassive openかの判定は簡単で、コマンド実行ホストのLISTENポートに対するコネクションをpassive open、それ以外をactive openとしている。 *2
おまけ
Linuxのnetfilterには、conntrackというL4のコネクションフローに関するパケットを追跡する機構がある。(/proc/net/ipconntrack
, /proc/net/nfconntrack
からdump結果が読める) これを利用して、同じようにコネクションフローを集約表示するツールも作ってみた。github.com
inboundとoutboundとそれぞれについて、各パケットのサイズを合計し、conntrack tableに存在するフローごとのトラフィック量とパケット数を表示できるというメリットはある。 しかし、コネクション数が大きいホストではconntrack tableあふれを避けるために、conntrackを無効にしているため、どのホストでも使えるわけではなかった。
distributed black-box tracingをするための部品づくりを最近やってる。