百度工程師淺談分布式日志
1、什么是日志
日志是一種按照時間順序存儲記錄的數據,它記錄了什么時間發生了什么事情,提供精確的系統記錄,根據日志信息可以定位到錯誤詳情和根源。按照APM概念的定義,日志的特點是描述一些離散的(不連續的)事件。
日志是按照錯誤級別分級的,常見的錯誤級別有 FATAL / WARNING / NOTICE / DEBUG / TRACE 5種類型。通常我們會在項目里面定義一個日志打印級別,高于這個級別的錯誤日志會數據落盤。
2、什么時候記錄日志
在大型網站系統架構里面,日志是其中的重要功能組成部分。它可以記錄下系統所產生的所有行為,并按照某種規范表達出來。我們可以使用日志系統所記錄的信息為系統進行排錯,優化性能。通過統計用戶行為日志,幫助產品運營同學做業務決策。在安全領域,日志可以反應出很多的安全攻擊行為,比如登錄錯誤,異常訪問等。日志能告訴你很多關于網絡中所發生事件的信息,包括性能信息、故障檢測和入侵檢測。還可以為審計進行審計跟蹤,日志的價值是顯而易見的。
3、日志的價值
在大型網站系統架構里面,日志是其中的重要功能組成部分。它可以記錄下系統所產生的所有行為,并按照某種規范表達出來。我們可以使用日志系統所記錄的信息為系統進行排錯,優化性能。通過統計用戶行為日志,幫助產品運營同學做業務決策。在安全領域,日志可以反應出很多的安全攻擊行為,比如登錄錯誤,異常訪問等。日志能告訴你很多關于網絡中所發生事件的信息,包括性能信息、故障檢測和入侵檢測。還可以為審計進行審計跟蹤,日志的價值是顯而易見的。
4、分布式架構的日志運維
4.1 為什么要有運維工具
微服務發展迅猛的今天,松耦合的設計層出不窮,為簡化服務服務帶來了極大的便利。業務方向分工明確,研發同學只需要關心自己模塊的版本迭代上線就好。隨著整個業務架構的擴大,服務實例的數量迎來了爆炸性的增長,往往帶來以下問題:
- 由不同團隊開發,使用不同的編程語言,日志格式不規范統一;
- 微服務迭代速度快,日志漏記、級別使用錯誤、難以提取有效信息;
- 容器實例分布在成千上萬臺服務器上,橫跨多個數據中心,異構部署,難以串聯請求鏈路。
沒有工具的情況下,需要登錄服務實例,查看原始日志,在日志文件中通過grep、awk方式獲得自己想要的信息。但在規模較大的場景中,此方法效率低下,面臨問題包括日志量太大不易歸檔、文本搜索太慢、不方便多維度查詢。這時候需要更加高效的運維工具來代替人工訪問日志。常見解決思路是建立集中式日志收集系統,將所有節點上的日志統一收集,管理,訪問。
4.2 運維工具建設
我們希望通過原始日志可以理解系統行為,這需要建設具備性能分析,問題定位的能力的工具平臺。它能夠支持:
- 在故障發生前,分析風險和系統瓶頸;
- 在故障發生時,及時通知,快速定位解決問題;
- 在故障發生后,有歷史數據迅速復盤。
通過建設具備日志即時收集、分析、存儲等能力的工具平臺。用戶可以快速高效地進行問題診斷、系統運維、流量穩定性監控、業務數據分析等操作。比如搭建鏈路追蹤系統,能追蹤并記錄請求在系統中的調用順序,調用時間等一系列關鍵信息,從而幫助我們定位異常服務和發現性能瓶頸,提升了系統的『可觀測性』。前面提到日志在APM標準的定義下日志的特點是描述一些離散的(不連續的)事件。這里說下APM是什么,方便更好的構建監控方面的知識體系。
5、APM和可觀測性
APM 是Application Performance Managment的縮寫,即:“應用性能管理”。可以把它理解成一種對分布式架構進行觀測分析優化的理念和方法論。監控系統(包括告警)作為SLA體系的一個重要組成部分,不僅在業務和系統中充當保鏢發現問題、排查問題的作用。
隨著系統不斷演進完善,我們可以獲得越多幫助于了解業務和系統的數據和信息,這些信息可以更進一步的幫助我們進行系統上的優化,由于可以梳理請求鏈路得出用戶的瀏覽偏好,甚至可以影響業務上的關鍵決策。
整體來說,整個APM體系就是將大三類數據(logs、metrics、trace)應用到四大模塊中(收集、加工、存儲、展示),并在四個難點(程序異構,組件多樣,鏈路完整,時效采樣)上不斷優化。
可觀測性 是APM的一大特征,主要由以下三大支柱構成,分別是Logging(日志),Metrics(指標),以及Tracing(應用跟蹤)。
- Logging:自動埋點/手動埋點,展現的是應用運行而產生的事件或者程序在執行的過程中間產生的一些日志,可以詳細解釋系統的運行狀態,但是存儲和查詢需要消耗大量的資源。
- Metrics:服務、端點、實例的各項指標,是一種聚合數值,存儲空間很小,可以觀察系統的狀態和趨勢,對于問題定位缺乏細節展示,最節省存儲資源。
- Tracing:同一TraceId的調用序列,面向的是請求,可以輕松分析出請求中異常點,資源可能消耗較大,不過依據具體功能實現相對可控。
5.1 Metrics和Prometheus
Metrics:指標。
I think that the defining characteristic of metrics is that they are aggregatable: they are the atoms that compose into a single logical gauge, counter, or histogram over a span of time.
大致上可理解為一些可進行聚合計算的原子型數據。舉些例子:cpu占用情況、系統內存占用、接口響應時間、接口響應QPS、服務gc次數、訂單量等。這些都是根據時間序列存儲的數據值,可以在一段時間內進行一些求和、求平均、百分位等聚合計算。指標在監控系統中不可或缺,我們都需要收集每種指標在時間線上的變化,并作同比、環比上的分析。metrics的存儲形式為有時間戳標記的數據流,通常存儲在TSDB(時間序列數據庫)中。
Metrics側重于各種報表數據的收集和展示,常用在大規模業務的可用性建設、性能優化、容量管理等場景,通過可視化儀表盤可高效地進行日常系統巡檢、快速查看應用健康狀況,可以精準感知可用性和性能問題,為產品的穩定運行保駕護航。
Prometheus 是一個開源的監控解決方案,它能夠提供監控指標數據的采集、存儲、查詢以及監控告警等功能。作為云原生基金會(CNCF)的畢業項目,Prometheus 已經在云原生領域得到了大范圍的應用,并逐漸成為了業界最流行的監控解決方案之一。
下圖為Prometheus的工作流程,可以簡單理解為:Prometheus server定期拉取目標實例的采集數據,時間序列存儲,一方面通過配置報警規則,把觸發的報警發送給接收方,一方面通過組件Grafana把數據以圖形化形式展示給用戶。
5.2 Logging和ELK
Logging:日志。
I think that the defining characteristic of logging is that it deals with discrete events.
日志是系統運行時發生的一個個事件的記錄。Logging的典型特征就是它和孤立的事件(Event)強關聯,一個事件的產生所以導致了一條日志的產生。舉個例子就是一個網絡請求是一個事件,它被云端接到后Nginx產生了一個訪問log。大量的不同外部事件間基本是離散的,比如多個用戶訪問云端業務時產生的5個事件間沒有必然的關系,所以在一個服務節點的角度上看這些事件產生的日志間也是離散的。
關于日志管理平臺,相信很多同學聽說過最多的就是ELK(elastic stack),ELK是三款軟件的簡稱,分別是Elasticsearch、 Logstash、Kibana組成。在APM體系中,它可以實現關鍵字的分布式搜索和日志分析,能夠快速定位到我們想要的日志,通過可視化平臺的展示,能夠從多個維度來對日志進行細化跟蹤。
?Elasticsearch基于java,是個開源分布式搜索引擎,它提供了一個分布式多用戶能力的全文搜索引擎,基于RESTful web接口。是當前流行的企業級搜索引擎。設計用于云計算中,能夠達到實時搜索,穩定,可靠,快速,安裝使用方便。它的特點有:分布式,零配置,自動發現,索引自動分片,索引副本機制,restful風格接口,多數據源,自動搜索負載等。
Kibana基于nodejs,是一款開源的數據分析和可視化平臺,它是Elastic Stack成員之一,設計用于和Elasticsearch協作。您可以使用Kibana對Elasticsearch索引中的數據進行搜索、查看、交互操作。您可以很方便的利用圖表、表格及地圖對數據進行多元化的分析和呈現。
Logstash基于java,是一個開源的用于收集,分析和存儲日志的工具,能夠同時從多個來源采集數據,轉換數據,然后將數據發送到最喜歡的存儲庫中(我們的存儲庫當然是ElasticSearch)。?
下面是ELK的工作原理:
ELK中的L理解成Logging Agent比較合適。Elasticsearch和Kibana是存儲、檢索和分析log的標準方案。在高負載的ELK平臺迭代實踐中,常常采用一些優化策略。比如:ElasticSearch 做冷熱數據分離,歷史索引數據關閉;Filebeat更加輕量,對資源消耗更少,替代Logstash作為數據收集引擎;增加消息隊列做數據緩沖,通過解耦處理過程實現削峰平谷,幫助平臺頂住突發的訪問壓力。
ELK的缺點也是明顯的,部署這樣一套日志分析系統,不論是存儲還是分析所需要占用的機器成本是挺大的。業務日志是時時打印的,大規模的在線服務一天日志量可能達到TB級別,如果采用ELK平臺,在保證關鍵日志信息入庫的同時,有針對性的對所需日志文件進行采集和過濾是必不可少的。
5.3 Tracing、OpenTracing和Apache SkyWalking
.Tracing:鏈路。
I think that the single defining characteristic of tracing , then, is that it deals with information that is request-scoped.
鏈路可理解為某個最外層請求下的所有調用信息。在微服務中一般有多個調用信息,如從最外層的網關開始,A服務調用B服務,調用數據庫、緩存等。在鏈路系統中,需要清楚展現某條調用鏈中從主調方到被調方內部所有的調用信息。這不僅有利于梳理接口及服務間調用的關系,還有助于排查慢請求產生的原因或異常發生的原因。
Tracing最早提出是來自Google的論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》,它讓Tracing流行起來。而Twitter基于這篇論文開發了Zipkin并開源了這個項目。再之后業界百花齊放,誕生了一大批開源和商業Tracing系統。
Tracing 以請求的維度,串聯服務間的調用關系并記錄調用耗時,即保留了必要的信息,又將分散的日志事件通過Span層串聯, 幫助我們更好的理解系統的行為、輔助調試和排查性能問題。它的基本概念如下兩點:
- Trace(調用鏈):OpenTracing中的Trace(調用鏈)通過歸屬于此調用鏈的Span來隱性的定義。一條Trace(調用鏈)可以被認為是一個由多個Span組成的有向無環圖(DAG圖),可以簡單理解成一次事務;
- Span(跨度):可以被翻譯為跨度,可以被理解為一次方法調用,一個程序塊的調用,或者一次RPC/數據庫訪問,只要是一個具有完整時間周期的程序訪問,都可以被認為是一個Span。
對于一個組件來說,一次處理過程產生一個 Span,這個 Span 的生命周期是從接收到請求到返回響應這段過程,在單個Trace中,存在多個Span。
舉個例子,比如一個請求用戶訂單信息的接口,流量分發到了應用層實例(Span A)來處理請求,應用層實例(Span A)需要請求訂單中心服務實例(Span B)來獲取訂單數據,同時請求用戶中心服務實例(Span C)來獲取用戶數據。基礎服務B、C可能還有其他依賴服務鏈路,則如下圖所示結構,Span間的因果關系如下:
OpenTracing是一個中立的(廠商無關、平臺無關)分布式追蹤的API 規范,提供統一接口,可方便開發者在自己的服務中集成一種或多種分布式追蹤的實現。由于近年來各種鏈路監控產品層出不窮,當前市面上主流的工具既有像Datadog這樣的一攬子商業監控方案,也有AWS X-Ray和Google Stackdriver Trace這樣的云廠商產品,還有像Zipkin、Jaeger這樣的開源產品。
云原生基金會(CNCF) 推出了OpenTracing標準,推進Tracing協議和工具的標準化,統一Trace數據結構和格式。OpenTracing通過提供平臺無關、廠商無關的API,使得開發人員能夠方便添加(或更換)追蹤系統的實現。比如從Zipkin替換成Jaeger/Skywalking等后端。
在眾多Tracing產品中,值得一提的是國人自研開源的產品Skywalking。它是一款優秀的APM工具,專為微服務、云原生架構和基于容器架構而設計,支持Java、.Net、NodeJs等探針方式接入項目,數據存儲支持Mysql、Elasticsearch等。功能包括了分布式鏈路追蹤,性能指標分析和服務依賴分析等。2017年加入Apache孵化器,2019年4月17日Apache董事會批準SkyWalking成為頂級項目,目前百度廠內有一些業務線采用skywalking作為主要的日志運維平臺。
5.4 Metrics,Logging和 Tracing 結合
指標、日志、鏈路在監控中是相輔相成的。現在再來看上圖中,兩兩相交的部分:
- 通過指標和日志維度,我們可以做一些事件的聚合統計,例如,繪制流量趨勢圖,某應用每分鐘的錯誤日志數
- 通過鏈路和日志系統,我們可以得到某個請求詳細的請求信息,例如請求的入參、出參、鏈路中途方法打印出的日志信息;
- 通過指標和鏈路系統,我們可以查到請求調用信息,例如 SQL執行總時長、各依賴服務調用總次數;
可見,通過這三種類型數據相互作用,可以得到很多在某種類型數據中無法呈現的信息。例如下圖是一個故障排查的示例,首先,我們從消息通知中發現告警,進入metrics指標面板,定位到有問題的數據圖表,再通過指標系統查詢到詳細的數據,在logging日志系統查詢到對應的錯誤,通過tracing鏈路追蹤系統查看鏈路中的位置和問題(當然也可以先用鏈路追蹤系統進行故障的定位,再查詢詳細日志),最后修復故障。這是一個典型的將三個系統串聯起來應用的示例。
6、文庫在日志運維上的實踐
6.1 匯聚監控
文庫App對于域名、中間件、依賴服務等流量穩定性,機器資源的監控,基于廠內現有的解決方案(Bns+Argus監控系統+Sia可視化平臺)實現。工作流程可以理解為:
- 在日志采集平臺(Argus)配置數據采集規則,異常判斷規則和報警配置規則;
- 通過服務實例映射配置(Bns)獲取到要采集日志的實例列表,實例服務的log format要符合采集規則的正則表達式;
- Agent上報日志分析數據給MQ消化,MQ存入TSDB;
- 日志匯聚后的分析計算結果符合異常判斷規則,則觸發對應配置的報警規則;
- 報警規則可以配置多維度分級分時間和不同方式提醒到接收人。同時,通過配置群聊機器人對包括資源,接入層,運行層,服務及底層依賴的等服務,依據閥值進行基本實時的監控報警;
- 可視化平臺(Sia)通過 metric 配置從 TSDB 中讀出相應數據,進行圖形化展示。
6.2 批量查詢
即時日志撈取工具在我們業務開發中也是比較常見的,通常通過批量并發執行遠程服務器指令來實現,解決依次執行的繁鎖,讓運維操作更安全便捷。
這種工具不依賴agent,只通過ssh就可以工作,一般通過中控機或者賬戶密碼等方式做ssh訪問控制,執行grep,tail等命令獲取日志,然后對logs進行分析,可以解決日常中很多的需求。簡化代碼如下。
把如上代碼部署在中控機上ssh免密登錄,通過go run batch.go或執行go build后的二進制文件,可以實現批量查詢日志的基礎能力。在此基礎上增加傳參,可以實現指定集群實例,指定exec命令,并發度控制,優化輸出等功能。
6.3 鏈路跟蹤
文庫自研的全鏈路日志跟蹤平臺,支持trace全鏈路日志跟蹤,指標匯聚,關鍵信息高亮,搜索范圍覆蓋nginx,nodejs,php,go等異構微服務,還支持動態繪制調用鏈路圖。用戶可以通過查詢tracid的方式獲得一個請求鏈路的http分析,調用服務的次數匯聚,日志list和拓撲鏈路圖。
透傳trace的底層流程是在接入層nginx擴展生成的一個20 -26位長、編碼了nginx所在機器ip和請求時間的純數字字符串。這個字符串在請求日志、服務運行日志、rpc日志中記錄,通過Http Header向下透傳,在服務間調用過程中,在當前層記錄調用的下一層實例ip:port信息,保證trace參數維持。
綠色的節點為鏈路調用的起始節點,一般是文庫接入層。鼠標hover到哪個節點會title展示詳情,并在整個鏈路中隱去與之不相關的節點鏈路。如果節點有fatal,warning的日志,節點背景色會以紅色,黃色展示。
7、日志的壞味道
- 信息不明確。后果:執行效率降低;
- 格式不規范。后果:不可讀,無法采集;
- 日志過少,缺乏關鍵信息。后果:降低定位問題效率;
- 參雜了臨時、冗余、無意義的日志。后果:生產打印大量日志消耗性能;
- 日志錯誤級別使用混亂。后果:導致監控誤報;
- 使用字符串拼接方式,而非占位符。后果:可維護性較低;
- 代碼循環體打非必要的日志。后果:有宕機風險;
- 敏感數據未脫敏。后果:有隱私信息泄露風險;
- 日志文件未按小時分割轉儲。后果:不易磁盤空間回收;
- 服務調用間沒有全局透傳trace信息。后果:不能構建全鏈路日志跟蹤。
8、日志 good case
- 能快速的定位問題;
- 能提取有效信息,了解原因;
- 了解線上系統的運行狀態;
- 匯聚日志關鍵信息,可以發現系統的瓶頸;
- 日志隨著項目迭代,同步迭代;
- 日志的打印和采集、上報服務,不能影響系統的正常運行。
9、結語
在萬物上云的時代,通過搭建合適的日志運維平臺來賦予數據搜索、分析和監控預警的能力,讓沉寂在服務器的日志"動"起來,可以幫助我們在數據分析,問題診斷,系統改進的工作中更加順利的進行,希望本文的內容對大家的實踐有所幫助。