實體主機無法建立新連線,如何確認 conntrack 是否耗盡?
業務程序正常運作,既有長連線仍能傳輸,新請求卻間歇性逾時,這類現象不一定是應用程式的監聽佇列造成的。實體主機負責有狀態防火牆或網路位址轉換(NAT)時,Linux 的連線追蹤表也可能成為瓶頸。排查的重點是比對失敗發生的時間、表的使用量與核心計數,而不是看到連線多就直接提高上限。
本文以 Debian 13 為例,所有檢查都在宿主機的網路命名空間中執行。CloudUDP 主機付款後,可在控制台查看登入憑證,Linux 透過 SSH 連線;若有多個位址,請使用第一個位址連線。以下操作不會修改網路規則,也不會清空既有連線狀態。
一、確認故障流量經過連線追蹤路徑
連線追蹤(conntrack)會記錄通訊流的協定、位址、狀態與逾時時間,供狀態比對及 NAT 使用。一條業務連線不等於一個應用程式執行緒,應用程式關閉連線後,表項也可能繼續保留一段時間。密集建立短連線、異常掃描或流量轉送負載,都可能推高使用量。
先安裝檢查工具並讀取設定:
sudo apt-get update
sudo apt-get install conntrack
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
sudo conntrack -S
sudo nft list ruleset
規則中出現 ct state 或 NAT,表示需要留意連線追蹤容量,但沒有這些規則,也不能證明流量完全未經追蹤。若讀取參數時顯示不存在,應先確認模組與實際流量路徑,不要為了「補齊輸出」而貿然載入模組。
容器內的結果不能直接取代宿主機的結果。宿主機轉送的流量與容器內部流量,可能經過不同的命名空間,必須記錄命令的執行位置;否則很容易拿容器的低使用量來解釋宿主機的封包遺失。
不要將
conntrack -F當作例行復原手段。清空連線表會移除既有狀態,可能中斷依賴狀態比對或 NAT 的連線,也會讓原本需要保留的現場證據消失。
二、採集同一時段的使用量與錯誤增量
nf_conntrack_count 是目前的表項數,nf_conntrack_max 是容量上限。接近上限表示剩餘空間減少,但不能單憑這點就證明請求因此失敗。conntrack -S 會按處理器輸出統計資料,應將各處理器的同一欄位加總,再比較兩次採樣的差值,不能把其中一行當作整台主機的總量。
umask 077
out=$(mktemp -d /var/tmp/ct-check.XXXXXX)
for sample in 1 2; do
{
date -Is
sysctl net.netfilter.nf_conntrack_count
sysctl net.netfilter.nf_conntrack_max
sudo conntrack -S
} > "$out/sample-$sample.txt"
if [ "$sample" -eq 1 ]; then
sleep 10
fi
done
sudo journalctl -k --since "-10 min" --no-pager \
> "$out/kernel.txt"
printf '%s\n' "$out"
這裡的採樣間隔只是操作範例,實際採樣應涵蓋業務失敗發生的時段。重點是觀察 insert_failed、drop、early_drop 是否持續增加,以及核心是否出現連線表已滿的訊息。欄位可能隨核心版本而不同,不能因為缺少某個欄位就認定系統正常。
同時保存應用程式的新連線失敗次數、請求量與原始錯誤訊息。若主機剛重新啟動,累計計數的基準已經改變,不要直接將重新啟動前後的數值相減。離峰時段的錯誤計數不再增加,也不代表容量已通過尖峰負載的驗證。
三、判斷表項為何累積
先區分「正常並行連線數增加」與「異常建立速率」。比對入口請求、應用程式主動建立的對外連線、轉送業務及連線重用情況。大量短連線即使存活時間不長,也可能因建立速率過高而累積;長連線則更取決於實際的同時連線數。
避免一開始就匯出整張連線表
在忙碌的主機上,完整列出表項本身就會增加排查負擔,而且輸出包含通訊位址。先讀取彙總計數,確有需要時,再限制協定與輸出量:
sudo timeout 5s conntrack -L -p tcp -o extended 2>/dev/null \
| head -n 100
這段輸出只是有偏差的樣本,不是狀態分布統計。逾時或管線提早關閉,也可能讓命令以非零狀態碼結束,不能據此判斷連線表損壞。位址記錄只應保存在存取權限受限的目錄中,提交支援單前,先移除與問題無關的業務資訊。
也應同步檢查監聽程序、應用程式錯誤與上游回應。若使用量仍有餘裕、相關計數也沒有增加,應轉而檢查應用程式阻塞、路由或其他封包遺失位置,不要繼續只圍繞 conntrack 調整參數。
不要一開始就縮短所有協定的逾時時間。逾時設定決定閒置連線狀態保留多久,過度縮短可能影響長連線;連線池未重用連線、失敗後重試失控等問題,應在呼叫端修正。
四、依記憶體預算進行可回復的變更
提高上限只是允許更多表項存在,並不會修正異常流量的來源。表項會消耗核心記憶體,實際用量受協定擴充功能、核心設定等因素影響,不能用固定的「每筆若干位元組」來精確估算預算。
變更前,記錄 free -h、/proc/meminfo,並用 sudo slabtop -o 觀察核心物件快取。Slab 是核心用來管理物件的快取機制;其中的連線追蹤物件統計,也不涵蓋所有相關的記憶體成本。
若證據支持容量不足,而且記憶體仍有餘裕,可以小幅調整來驗證。以下將原上限增加四分之一,僅作為試驗幅度,並非建議的固定設定:
old=$(sysctl -n net.netfilter.nf_conntrack_max) || exit 1
case "$old" in
''|*[!0-9]*) exit 1 ;;
esac
new=$((old + old / 4))
printf 'old=%s new=%s\n' "$old" "$new"
sudo sysctl -w net.netfilter.nf_conntrack_max="$new"
保留目前的工作階段與原值,在相近的請求量下重新採樣。若失敗情況沒有改善,不要連續提高參數;應還原原值,並檢查其他證據:
sudo sysctl -w net.netfilter.nf_conntrack_max="$old"
還原前先核對目前使用量;若已超過原上限,應先降低新連線建立的壓力,否則還原後可能再次觸發容量問題。不要同時調整雜湊桶、協定逾時時間與防火牆規則,以免失去單一變因的驗證條件。
五、依業務結果決定是否永久套用
驗收必須同時滿足三類證據:相近業務量下,新連線成功率恢復;相關錯誤計數不再持續增加;記憶體與核心物件快取沒有出現新的壓力。只有使用率下降,不能算是完成修復。
確認有效後,將已驗證的數字寫入 /etc/sysctl.d/90-conntrack-capacity.conf。寫入前,檢查其他設定檔是否重複定義同一參數,避免載入順序造成覆寫。只載入本次檔案,不要順帶套用整台主機上其他尚未驗證的設定:
sudo sysctl -p /etc/sysctl.d/90-conntrack-capacity.conf
sysctl net.netfilter.nf_conntrack_max
檔案應包含一行 net.netfilter.nf_conntrack_max = 已驗證的整數,其中的說明文字必須替換成實際數字。待下次由維運安排重新啟動後,再核對生效值與載入錯誤,不要為了驗證參數就立即重新啟動正式環境主機。
最後保留原值、新值、採樣區間、請求量、計數差值與還原條件。連線追蹤容量管理的目標不是得到更大的數字,而是能解釋連線失敗、證明變更有效,並在負載改變後重新檢查同一組證據。
常見問題
conntrack 用量接近上限,就代表已經耗盡嗎?
不一定。應對照同一時段的 insert_failed、drop、early_drop 計數增量、核心日誌與業務新連線錯誤。高用量只是容量風險訊號,單一計數也不足以確認根因。
可以清空 conntrack 表來快速恢復服務嗎?
不應將清表當作一般恢復方式。清空會移除既有連線的追蹤狀態,可能中斷依賴狀態比對或 NAT 的工作階段。應先保留計數與日誌,再處理異常連線來源,或依記憶體預算調整容量。
EPYC 7543P 獨享實體主機,每月 $454 起