
鏡像下載下傳、域名解析、時間同步請點選
阿裡巴巴開源鏡像站作者:元乙
一、Kubernetes 日志等級選擇
日志等級是用來區分日志對應事件嚴重程度的說明,這是所有日志中必須具備的一個選項。通常日志會分為6個不同的等級:
- FATAL(緻命):用來輸出非常嚴重或預期中不會發生的錯誤,遇到此種錯誤應當立即報警并人工介入處理。
- ERROR (錯誤):非預期中的錯誤,此種錯誤可能導緻部分系統異常但不會影響核心業務和系統正常運作。
- WARN(警告):潛在的危險或值得關注的資訊(比較核心的路徑)。
- INFO(資訊):應用執行過程中的詳細資訊,一般通過該資訊可以看到每個請求的主要執行過程。
- DEBUG(調試):用于線下調試的日志資訊,用于分析應用執行邏輯,線上應用切勿開啟。
- TRACE(跟蹤):輸出最細緻的運作軌迹,可能包含涉及的資料内容。
作為程式員,一定要合理設定日志等級,個人在開發過程中總結以下幾點經驗:
- FATAL類型日志一定是非常嚴重的錯誤、需要人工處理的場景列印的。
- ERROR和WARNING的差別很多程式員難以選擇,可以從告警角度考慮:ERROR一般需要告警,WARNING不需要。
- 日志等級一方面是為了能夠表示日志的嚴重程度,另一方面也是為了控制應用程式的日志輸出量,通常線上隻能打開INFO或WARN的日志。
- DEBUG日志可以多打,友善分析問題。
- 所有使用者請求日志,必須記錄。
- 對于不确定的外部系統調用,日志需盡可能覆寫周全。
- 程式中的日志庫需要具備運作期間變更日志等級的能力,友善在遇到問題需要分析時臨時更改日志等級。
- 通常在新功能上線,涉及的日志可适當提升一個等級,友善實時觀察和監控,待穩定後再調整到正常(記得加上注釋,友善改回來)。
二、日志内容規範
通常在沒有限制的情況下,程式員的發揮天馬行空,各種日志内容都會出現,這些隻有開發自己才能看懂的日志很難進行分析和告警。是以我們需要一個日志頂向下的規範來限制項目中的開發人員,讓所有的日志看起來是一個人列印的而且是易于分析的。
2.1 日志的字段
日志中通常必備的字段有:Time、Level、Location。對于特定子產品/流程/業務,還需要有一些Common的字段,例如:
- 如果使用Trace系統,可以把TraceID附加到日志中。
- 固定的流程需要附加對應的字段,例如訂單的生命周期中,一定要有訂單号、使用者ID等資訊,這些資訊可以通過Context附加到對應流程的日志執行個體上。
- HTTP請求需要記錄:URL、Method、Status、Latency、Inflow、OutFlow、ClientIP、UserAgent等,詳情可以參考 Nginx日志格式 。
- 如果多個子產品的日志都列印到同一個流/檔案中,必須有字段辨別子產品名。
日志的字段規約最好由運維平台/中間件平台自頂向下推動,限制每個子產品/流程的程式員按照規定列印日志。
2.2 日志表現形式
通常我們建議使用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:AddBlock
KeyValue對的日志可以完全自解析且易于了解,同時便于日志采集時自動解析。
另外推薦的是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"}
2.3 單條日志換行問題
非必要情況下,盡量不要一條日志輸出成多行,這種對于采集、解析和索引的代價都比較高。
三、日志輸出
3.1 合理控制日志輸出量
日志的輸出量直接影響到磁盤使用以及對于應用的性能消耗,日志太多也不利于檢視、采集、分析;日志太少不利于監控,同時在出現問題的時候沒辦法調查。一般線上應用需合理控制日志的資料量:
- 服務入口的請求和響應日志沒有特殊原因都要輸出并采集,采集的字段可以根據需求調整。
- 錯誤日志一般都要列印,如果太多,可以使用采樣方式列印。
- 減少無效日志輸出,尤其是循環中列印日志的情況需盡量減少。
- 請求型的日志(比如Ingress、Nginx通路日志)一般不超過5MB/s(500位元組每條,不超過1W/s),應用程式日志不超過200KB/s(2KB每條,不超過100條/s)。
3.2 選擇多種日志輸出目标
建議一個應用不同類型的日志輸出到不同的目标(檔案),這樣便于分類采集、檢視和監控。例如:
- 通路日志單獨放到一個檔案,如果域名不多,可以按照一個域名一個檔案的形式。
- 錯誤類的日志單獨放一個檔案,單獨配置監控告警。
- 調用外部系統的日志單獨放一個檔案,便于後續對賬、審計。
- 中間件通常都由統一的平台提供,日志一般單獨列印一個檔案。
3.3 控制日志性能消耗
日志作為業務系統的輔助子產品,一定不能影響到業務正常的工作,是以日志子產品的性能消耗需要單獨額外注意,一般在選擇/開發日志庫時,需要對日志庫進行性能測試,確定正常情況下日志的性能消耗不超過整體CPU占用的5%。
- 注意:一定要確定日志列印是異步的,不能阻塞業務系統運作。
3.4 如何選擇日志庫
開源的日志庫非常多,基本每個語言都有數十種,選擇一個符合公司/業務需求的日志庫需要精挑細選,有一個簡單的指導原則是盡可能使用比較流行的日志庫的穩定版本,入坑的幾率要小一點。例如:
- Java 使用 Log4J、LogBack。
- Golang 使用 go-kit
- Python預設內建的日志庫大部分場景都夠用,建議閱讀一下 CookBook
- C++ 推薦使用 spdlog ,高性能、跨平台。
3.5 日志形态選擇
在虛拟機/實體機的場景中,絕大部分應用都以檔案的形式輸出日志(隻有一些系統應用輸出到syslog/journal);而在容器場景中,多了一個标準輸出的方式,應用把日志打到stdout或stderr上,日志會自動進入到docker的日志子產品,可以通過 docker logs 或 kubectl logs 直接檢視。
容器的标準輸出隻适應于比較單一的應用,例如K8s中的一些系統元件,線上的服務類應用通常都會涉及到多個層級(中間件)、和各種服務互動,一般日志都會分為好幾類,如果全部列印到容器的标準輸出,很難區分處理。
同時容器标準輸出對于DockerEngine的性能消耗特别大,實測10W/s的日志量會額外占用DockerEngine 1個核心的CPU(單核100%)。
3.6 日志是否落盤以及落盤媒體
在Kubernetes中,還可以将日志庫直接對接日志系統,日志列印的時候不落盤而直接傳輸到日志系統後端。這種使用方式免去了日志落盤、Agent采集的過程,整體性能會高很多。這種方式我們一般隻建議日志量極大的場景使用,普通情況下還是直接落盤,相比直接發送到後端的方式,落盤增加了一層檔案緩存,在網絡失敗的情況下還能緩存一定的資料,在日志系統不可用的情況下我們的研發運維同學可以直接檢視檔案的日志,提高整體的可靠性。
Kubernetes提供了多種存儲方式,一般在雲上,都會提供本地存儲、遠端檔案存儲、對象存儲等方式。由于日志寫入的QPS很高,和應用也直接相關,如果使用遠端類型的存儲,會額外多2-3次網絡通信開銷。我們一般建議使用本地存儲的方式,可以使用HostVolume或者EmptyDir的方式,這樣對于寫入和采集的性能影響會盡可能的小。
3.7 如何保證日志存儲周期
相比傳統虛拟機/實體機的場景,Kubernetes對于節點、應用層提供了強大的排程、容錯、縮/擴容能力,我們通過Kubernetes很容易就能讓應用獲得高可靠運作、極緻彈性。這些優勢帶來的一個現象是:節點動态建立/删除、容器動态建立/删除,這樣日志也會随時銷毀,沒辦法保證日志的存儲周期能夠滿足DevOps、審計等相關的需求。
在動态的環境下實作日志的長期存儲隻能通過中心化的日志存儲來實作,通過實時的日志采集方式,将各個節點、各個容器的日志在秒級内采集到日志中心系統上,即使節點/容器挂掉也能夠通過日志還原當時的現場。
四、總結
日志輸出是日志系統建設中非常重要的環節,公司/産品線一定要遵循一個統一的日志規範,這樣才能保證後續日志采集、分析、監控、可視化能夠順利進行。
“ 提供全面,高效和穩定的系統鏡像、應用軟體下載下傳、域名解析和時間同步服務。”