Skip to content
All writing Part 12 of 12 · 在容器裡遙控 Chrome 的完整路由
Engineering · 3 min read

noKeepAlive:為什麼每次都要重新連線

Go 預設的 HTTP client 重用 TCP 連線,跳過 DNS。KEDA 縮容後,舊連線會打到死掉的 Pod。一個設定就能修好。

問題

Go 的預設 HTTP client 會重用 TCP 連線。對固定伺服器來說省時間。但 Chrome Pod 不是固定伺服器。KEDA 隨時在擴縮。重用的連線可能指向一個已經消失的 Pod。

預設 client(keep-alive ON): Req 1 → TCP 連到 10.0.1.5 → 成功 → 保持管道 KEDA 縮容 → 10.0.1.5 已消失 Req 2 → 重用舊管道 → 斷線(跳過 DNS,打給死掉的 Pod) 斷線 noKeepAliveClient(keep-alive OFF): Req 1 → TCP 連到 10.0.1.5 → 成功 → 關閉管道 KEDA 縮容 → 10.0.1.5 已消失 Req 2 → DNS 查詢 → 拿到新的 Pod IP → 成功(每次都重新查) 成功

為什麼 Keep-Alive 會跳過 DNS

Keep-alive 連線是一條直通某個 Pod IP 的 TCP 管道。Client 把管道撐開。下一次 request 直接送到同一條管道,不再問 DNS。如果那個 IP 後面的 Pod 已經不在了,request 就失敗。

keep-alive ON: DNS → Pod IP → TCP 打開 ────► 重用 ────► 重用(不查 DNS) keep-alive OFF: DNS → Pod IP → TCP 打開 → 關閉 → DNS → Pod IP → TCP 打開 → 關閉

修復方式

一個設定。每次 request 開一條新 TCP 連線,結束就關掉。5 秒的 timeout 防止卡在連不上的 Pod。

var noKeepAliveClient = &http.Client{
    Transport: &http.Transport{DisableKeepAlives: true},
    Timeout:   5 * time.Second,
}

三道防線缺一不可

少掉任何一道,系統會用不同的方式壞掉。

防線 少了它 Headless Service DNS 回傳 Pod IP Proxy 隨機轉接 → GUID race Atomic round-robin 分散到不同 Pod 所有 goroutine 擠同一個 → 負載不均 DisableKeepAlives 每次 request 開新 TCP TCP 連到死掉的 Pod → 縮容後失敗

不要加 connection pool。Pool 會保持對 Pod IP 的連線,KEDA 隨時可能把那個 Pod 收掉。Chrome Pod 的 HTTP 呼叫必須保持無 pool。


參考來源:

Related: 看提供 Pod IP 的 headless Service,或回到系列總覽

Tags #kubernetes #chrome-devtools #containers
// connect

Be brave | Be wise | Be grateful

21 BreakinCode

// elsewhere
LinkedInMedium (lang: en)Youtube
wh:~$William Hung· © 2026 Taipei · GMT+8 · Available for collaboration