9 个技巧,解决 K8s 中的日志输出问题
作者 | 元乙??阿里云存儲服務(wù)技術(shù)專家
導(dǎo)讀:近年來,越來越多的同學(xué)咨詢?nèi)绾螢?Kubernetes 構(gòu)建一個日志系統(tǒng),或者是來求助在此過程中遇到一系列問題如何解決,授人以魚不如授人以漁,于是作者想把這些年積累的經(jīng)驗以文章的形式發(fā)出來,讓看到文章的同學(xué)少走彎路。K8s 日志系列文章內(nèi)容偏向落地實(shí)操以及經(jīng)驗分享,且內(nèi)容會隨著技術(shù)的迭代而不定期更新,本文為該系列文章的第 3 篇。
第一篇:《6 個 K8s 日志系統(tǒng)建設(shè)中的典型問題,你遇到過幾個?》
第二篇:《一文看懂 K8s 日志系統(tǒng)設(shè)計和實(shí)踐》
前言
在上一篇文章《一文看懂 K8s 日志系統(tǒng)設(shè)計和實(shí)踐》中,主要和大家介紹從全局維度考慮如何去構(gòu)建 K8s 中的日志系統(tǒng),本文我們將從實(shí)踐角度出發(fā)來一步步構(gòu)建 K8s 中的日志監(jiān)控體系。
構(gòu)建日志系統(tǒng)的第一步是如何去產(chǎn)生這些日志,而這也往往是最繁雜最困難的一步。
2009 年阿里云春節(jié)上班第一天,在北京一間連暖氣都沒有的辦公室里,一幫工程師一邊口呼白氣,一邊敲出了“飛天”的第一行代碼。“飛天”作為阿里云的核心技術(shù)平臺,其英文名 Apsara——來自吳哥王朝的阿仆薩羅飛天仙女的名字。
阿里云飛天系統(tǒng)的第一行代碼就是為了編寫一個日志系統(tǒng),而現(xiàn)在 apsara logging 的日志庫應(yīng)用在飛天所有的系統(tǒng)中,包括盤古、女媧、伏羲、洛神…
Kubernetes 中日志重要性
通常日志最基礎(chǔ)的作用是記錄程序的運(yùn)行軌跡,在此之上會衍生出非常多的功能,例如線上監(jiān)控、告警、運(yùn)營分析、安全分析等等(詳情可以參見第一篇文章《6 個 K8s 日志系統(tǒng)建設(shè)中的典型問題,你遇到過幾個?》,這些功能反過來也對日志具備一定的要求,我們需要盡可能的將日志規(guī)范化,以減少收集、解析、分析的代價。
在 Kubernetes 中,環(huán)境的動態(tài)性很強(qiáng),日志基本上都是易失的,因此需要實(shí)時將日志采集到中心的存儲中,為了配合日志采集,對于日志的輸出、采集會有更多的要求。
下述我們列舉了 Kubernetes 中,日志輸出的常見注意事項(其中標(biāo)記 (*)的是 Kubernetes 中特有的項目):
如何選擇日志等級
日志等級是用來區(qū)分日志對應(yīng)事件嚴(yán)重程度的說明,這是所有日志中必須具備的一個選項。通常日志會分為 6 個不同的等級:
- FATAL(致命):用來輸出非常嚴(yán)重或預(yù)期中不會發(fā)生的錯誤,遇到此種錯誤應(yīng)當(dāng)立即報警并人工介入處理;
- ERROR (錯誤):非預(yù)期中的錯誤,此種錯誤可能導(dǎo)致部分系統(tǒng)異常但不會影響核心業(yè)務(wù)和系統(tǒng)正常運(yùn)行;
- WARN(警告):潛在的危險或值得關(guān)注的信息(比較核心的路徑);
- INFO(信息):應(yīng)用執(zhí)行過程中的詳細(xì)信息,一般通過該信息可以看到每個請求的主要執(zhí)行過程;
- DEBUG(調(diào)試):用于線下調(diào)試的日志信息,用于分析應(yīng)用執(zhí)行邏輯,線上應(yīng)用切勿開啟;
- TRACE(跟蹤):輸出最細(xì)致的運(yùn)行軌跡,可能包含涉及的數(shù)據(jù)內(nèi)容。
作為程序員,一定要合理設(shè)置日志等級,個人在開發(fā)過程中總結(jié)了以下幾點(diǎn)經(jīng)驗:
日志內(nèi)容規(guī)范
通常在沒有約束的情況下,程序員的發(fā)揮天馬行空,各種日志內(nèi)容都會出現(xiàn),這些只有開發(fā)自己才能看懂的日志很難進(jìn)行分析和告警。因此我們需要一個日志頂向下的規(guī)范來約束項目中的開發(fā)人員,讓所有的日志看起來是一個人打印的而且是易于分析的。
日志的字段
日志中通常必備的字段有:Time、Level、Location。對于特定模塊/流程/業(yè)務(wù),還需要有一些 Common 的字段,例如:
日志的字段規(guī)約最好由運(yùn)維平臺/中間件平臺自頂向下推動,約束每個模塊/流程的程序員按照規(guī)定打印日志。
日志表現(xiàn)形式
通常我們建議使用 KeyValue 對形式的日志格式,比如我們阿里的飛天日志庫采用的就是這種形式:
[2019-12-30 21:45:30.611992] [WARNING] [958] [block_writer.cpp:671] path:pangu://localcluster/index/3/prom/7/1577711464522767696_0_1577711517 min_time:1577712000000000 max_time:1577715600000000 normal_count:27595 config:prom start_line:57315569 end_line:57343195 latency(ms):42 type:AddBlockKeyValue 對的日志可以完全自解析且易于理解,同時便于日志采集時自動解析。
另外推薦的是 JSON 日志格式,支持以 JSON 格式輸出的日志庫很多,而且大部分的日志采集 Agent 都支持 JSON 格式的日志收集。
{"addr":"tcp://0.0.0.0:10010","caller":"main.go:98","err":"listen tcp: address tcp://0.0.0.0:10010: too many colons in address","level":"error","msg":"Failed to listen","ts":"2019-03-08T10:02:47.469421Z"}注意:絕大部分場景不建議使用非可讀的日志格式(例如 ProtoBuf、Binlog 等)。
單條日志換行問題
非必要情況下,盡量不要一條日志輸出成多行,這種對于采集、解析和索引的代價都比較高。
合理控制日志輸出量
日志的輸出量直接影響到磁盤使用以及對于應(yīng)用的性能消耗,日志太多不利于查看、采集、分析;日志太少不利于監(jiān)控,同時在出現(xiàn)問題的時候沒辦法調(diào)查。
一般線上應(yīng)用需合理控制日志的數(shù)據(jù)量:
選擇多種日志輸出目標(biāo)
建議一個應(yīng)用不同類型的日志輸出到不同的目標(biāo)(文件),這樣便于分類采集、查看和監(jiān)控。例如:
控制日志性能消耗
日志作為業(yè)務(wù)系統(tǒng)的輔助模塊,一定不能影響到業(yè)務(wù)正常的工作,因此日志模塊的性能消耗需要單獨(dú)額外注意,一般在選擇/開發(fā)日志庫時,需要對日志庫進(jìn)行性能測試,確保正常情況下日志的性能消耗不超過整體 CPU 占用的 5%。
注意:一定要確保日志打印是異步的,不能阻塞業(yè)務(wù)系統(tǒng)運(yùn)行。
如何選擇日志庫
開源的日志庫非常多,基本每個語言都有數(shù)十種,選擇一個符合公司/業(yè)務(wù)需求的日志庫需要精挑細(xì)選,有一個簡單的指導(dǎo)原則是盡可能使用比較流行的日志庫的穩(wěn)定版本,入坑的幾率要小一點(diǎn)。例如:
日志形態(tài)選擇
在虛擬機(jī)/物理機(jī)的場景中,絕大部分應(yīng)用都以文件的形式輸出日志(只有一些系統(tǒng)應(yīng)用輸出到 syslog/journal);而在容器場景中,多了一個標(biāo)準(zhǔn)輸出的方式,應(yīng)用把日志打到 stdout 或 stderr 上,日志會自動進(jìn)入到 docker 的日志模塊,可以通過 docker logs 或 kubectl logs 直接查看。
容器的標(biāo)準(zhǔn)輸出只適應(yīng)于比較單一的應(yīng)用,例如 K8s 中的一些系統(tǒng)組件,線上的服務(wù)類應(yīng)用通常都會涉及到多個層級(中間件)、和各種服務(wù)交互,一般日志都會分為好幾類,如果全部打印到容器的標(biāo)準(zhǔn)輸出,很難區(qū)分處理。
同時容器標(biāo)準(zhǔn)輸出對于 DockerEngine 的性能消耗特別大,實(shí)測 10W/s 的日志量會額外占用 DockerEngine 1 個核心的 CPU(單核 100%)。
日志是否落盤以及落盤介質(zhì)
在 Kubernetes 中,還可以將日志庫直接對接日志系統(tǒng),日志打印的時候不落盤而直接傳輸?shù)饺罩鞠到y(tǒng)后端。這種使用方式免去了日志落盤、Agent 采集的過程,整體性能會高很多。
這種方式我們一般只建議日志量極大的場景使用,普通情況下還是直接落盤,相比直接發(fā)送到后端的方式,落盤增加了一層文件緩存,在網(wǎng)絡(luò)失敗的情況下還能緩存一定的數(shù)據(jù),在日志系統(tǒng)不可用的情況下我們的研發(fā)運(yùn)維同學(xué)可以直接查看文件的日志,提高整體的可靠性。
Kubernetes 提供了多種存儲方式,一般在云上,都會提供本地存儲、遠(yuǎn)程文件存儲、對象存儲等方式。由于日志寫入的 QPS 很高,和應(yīng)用也直接相關(guān),如果使用遠(yuǎn)程類型的存儲,會額外多 2-3 次網(wǎng)絡(luò)通信開銷。我們一般建議使用本地存儲的方式,可以使用 HostVolume 或者 EmptyDir 的方式,這樣對于寫入和采集的性能影響會盡可能的小。
如何保證日志存儲周期
相比傳統(tǒng)虛擬機(jī)/物理機(jī)的場景,Kubernetes 對于節(jié)點(diǎn)、應(yīng)用層提供了強(qiáng)大的調(diào)度、容錯、縮/擴(kuò)容能力,我們通過 Kubernetes 很容易就能讓應(yīng)用獲得高可靠運(yùn)行、極致彈性。這些優(yōu)勢帶來的一個現(xiàn)象是:節(jié)點(diǎn)動態(tài)創(chuàng)建/刪除、容器動態(tài)創(chuàng)建/刪除,這樣日志也會隨時銷毀,沒辦法保證日志的存儲周期能夠滿足 DevOps、審計等相關(guān)的需求。
在動態(tài)的環(huán)境下實(shí)現(xiàn)日志的長期存儲只能通過中心化的日志存儲來實(shí)現(xiàn),通過實(shí)時的日志采集方式,將各個節(jié)點(diǎn)、各個容器的日志在秒級內(nèi)采集到日志中心系統(tǒng)上,即使節(jié)點(diǎn)/容器掛掉也能夠通過日志還原當(dāng)時的現(xiàn)場。
總結(jié)
日志輸出是日志系統(tǒng)建設(shè)中非常重要的環(huán)節(jié),公司/產(chǎn)品線一定要遵循一個統(tǒng)一的日志規(guī)范,這樣才能保證后續(xù)日志采集、分析、監(jiān)控、可視化能夠順利進(jìn)行。
后面的章節(jié)會介紹如何為 Kubernetes 規(guī)劃日志采集和存儲的最佳實(shí)踐,敬請期待。
“阿里巴巴云原生關(guān)注微服務(wù)、Serverless、容器、Service Mesh 等技術(shù)領(lǐng)域、聚焦云原生流行技術(shù)趨勢、云原生大規(guī)模的落地實(shí)踐,做最懂云原生開發(fā)者的技術(shù)圈。”
總結(jié)
以上是生活随笔為你收集整理的9 个技巧,解决 K8s 中的日志输出问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从零开始入门 K8s | Kuberne
- 下一篇: 函数计算支持 MySQL 实例绑定