雲原生日誌架構實踐:網易數帆開源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項目地址:https://github.com/loggie-io/loggie/

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

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