雲原生日誌架構實踐:網易數帆開源Loggie的三生三世

語言: CN / TW / HK

導讀:網易從2015年就開始了雲原生的探索與實踐,作為可觀測性的重要一環,日誌平臺也經歷了從主機到容器的演進,支撐了集團內各業務部門的大規模雲原生化改造。本文會講述在這個過程中我們遇到的問題,如何演進和改造,並從中沉澱了哪些經驗與最佳實踐。

主要內容包括:

  • Operator化的⽇志採集
  • ⼤規模場景下的困境與挑戰
  • 開源Loggie的現在與未來

01 雲原⽣最初的探索 Operator化的⽇志採集

早期公司內部業務跑在物理機上時,各業務使用的日誌採集工具、日誌中轉和儲存、配置下發都比較混亂,選型種類多。公司內基於輕舟平臺推進了各服務容器化和雲原生化,隨著服務不斷地遷移到K8s上,我們關於採集K8s容器日誌和日誌平臺方面積累很多實踐經驗。

雲原生日誌是什麼樣的,容器日誌採集和主機上服務的日誌採集有什麼差異?首先Pod在K8s中會頻繁地發生遷移,手動去節點上變更配置日誌採集配置不太切實際。 同時,雲原生環境中日誌儲存的形式多樣,有容器標準輸出和HostPath,EmptyDir,PV等。另外,採集日誌後,一般會根據雲原生環境的Namespace、Pod、Container、Node甚至容器環境變數、Label等維度進行檢索和過濾,這些元資訊需要在日誌採集時被注入。

常見的雲原生環境日誌採集有以下三種思路:

1. 只採集標準輸出

日誌列印到標準輸出的操作雖然符合雲原生十二要素,但是很多業務還是習慣輸出到日誌檔案中,而且只採集標準輸出日誌難以滿足一些複雜業務的需求。常規的採集標準輸出日誌的方式是掛載/var/lib/docker,/var/log/pods下的目錄。同時需要注意選型的日誌Agent是否支援注入k8s元資訊。

2. Agent⽇志路徑全域性掛載

日誌可以放在EmptyDir,HostPath或PV儲存中,通過DaemonSet方式把日誌採集Agent部署到每一臺k8s節點上。EmptyDir等儲存對映到節點的目錄可以通過通配的方式配置到Agent進行採集,由Agent讀取配置路徑下的日誌檔案。

但這種通用匹配的方式無法根據服務級別進行單獨配置。如果需要配置只採集某些服務的日誌、或是某一個應用和其他應用的格式不同,例如某個應用的日誌是多行的日誌,此時需要單獨修改配置,管理成本比較高。

3. Sidecar⽅式

每個業務Pod在部署時都增加一個日誌採集的Agent SideCar,可以通過容器平臺或k8s webhook的方式把日誌採集Agent注入到Pod內。Agent可以通過掛載相同的HostPath或EmptyDir的方式採集到業務容器的日誌。

這種方式的弊端是對Pod侵入性強,Pod數量多時資源消耗較大。

 

對比DaemonSet和SideCar兩種部署方式,DaemonSet在穩定性、侵入性、資源佔用方面有優勢,但隔離性、效能方面SideCar方式更好。我們實踐中會優先使用DaemonSet方式採集日誌。如果某個服務日誌量較大、吞吐量較高,可以考慮為該服務的Pod配置Sidecar方式採集日誌。

針對日誌採集方面的痛點,我們提出的第一個初步方案是:自研的Ripple Operator配合開源的日誌採集客戶端Filebeat進行業務日誌採集。

部署方面,FileBeat、Ripple通過SideCar方式部署在一起,Ripple監聽k8s。在使用方面,使用者通過CRD,一個CRD可以表示一個服務的日誌採集配置,Ripple可以和k8s互動感知到Pod生命週期。Ripple可以下發配置到Agent,自動新增Pod相關元資訊並注入到日誌中。儲存方面HostPath、EmptyDir、PV、Docker Rootfs都可以支援。

圖中日誌採集的架構先在網易嚴選進行了應用, 後面逐漸地被公司內絕大多數部門參考落地,具體架構會根據實際環境有所區別。首先日誌平臺下發配置,Ripple監聽到K8s的CRD配置變動後,把配置下發給Filebeat。Filebeat把採集到的日誌傳送到中轉機,中轉機發送給Kafka,Flink消費Kafka資料進行處理後轉發給後端日誌儲存。

02 進⼊深⽔區⼤規模場景下的困境與挑戰

隨著接入的業務越來越多,1.0版本的日誌架構逐漸暴露了一些問題:超大規模下系統的穩定性問題、日誌平臺效能問題、排障困難和排障需求不斷增多、維護人力成本直線升高等。

在前面介紹的架構中,Filebeat會把每個服務的日誌傳送給中轉機。但是Filebeat是一個單一的佇列架構,在中轉機的阻塞會影響整個節點的Filebeat日誌上報。我們嘗試把Filebeat改造成多佇列的模式增強隔離性,但是由於Filebeat本身的設計架構侷限,重構的效果和執行狀態都不理想,同時與開源版本的維護和升級存在很大困難。

Filebeat只支援單個Output,當用戶需要把日誌傳送到多個Kafka叢集時,只能在同一個節點上部署多個Filebeat。導致運維成本高、計算資源消耗大、水平擴充套件困難。

Filebeat設計之初是為了解決Logstash的問題,作為輕量級的日誌採集端執行,不適合作為中轉。Logstash在日誌切分、解析等方面表現出色,但是問題在於效能較弱。雖然Flink效能和表現出色,但我們的很多場景只需要簡單的日誌切分,Flink一般依賴流式處理基礎平臺的支援,同時在交付過程中使用者要額外付出Flink的機器和運維成本,所以我們需要一個更輕量、成本更低的方案。

此外,日誌採集過程的可觀測性和穩定性也很重要。在使用者使用過程中經常會遇到日誌沒有按預期採集、日誌採集延遲、日誌丟失、日誌量增長速度過快磁碟爆滿等問題,Filebeat沒有提供這些完善等監控指標,同時還需要額外部署prometheus exporter。

我們以一個線上問題為例。線上某叢集經常遇到磁碟使用量短時間內暴增到90%以上並觸發報警的情況。實際登入節點排查問題後,發現報警的原因在於下游Kafka吞吐量不夠,一些日誌檔案沒有完全採集完畢,Filebeat程序預設保留檔案控制代碼直到檔案採集完畢,由於檔案控制代碼沒有釋放,底層的檔案無法被真正刪除。但在這種情況下,Filebeat缺乏輸入延遲、傳送延遲和堆積情況等指標,影響穩定性。

在一個大流量的節點,我們發現Filebeat傳送資料到下游Kafka時整體資料處理速度不理想,於是進行了很多優化的嘗試,比如換SSD的Kafka叢集、改Kafka配置、優化Filebeat配置等調優。我們發現在Filebeat不開啟資料壓縮的情況下,最大資料傳送速度達到80MB/s後很難再有提升,開啟資料壓縮後Filebeat的CPU的消耗又暴增。調整Kafka或Filebeat引數、機器等配置的優化效果不明顯。

那麼除了Filebeat外,其他的日誌採集工具能不能滿足需求?當前主流的日誌採集Agent對容器化場景下的日誌採集支援不太理想,大部分開源日誌採集工具僅支援到容器標準輸出的採集,對雲原生下日誌採集也沒有整體解決方案。

03 新的征程 開源Loggie的現在和未來

基於Filebeat和現有主流資料採集工具的情況,我們決定自研日誌採集Agent——Loggie。它是基於Golang的輕量級、⾼效能、雲原⽣⽇志採集、聚合Agent,⽀持多Pipeline和元件熱插拔,整體架構如圖。

我們加強了Agent的監控和穩定性,可以利用Monitor EventBus上報Agent執行情況,同時暴露了可呼叫的Restful API和Prometheus拉取監控資料的介面。配置管理方面,目前使用K8S進行配置下發和管理,後續會接入更多配置中心供使用者管理配置。

Loggie提供了一棧式日誌解決方案,新Agent不再分開維護Agent和中轉機。作為一個可插拔元件,Agent既可以作為日誌採集端使用,也可以作為中轉機使用,同時支援日誌中轉、過濾、解析、切分、⽇志報警。Loggie同時提供了雲原生日誌採集完整解決方案,比如通過CRD的形式利用K8s的能力下發配置、部署等。基於我們長期的大規模運維日誌收集服務的經驗,Loggie沉澱了全⽅位的可觀測性、快速排障、異常預警、⾃動化運維能⼒的功能。Loggie基於Golang開發,效能非常好,它資源佔⽤小、吞吐效能優異、開發效率高維護成本低。

1. ⼀棧式⽇志解決⽅案

Agent既可以作為日誌採集客戶端,也可以作為中轉機使用。在日誌中轉方面,我們通過實現Interceptor模組邏輯實現日誌的分流、聚合、轉存、解析、切分等。通過K8s的CRD可以下發日誌採集Agent配置。新的日誌採集架構整體維護成本更低。

在採用Loggie之前我們有兩種報警方案:第一種是基於ElastAlert輪詢Elasticsearch進行日誌報警,該方案存在配置下發需要手動配置、告警接入不能自動化和高可用不完善等問題;第二種是基於Flink解析關鍵字或是對日誌進行正則匹配進行報警,在前面我們已經介紹過,對於整體日誌採集服務而言Flink是比較重量級的。

在採用Loggie後,我們可以使用logAlert Interceptor,在日誌採集過程中就可以通過關鍵字匹配識別info或error進行報警。也可以通過單獨部署Elasticsearch Source的Loggie Aggregator對Elasticsearch進行輪詢,把資訊傳送到Prometheus進行報警。新版日誌報警架構更輕量,維護起來也更簡單。

在專案開發方面,我們秉承微核心、外掛化、元件化的原則,把所有元件抽象為component。開發者通過實現生命週期介面,可以快速開發資料傳送端邏輯、資料來源讀取邏輯、處理邏輯和服務註冊邏輯。這樣的設計讓需求能更快更靈活地實現,大大了日誌採集側的開發效率。

基於靈活高效的Agent資料來源設計,我們可以配置kubeEvent source採集K8S Event資料作為監控報警的補充。相比重新實現一個採集K8S Event專案,只需要在Loggie上實現對應的source,其他如佇列快取、解析日誌、傳送日誌的邏輯都可以複用。

2. 雲原⽣的⽇志形態

 

使用者通過配置LogConfig CRD,可以指定採集Pod、節點、叢集日誌資訊。圖中的例子是通過labelSelector匹配要採集的Pod,並配置容器內日誌路徑;通過Sink CRD和Interceptor CRD可以配置日誌傳送和日誌處理、解析方式。

通過CRD的方式打通日誌處理鏈路,使用者可以通過配置CRD定義日誌中轉、聚合和傳送的方案,可以配置日誌的解析、限流、報警規則,在進行私有化部署和將日誌服務平臺化時大大降低了配置管理的複雜度,一旦有配置變更,k8s可以快速地把配置同步到日誌採集服務中。

在k8s中我們提供了多種部署方案, 作為Agent部署時,我們提供了DaemonSet或SideCar方式進行部署。作為中轉節點部署時可以作為StatefulSet部署。日誌採集的架構上更加靈活,可以直接傳送到ES,也可以傳送給Kafka再交給中轉節點,部署方便。

3. ⽣產級特性

我們為日誌採集Agent添加了完善的指標,包括日誌採集進度、長期採集未完成、採集傳送延遲、FD數量、輸出QPS和其他服務級別指標,提供了原生Prometheus格式的介面、RestAPI和指標傳送Kafka等方式暴露指標。

日誌採集服務大規模部署的穩定性和排障兩方面有很大提升。我們通過獨立各個採集任務Pipeline增強服務隔離性,還可以通過Interceptor提供了QPS限制,定時清理日誌防止磁碟寫滿,增加了日誌檔案突發增長檢測和合理的Fd保留機制等。

4. 資源與效能

 

我們利用Filebeat進行了基準測試,在處理單⾏、單⽂件、相同傳送併發度、⽆解析的場景下,傳送日誌⾄Kafka。

測試結果上看Loggie效能大幅度提升,消耗CPU為Filebeat的1/4、吞吐量為Filebeat的1.6-2.6倍,且極限吞吐量與Filebeat的80MB/s瓶頸提升到200MB/s以上。

04 Loggie開源計劃

Loggie已經開源,下面是我們專案推進的RoadMap和正在做的事,歡迎感興趣的開發者一起參與專案。

Loggie專案地址:http://github.com/loggie-io/loggie/

分享嘉賓:傅軼 網易數帆 輕舟日誌平臺負責人、架構師

目前專注網易數帆輕舟雲原生日誌平臺研發,致力於雲原生技術及其生態體系建設和商業化落地,對Kubernetes、Serverless、可觀測性等有較深入研究,具有豐富的雲原生分散式架構設計開發經驗與專案實踐。