なぜsnmpdがリクエストに答えないのか突き止めるべく、まずprstat (topみたいなやつ)で様子を見てみたら、snmpdが3%以上のCPU使用率でトップに君臨していました。この使用率は32CPUで計算されているので、本当は8コアのUltraSPARC T1にはかなりの重荷です。
いったい何をそんなに忙しくしているのかとtrussで追ってみたら、ひたすらファイル記述子6番からgetmsgでメッセージを読んでいました。このメッセージの読み込みが忙しくてリクエストに答えるひまがないようです。
こんなときはlsofがあると簡単なんですが、インストールしていなかったのでmdbでファイル記述子6番の正体を突き止めます。
> 0t28008::pid2proc | ::fd 6 | ::print file_t f_vnode | ::vnode2path
/devices/pseudo/arp@0:arp
こつがわかるまで少し時間がかかりますが、わかってしまえばmdbはとても便利です。 相手はなんと/dev/arpでした。Solarisは/dev/arpにtcpモジュールとudpモジュールをpushすると、MIB-II情報が取れるようになるらしいのです。
MIB-IIのTCP-MIBにはすべてのコネクションの情報が含まれています。snmpdはこれを必死に読んでいたわけです。まずは、このコストを手っ取り早く下げるために、getmsgで使うバッファのサイズを20倍にするという手に出ました。これでいくらか改善されましたが、本質的な解決には程遠い状態でした。
どうせ使ってないんだからTCP-MIBなんか捨ててしまおうかと思ったとき、一緒に同じ問題に取り組んでいたZinが重要なことに気が付きました。net-snmpは頻繁に/dev/arpを読みに行かないようにするために値をキャッシュしているのですが、そのキャッシュのサイズが小さすぎるのです。
{MIB_TCP_CONN, 1000 * sizeof(mib2_tcpConnEntry_t), ...
1000コネクション分じゃぜんぜん足りません。これを65536に変更したら見事に解決しました。C10K問題はこんなところにも潜んでいた、というのが今回の落ちです。
{MIB_IP_ROUTE, 200 * sizeof(mib2_ipRouteEntry_t), ...
返信削除実は↑も増やしてあげないといけません。どうやら経路表に PMTU の値を保持しているらしく、セッション数が増えると経路表も大変なことになるみたい。