今日はあなたにミステリーがあります。 AzureでCoreOS(2023.5.0/Linux 4.19.25-coreos)に基づく小さな3ノードのElasticsearchクラスターを実行します。 Elasticsearchは、ホストネットワークモードのDockerコンテナー内で実行されます。ほぼ完全にメンテナンスフリーで1年以上実行した後、マシンが非常に興味深い状態になるのを目にしてきました。
この問題は、 Linuxカーネル のドライバーを修正することで解決しました。以下の回答を参照してください。
基本的に、影響を受けるマシンと他の2つのノード間のネットワークが停止します。すべてが同じ仮想ネットワークと同じサブネット内にあり、通常、他のネットワークと通信できます。影響を受けるノードには、他のサブネット(sshで接続できます)および別のピアリングされた仮想ネットワークから到達できます。マシンはインターネットに(非常にむらがある)接続もありますが、ほとんどの要求はタイムアウトします。
影響を受けるノードでは、_/proc/net/sockstat
_によって報告される「使用されるソケット」の数が非常に多いことがわかりました(正常なノードでは約300ではなく約4.5k)。監視は、この数がノードが利用できなくなった瞬間から急速に増加することを示しています。
面白いのは、これらの使用済みソケットのソースを特定できないように見えることです。
_# cat /proc/net/sockstat
sockets: used 4566
TCP: inuse 2 Orphan 0 tw 2 alloc 98 mem 4
UDP: inuse 1 mem 0
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0
# cat /proc/net/sockstat6
TCP6: inuse 98
UDP6: inuse 1
UDPLITE6: inuse 0
RAW6: inuse 1
FRAG6: inuse 0 memory 0
_
それ以外はマシンは問題ないようです。疑わしいプロセスは実行されておらず、CPU使用率は最小限であり、使用可能なメモリが十分にあります。
「到達不能」にpingを送信するVMが同じサブネット内にある場合、EAGAIN
へのrecvmsg
応答がいくつか発生し、次にENOBUFS
に戻るfrom sendmsg
。 strace ping output here
(システムに変更を加える前に)追加の出力をいくつか収集し、このGistに投稿しました: https://Gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c
最初に容疑者はelasticsearchで、サーバー上で考えられるすべてのものをシャットダウンしようとしました。ただし、elasticsearchコンテナーをシャットダウンしても、使用済みのソケットは解放されません。すべてのCoreOS関連のプロセス(update-engine、locksmithdなど)、あるいはDockerランタイム全体またはAzure固有のものについても同様です。何も助けにならなかったようです。
しかし、今ではさらに奇妙になっています。何が起こっているのかを確認するために、マシンでtcpdump
を実行しようとしました。そして見よ:問題は自然に解決し、接続が回復した。私たちの理論は、tcpdumpがそれを解決するある種のシステムコールを行うというものでした。 gdbでtcpdumpを実行し、すべてのシステムコールにブレークポイントを設定しました。ブレークポイントの負荷をステップスルーした後、キャプチャソケット(特に libpcapのこの行 )で無差別モードを設定する動作が、使用されているソケットをリセットし、通常の状態に戻すものであることがわかりました状態。
-p/--no-promiscuous-mode
_フラグを使用してtcpdump
を実行しても、ソケット使用カウンタがクリアされず、マシンが使用可能な状態に戻らないことが確認されています。ifconfig eth0 txqueuelen 1001
_を実行すると、sockets usedカウンターがリセットされますが、接続はnotに復元されます。ip link set eth0 promisc on
_を使用して手動で無差別モードを設定しても、接続は復元されません。net.ipv4.xfrm4_gc_thresh
_は32768に設定されており、少し増やしても問題は解決しません。私たちは、これと同じくらい困惑しているAzureと連絡を取ってきました。これは問題ではなく、単なる症状であることを理解しています。しかし、それは私がこれまでに見つけた唯一の具体的なものです。症状を理解することで、根本的な原因に近づくことができることを願っています。 Azureのネットワークインターフェイスは this network driver で実行されます。
タイムラインの観点から、問題はCoreOSが最新バージョンに自動更新した日である2019-03-11に始まりました。 リリースノートによる 、この更新には 4.15.23から4.19.25へのカーネル更新が含まれていました。変更ログを調べて、問題があるかどうかを確認しています。これまでのところ、hypervネットワークドライバーが ここ数か月の間にかなりの数の更新を受け取った であることを発見しましたが、そのすべてが4.19.25の一部であるとは限りません。 CoreOSが4.19.25に適用したパッチセットはそれほど印象的ではありません ですが、偽のnf_conntrack_ipv4モジュールを導入するパッチは新しいものです。
これまでのところ、私たちが持っている質問は次のとおりです。
この「使用されたソケット」メトリックが急上昇する原因は何ですか?私は kernel sources を読み、このメトリックは just a counter のようです。実際にどのような種類のソケットであるか、それらを作成したものは参照していません。
数が約4.5kでフラットラインになるのはなぜですか?これを引き起こしているのはどの制限ですか?
カーネル4.14.96と4.19.25の間で何か重要な変更はありましたか?
Libpcapのsetsockopt()
呼び出しが状態をリセットするのはなぜですか?
関連するCoreOSのバグ: https://github.com/coreos/bugs/issues/2572
これは、Linuxカーネルのhv_netsvcドライバーのバグが原因でした。これをマイクロソフトの開発者と解決し、上流で修正を適用することができました。
ここではコミットメッセージを引用します。問題を非常によくまとめています。
RX完了メッセージが原因でリングバッファがほぼいっぱいになると、TXパケットが「最低水準点」に到達し、キューが停止することがあります。 TX完了がキュー停止よりも早く到着した場合、ウェイクアップが失敗する可能性があります。
このパッチは、最後の保留パケットのチェックを移動して、EAGAINと成功の両方のケースをカバーするため、必要なときにキューが確実にウェイクアップされます。
今後の参考のために、これを修正するコミットは https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f です。
まず、非常によく書かれた質問をありがとう!
あなたが説明した詳細レベルは非常に高く、あなたはすでにgdbレベルにいるので、私の答えはあまり役に立たないと思います。とにかく、ここで試してみます:
ss -ae
およびlsof -n
?dmesg
は興味深いものを返しますか?ip link set [interface] promisc on
)、これも問題を解決しますか?これがお役に立てば幸いです。