阿里妹導讀
文章探討了為什麼大規模叢集中的可觀測性服務會產生大量API請求、API伺服器為何對DNS解析至關重要以及故障恢復過程為何緩慢的原因。
背景
12月11日,OpenAI 出現了全球範圍內的不可用故障,影響了 ChatGPT,API,Sora,Playground 和 Labs 等服務。影響範圍從 12 月 11 日下午 3:16 至晚上 7:38 期間,持續時間超過四個小時,產生顯著影響。
從官方覆盤[1]中摘取根因分析如下:
Root Cause
OpenAI operates hundreds of Kubernetes clusters globally. Kubernetes has a control plane responsible for cluster administration and a data plane from where we actually serve workloads like model inference.
As part of a push to improve reliability across the organization, we’ve been working to improve our cluster-wide observability tooling to strengthen visibility into the state of our systems. At 3:12 PM PST, we deployed a new telemetry service to collect detailed Kubernetes control plane metrics.
Telemetry services have a very wide footprint, so thisnew service’s configuration unintentionally caused every node in each cluster to execute resource-intensive Kubernetes API operations whose cost scaled with the size of the cluster. With thousands of nodes performing these operations simultaneously, the Kubernetes API servers became overwhelmed, taking down the Kubernetes control plane in most of our large clusters. This issue was most pronounced in our largest clusters, so our testing didn’t catch it – and DNS caching made the issue far less visible until the rollouts had begun fleet-wide.
The Kubernetes data plane can operate largely independently of the control plane, but DNS relies on the control plane – services don’t know how to contact one another without the Kubernetes control plane.
In short, the root cause was a new telemetry service configuration that unexpectedly generated massive Kubernetes API load across large clusters, overwhelming the control plane and breaking DNS-based service discovery.
這裡我們需要理清楚如下幾個問題:
-
為什麼可觀測服務會產生如此大量的 API Server 請求? -
Api Server 為什麼會影響 DNS 解析? -
故障恢復為什麼這麼慢?
K8s 場景下
為什麼可觀測服務需要訪問 API Server
K8s 元資訊資料感知與可觀測資料富化
1. 生命週期短容器的短暫性和高度動態特性使得它們的生命週期極其短暫,這意味著許多容器可能在執行期間生成重要的日誌資訊,但一旦容器被銷燬,這些資訊就會隨之消失。日誌的瞬時性給日誌採集帶來了極大的挑戰。
2. 分散式架構容器通常部署在多個節點上,這種分散式架構導致日誌資料儲存在不同的位置。資料的分散性不僅增加了管理的複雜性,而且可能導致即時資料採集和分析的困難。
3. 儲存方式多樣容器的儲存方式各異,包括卷、掛載等。這些儲存方式的多樣性使得日誌的寫入、讀取和管理變得更加複雜。
4. 資料與容器元資訊關聯容器日誌作為可觀測資料,必須與容器的元資訊(如容器 ID、名稱、標籤等)進行精準關聯,以便於後續的查詢與分析,有效地匹配資料與容器資訊有助於快速定位問題源頭。然而,由於容器的頻繁建立和銷燬,以及其動態變化的特性,在資料採集時及時、準確地建立這種關聯,依然是一大挑戰。
其中,Pod 資訊感知、可觀測資料與元資訊關聯,都可以透過對 API Server 請求來獲取。
可觀測資料採集服務發現需要跟 API Server 互動

對於 Prometheus 指標資料採集,比如定義 PodMonitor/ServiceMonitor 之後,Prometheus Operator 實際上就會去 API Server 請求對應的 Pod 資訊,從而發現需要採集指標資料的 Pod/Service。
OpenAI 的可觀測元件的做法
vs LoongCollector/iLogtail 的做法
OpenAI 的做法
從故障分析報告中,Telemetry services have a very wide footprint, so this new service’s configuration unintentionally caused every node in each cluster to execute resource-intensive Kubernetes API operations whose cost scaled with the size of the cluster. 可以看到 OpenAI 的可觀測服務,從每個節點上,都向 API Server 去請求資源資料。
由此,我們可以猜測,OpenAI 的可觀測服務是類似 Daemonset 的部署模式,每個節點的 Pod,都會向 API Server List-Watch 大量資源。比如使用Daemonset 的方式部署 Prometheus Agent ,這樣做會對API Server 產生大量的壓力:
-
當 Prometheus 執行在叢集中的每個節點上時,watch 的壓力 * 節點數量增加
-
在 O(100) 或 O(1000) 節點的大型叢集上,這會給 K8s API Server 帶來相當大的壓力,壓力體現在如下幾方面:
-
每個 watch 產生 2 個 go 協程,具體可以參考原始碼[2] -
需要處理給定種類的物件的所有更改 -
需要序列化並向客戶端傳送給定種類物件的更新
所以 OpenAI 為什麼測試的時候沒有發現問題,故障分析報告中也有提到:
-
The change was tested in a staging cluster, where no issues were observed. The impact was specific to clusters exceeding a certain size, and our DNS cache on each node delayed visible failures long enough for the rollout to continue. 本質上就是測試叢集的規模、節點數不夠多,所以沒有觸發問題。
-
Our main reliability concern prior to deployment was resource consumption of the new telemetry service. Before deployment, we evaluated resource utilization metrics in all clusters (CPU/memory) to ensure that the deployment wouldn’t disrupt running services. While resource requests were tuned on a per cluster basis, no precautions were taken to assess Kubernetes API server load. This rollout process monitored service health but lacked sufficient cluster health monitoring protocols. 其實就是沒有意識到這樣架構下,會對 API Server 產生大壓力,測試的時候,甚至根本沒有觀測過 API Server 的情況。
LoongCollector/iLogtail 的做法
LoongCollector 秉承 All-in-One 的設計理念,致力於所有的採集工作用一個 Agent 實現 Logs、Metric、Traces、Events、Profiles 的採集、處理、路由、傳送等功能。LoongCollector 著重強化了 Prometheus 指標抓取能力,深度融入 eBPF(Extended Berkeley Packet Filter)技術以實現無侵入式採集,提供原生的指標採集功能,做到真正的 OneAgent。在 K8s 場景下,同樣面臨 K8s 資源監控與元資訊獲取的需求,為了減少對 API Server 的影響,我們採用瞭如下的最佳化方案:
-
節點上與容器執行時互動,獲取基礎的容器元資訊,用來滿足 Daemonset 部署場景的容器發現和可觀測資料與元資訊關聯;
-
叢集內,單副本 List-Wactch,為 LoongCollector 指標採集提供統一的 Target Allocator 能力,避免對 API Server 產生大量請求;

Api Server 為什麼會影響
DNS 解析 && 故障恢復為什麼這麼慢
從 K8s 官方文件,我們很容易找到這樣的架構圖:

可以看到 API Server 是 Kubernetes 叢集中的最核心的元件, 在 Kubernetes 叢集中扮演著至關重要的角色,不僅提供了強大的 API 服務,還負責資料儲存、版本管理、訪問控制等多個方面的功能,確保了叢集的高效執行和安全性:
-
API 服務端:作為 Kubernetes API 的服務端,API Server 為叢集內的節點以及 kubectl 工具提供 API 服務。這意味著使用者可以透過 API Server 與 Kubernetes 叢集進行互動,執行如建立、更新、刪除資源等操作。 -
叢集元件代理:API Server 還充當叢集元件的代理,例如 Kubernetes UI,使得這些元件能夠透過 API Server 與叢集進行通訊。 -
資料儲存互動:API Server 是唯一能夠與儲存系統 etcd 互動通訊的元件。它負責將客戶端請求的資料進行編碼、解碼,並存儲到 etcd 中。同時,API Server 支援不同版本之間的資料轉換,確保資料的一致性和相容性。 -
訪問控制:API Server 負責身份鑑權和訪問控制,確保只有經過授權的使用者才能訪問特定的資源。此外,API Server 還可以設定訪問邏輯(Admission Control),進一步增強安全性。 -
通訊機制:API Server 與 Controller Manager、Scheduler 以及 kubelet 之間透過 List-Watch 方式進行通訊。Controller Manager 透過 etcd 獲取需要建立資源的副本數,交由 Scheduler 進行策略分析,最後由 kubelet 負責 Pod 的建立和容器載入。
Api Server 為什麼會影響 DNS 解析

當客戶端 Pod 需要進行域名解析時,首先會向 KubernetesDNS/CoreDNS 發出查詢請求,KubernetesDNS/CoreDNS基於其記憶體中維護的 DNS 記錄,迅速返回相應服務的 IP 地址。這一過程不僅提高了域名解析的效率,也增強了系統的可伸縮性和可靠性。
當然為了避免CoreDNS 壓力過大,Kubernetes 也提供高了 Local DNS Cache 的方式,在節點上,對於 DNS 記錄進行快取。但是當 API Server 幾乎掛掉的情況下,KubernetesDNS/CoreDNS 裡的 DNS 記錄沒有辦法得到更新,因此 Kubernetes 服務發現基本處於不可用的狀態。
故障恢復為什麼這麼慢
其實定位到可觀測服務的問題之後,最簡單的方式就是直接kubectl delete把可觀測服務刪除掉,但是很可惜,API Server 其實就是kubectl命令的入口,API Server 在幾乎故障的情況下,是沒有辦法響應管理命令的。
為了保證 API Server 可用,OpenAI 團隊在做故障恢復的時候做了如下措施:
-
縮小叢集規模:降低總 Kubernetes API 負載。 -
阻止對 Kubernetes 管理員 API 的網路訪問:阻止新的高資源成本請求,讓 API 伺服器有時間恢復正常。 -
擴充套件 Kubernetes API 伺服器:增加可用資源以消化待處理請求,藉此為修復操作留出空間。
由此,把有問題的可觀測服務刪掉之後,叢集恢復了正常的狀態。
給 iLogtail/LoongCollector 關於穩定性方面的啟示
OpenAI 的這次故障,有著多方面的原因,比如服務依賴沒有梳理清楚,可觀測服務架構設計上不合理,准入測試沒有起到作用等等。這些原因對我們自己的服務有著同樣的警示作用,這不得不讓我們再反思一下我們在穩定性方面還有哪些需要注意的地方。
深刻理解我們的服務對基礎環境的影響
在設計和實施可觀測方案時,最重要的一點是確保其對基礎環境系統的影響最小化。我們需要避免過多的負載和資源消耗,以免影響系統的正常執行。任何可觀測資料的採集都應經過精心設計,確保不會對業務流程造成干擾或延遲。
在主場景中,需要特別關注CPU、記憶體、磁碟、網路、控制代碼等資源的佔用情況,確保我們不會佔用預期之外的資源。在 Kubernetes 環境中,我們的服務對核心元件如CRI(容器執行時介面)、API Server、DNS等的影響與依賴同樣不容忽視,這直接關乎整個叢集業務的穩定性。
避免迴圈依賴
例如,服務 A 的正常運作對服務 B 至關重要,而同樣,服務 B 也可能依賴於服務 A。這種雙向依賴關係在 Kubernetes 環境中特別凸顯,以 ECS 異常監控為例,如果我們採用 LoongCollector Daemonset 對節點進行監控,但 ECS 異常又會反過來影響 LoongCollector 資料上報,這種複雜的依賴關係使得故障排查和系統恢復變得更加困難。在設計服務時,應該儘量避免或減少迴圈依賴的情況,以提升系統的穩定性與可維護性。
架構層面資料面與管控面隔離
我們需要探討資料面是否會對管控面產生依賴。例如,如果我們的配置伺服器(configserver)出現故障,這種故障是否會影響到已在執行的日誌採集工具(logtail)?理想情況下,當配置伺服器無法下發新配置時,logtail 應該能夠依靠本地快取繼續正常傳送資料。這就強調了系統在設計時必須確保資料傳送的獨立性,以避免由於管控層的故障而導致資料流失或中斷。
壓力測試
隨著 K8s 單叢集節點規模的不斷增加,iLogtail/LoongCollector DaemonSet部署模式下對單一服務請求的壓力也是呈現倍數級增加。我們當前的架構中也存在類似的設計與依賴,比如DaemonSet 的 Pod 會請求 LoongCollector 承擔 Meta Server 的 Pod。 這意味著我們有必要對一定叢集規模下服務架構的穩定性與效能進行模擬測試,確保在生產環境,面對巨大規模叢集的情況下,我們的服務依然能夠保持高效的響應與穩定性,避免出現意外的效能崩潰。
透過不斷反思與最佳化,我們將進一步提升 iLogtail/LoongCollector 的可靠性與穩定性,確保其在未來的複雜環境中依然具備卓越的表現。
參考連結:
[1]https://status.openai.com/incidents/ctrsv3lwd797
[2]https://github.com/kubernetes/kubernetes/blob/v1.25.2/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/get.go#L263
應用日誌資料歸檔
為企業提供雲上日誌資料的儲存成本最佳化,供了訪問日誌資料採集、自動壓縮、持久化儲存,滿足企業的網站訪問日誌資料的歸檔需求。具有低成本、免運維、彈性擴容的優勢。
點選閱讀原文檢視詳情。