CoreOS:tcpdump 神秘地解決了網路問題(使用的套接字數量過多)
今天我有一個謎要告訴你。我們在 Azure 上執行一個基於 CoreOS(2023.5.0 / Linux 4.19.25-coreos)的小型三節點 Elasticsearch 集群。Elasticsearch 在主機網路模式下的 docker 容器內執行。在幾乎完全免維護執行一年多之後,我們已經看到機器進入了一個非常有趣的狀態。
更新
此問題已通過修復Linux 核心中的驅動程序得到解決。請參閱下面的答案。
症狀
基本上,受影響的機器和其他兩個節點之間的網路會死掉。所有都在同一個虛擬網路和同一個子網中,並且通常可以相互通信。受影響的節點仍然可以從其他子網(我可以 ssh 進入它)和不同的對等虛擬網路訪問。這台機器也有(非常不穩定的)網際網路連接,但大多數請求只是超時。
我們觀察到,在受影響的節點上,報告的“使用的套接字”數量
/proc/net/sockstat
非常高(~4.5k 而不是健康節點上的~300)。監控顯示,這個數字從節點變得不可用的那一刻起迅速上升。有趣的是,我們似乎無法辨識這些使用過的套接字的來源:
# 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 使用率最低,並且有大量可用記憶體。
在同一子網中對“無法訪問”的 VM 執行 Ping
EAGAIN
操作會導致recvmsg
對. strace ping 輸出在這裡ENOBUFS``sendmsg
我收集了一些額外的輸出(在對系統進行任何修改之前)並將其發佈在這個要點中: https ://gist.github.com/privatwolke/e7e2e7eb0272787765f5d3726f37107c
分析
我們已經嘗試關閉伺服器上我們能想到的所有東西,其中 elasticsearch 是第一個嫌疑人。但是關閉 elasticsearch 容器並不會釋放使用的套接字。所有與 CoreOS 相關的程序(更新引擎、locksmithd、…)甚至整個 Docker 執行時或 Azure 特定的東西都是一樣的。似乎沒有任何幫助。
但現在它變得更奇怪了:我們試圖
tcpdump
在機器上執行以查看發生了什麼。瞧:問題自己解決了,連接恢復了。我們的理論是 tcpdump 執行某種系統呼叫來解決它。我們使用 gdb 執行 tcpdump 並在所有系統呼叫上設置斷點。在遍歷大量斷點之後,我們終於發現在擷取套接字(特別是 libpcap 中的這一行)上設置混雜模式的行為是重置使用的套接字計數器並使我們返回正常狀態的事情。其他發現
我們已經驗證,
tcpdump
使用該-p/--no-promiscuous-mode
標誌執行不會清除使用的套接字計數器並將機器返回到可用狀態。執行
ifconfig eth0 txqueuelen 1001
會重置使用的套接字計數器,但不會恢復連接。手動設置 promisc 模式
ip link set eth0 promisc on
也不會恢復連接。
net.ipv4.xfrm4_gc_thresh
設置為 32768 並稍微增加它並不能解決問題。我們一直與 Azure 保持聯繫,他們和我們一樣對此感到困惑。我知道這可能不是問題,而只是一個症狀。但這是迄今為止我發現的唯一有形的東西。我希望通過了解症狀,我可以更接近根本原因。Azure 上的網路介面使用此網路驅動程序執行。
也許 CoreOS/Kernel 是罪魁禍首?
從時間線來看,問題開始於 2019 年 3 月 11 日,也就是 CoreOS 自動更新到最新版本的那一天。根據發行說明,此更新包含從**4.15.23 到 4.19.25**的核心更新。我仍在查看變更日誌,看看那裡是否有任何問題。到目前為止,我只發現 hyperv 網路驅動程序在最近幾個月收到了相當多的更新,並非所有更新似乎都是 4.19.25 的一部分。CoreOS 應用於 4.19.25 的更新檔集並沒有那麼令人印象深刻,但引入假 nf_conntrack_ipv4 模組的更新檔是新的。
幫助!
到目前為止,我們的問題如下:
- 什麼可能導致這個“使用的套接字”指標飆升?我已經閱讀了該指標的核心原始碼,它似乎只是一個計數器,沒有提及這些實際是什麼類型的套接字或創建它們的原因。
- 為什麼數字持平在 4.5k 左右?哪個限制會導致這種情況?
- 核心 4.14.96 和 4.19.25 之間是否發生了重大變化?
- 為什麼
setsockopt()
libpcap 中的呼叫會重置狀態?相關 CoreOS 錯誤:https ://github.com/coreos/bugs/issues/2572
這是由 Linux 核心中的 hv_netsvc 驅動程序中的錯誤引起的。我們可以與 Microsoft 開發人員一起解決此問題,並設法在上游應用修復程序。
我將在這裡引用送出消息,因為它很好地總結了問題:
當環形緩衝區由於 RX 完成消息而快滿時,TX 數據包可能會達到“低水位線”並導致隊列停止。如果 TX 完成在隊列停止之前到達,則可能會錯過喚醒。
此更新檔移動了對最後一個待處理數據包的檢查以涵蓋 EAGAIN 和成功案例,因此隊列將在必要時可靠地喚醒。
為了將來參考,修復此問題的送出是https://github.com/torvalds/linux/commit/6d9cfab853ca60b2f77b5e4c40443216988cba1f。
首先,感謝您寫得非常好的問題!
由於您描述的詳細程度非常高,並且您已經處於 gdb 級別,我認為我的回答對您沒有多大用處。無論如何,這是一個嘗試:
- 大概您已經嘗試過類似的東西
ss -ae
andlsof -n
?dmesg
發生這種情況時會返回任何有趣的東西嗎?- 你在伺服器上使用 iptables 嗎?
- 如果您使用 tcpdump 以外的其他方式設置混雜模式(例如,
ip link set [interface] promisc on
),這是否也解決了問題?- 你檢查過任何可疑的程序、文件或其他奇怪的活動嗎?只是想也許一些不請自來的討厭的過程潛伏在隱藏自己的陰影中,並且在設置混雜模式時保持沉默?
- 如果讓 tcpdump 在後台執行,會不會再次出現這個問題?
我希望這有幫助。