B站日誌分析系統大法——基於elastic stack,面向全站提供統一的日誌採集、檢索、監控服務

B站的日誌系統(Billions)從2017年5月份開始建設,基於elastic stack,面向全站提供統一的日誌採集、檢索、監控服務。目前集群規模20台機器,接入業務200+,單日日誌量10T+。

藉此機會跟大家分享一些B站在日誌系統的建設、演進以及優化的經歷。由於經驗尚少,拋磚引玉,歡迎大家一起交流討論。文章主要分為三個部分:原有日誌系統,現有系統演進,未來的展望。

原有日誌系統

在Billions之前,B站內部並沒有統一的日誌平台,基本是業務之間各自為戰,既有基於ELK的比較前瞻的方式,又有伺服器上使用tail/grep比較基本原始的方式,水平參差不齊。在了解各個產品線的情況後,存在的問題和訴求主要有以下幾點:

1、方案各異。 由於各個部門自行實現日誌方案,沒有專人維護,普遍存在維護成本高、系統不穩定、丟日誌、易用性不足的情況。

2、業務日誌沒有統一的規範。業務日誌格式各式各樣,導致最直接的問題就是無法按照統一的規則對日誌進行切分,這無疑大大的增加了日誌的分析、檢索成本。

3、對PAAS支持不好。公司內部正在大面積推廣應用容器化,但是並沒有一個好的日誌方案支撐容器內應用日誌的採集。

4、日誌利用程度低。對於日誌的利用程度普遍停留於日誌檢索的水平,受限於工具未對日誌的價值進行進一步挖掘,例如:日誌監控、統計分析、調用鏈分析。

針對上述問題,提出新的日誌系統的設計目標如下:

  • 業務日誌平滑接入:業務日誌接入日誌系統,只需要進行簡單的配置;日誌平台也只需要進行一些基本的配置,無須涉及日誌內容等業務信息。
  • 多樣性支持:環境多樣:物理機(虛擬機)、容器;來源多樣:系統日誌、業務日誌、中間件日誌……;格式多樣:單行/多行, plain/json。
  • 日誌挖掘:快速可查,日誌監控,統計分析。
  • 系統可用性:數據實時性;丟失率可控(業務分級、全鏈路監控)。

Billions的演進

系統的初建

  • 日誌規範

為了解決業務日誌格式多樣性問題,統一制定了日誌格式規範,使用JSON作為日誌的輸出格式。

格式要求,必須包含四類元信息:

time: 日誌產生時間,ISO8601格式

level:日誌等級, FATAL、ERROR、WARN、INFO、DEBUG

app_id:應用id,用於標示日誌來源,與公司服務樹一致,全局唯一

instance_id:實例id,用於區分同一應用不同實例,格式業務方自行設定

日誌詳細信息統一保存到log欄位中。

除上述欄位之外,業務方也可以自行添加額外的欄位。

json的mapping應保持不變:key不能隨意增加、變化,value的類型也應保持不變。

例如:

{"log": "hello billions, write more", "level": "INFO", "app_id": "testapp111", "instance_id": "instance1", "time": "2017-08-04T15:59:01.607483", "id": 0}

  • 日誌系統技術方案

日誌從產生到消費,主要經歷以下幾個階段:採集->傳輸->切分->檢索

日誌採集

日誌採集針對非落盤和落盤兩種方式。

  • 對於業務模塊日誌,統一按照日誌規範並且通過非落盤的方式進行輸出。針對此類場景,與平台技術部合作,基於go我們開發了log agent模塊。

log agent部署在物理機上,暴露出一個domain sock文件,程序將日誌通過unixgram方式輸出到domain sock。

對於運行在PAAS上的應用,在container初始化的時候,sock文件被默認mount到container內部,這樣容器內的程序就可以輸出日誌。

log agent分為兩個部分,collector和sender。collector用於接收日誌,sender用於向傳輸系統發送日誌。兩者直接通過一個文件緩存進行交互。這樣在日誌傳輸系統故障的情況下,依賴本地緩存可以保證日誌的正常接收。

我們提供了不同語言對應的日誌庫(sdk),程序可以快速接入日誌系統。

  • 非業務模塊(中間件、系統模塊、接入層)日誌,由於定製化能力較差,我們通過讀取生成的日誌文件完成日誌的採集。

我們採用的elastic stack中的filebeat進行採集,filebeat具有方便部署、配置簡單、資源消耗低的優勢,而且支持多行日誌的拼接。

物理機上部署一個單獨的filebeat進程,每一類日誌對應一個單獨的配置文件。

每一條日誌都會被單獨打上一個app_id標籤,這個類似業務日誌的app_id欄位,這樣在最終消費日誌的時候就可以進行區分了。

filebeat會自動標示日誌來源機器,這樣也就具有了區分同一應用不同實例的能力。

日誌採集

公司內部已經有了統一的數據傳輸平台(lancer),lancer的優勢如下:

基於flume+kafka做二次定製化開發,內部自動負載均衡,容量可水平擴展。

數據接收端實現了一套可靠的數據傳輸協議,完善的鏈路監控,數據傳輸安全可靠。

可以根據業務需要對接不同的消費方式(kafka、hdfs)。

有專業的團隊進行7*24維護。

因此我們直接選擇lancer作為我們的日誌傳輸系統。

log agent中的sender模塊基於lancer的定製化的數據傳輸協議發送日誌,最終日誌被傳輸到kafka集群中的不同topic(根據日誌流量,配置topic),後續從kafka消費日誌,所有的topic採用一個統一的prefix。

由於暫時沒有精力對filebeat進行二次定製化開發,因此filebeat直接將日誌輸出到lancer的kafka集群。

日誌切分

日誌切分模塊的主要作用是從kafka消費日誌,對日誌進行處理(欄位提取、格式轉換),最終存儲到elasticsearch的對應的index中。我們使用logstash作為我們的日誌切分方案。

其中:

對於按照日誌規範生成的日誌,日誌的kafka topic採用了統一的前綴,因此我們採用topics_pattern的方式來消費日誌。

logstash的partition_assignment_strategy要設置為」org.apache.kafka.clients.consumer.RoundRobinAssignor」,默認的策略(Range partitioning)會導致partition分配不均,如果採用默認的策略,當consumer(logstash數量*worker數量)的數量大於topic partition數量時,partition總是只會被分配給固定的一部分consumer。

對於非標準格式日誌,由於logstash single event pipeline的限制,因此缺乏對於多配置的支持(期待6.0的multi event pipeline)。每種日誌配置不同,因此需要單獨的logstash進程進行消費。

日誌檢索

elasticsearch集群規模為:master node*3, hot node*20, stale node*20,client node*2。es版本為5.4.3,集群配置如下:

數據機器(40core,256G內存, 1T ssd, 6T*4 SATA)採用冷熱分離的方案:同時部署一個hot node和stale node。hot node使用ssd作為存儲介質,接收實時日誌。stale node使用sata盤作為存儲介質,存儲歷史日誌(只讀不寫)。每日固定時間進行熱->冷遷移。

client node對外提供讀取api,對接kibana、管理程序(比如curator、cerebro等)。

index管理(遷移、刪除)採用curator,日誌默認保留7天。

es集群配置優化借鑒了很多社區的建議,就不詳細介紹了。

使用template進行index mapping的管理。

index提前一天進行創建,防止集中創建導致數據無法寫入。

es監控:調研了官方的x-pack monitor,由於x-pack monitor功能不足(例如缺少對於線程池的監控),並且不能進行報警,最終選擇自研。公司內部監控系統基於Prometheus,我們開發了es_exporter負責採集es的狀態信息,最終監控報警通過Prometheus實現。報警主要包含關鍵指標,例如:es cluster的狀態信息、thread rejected數量、node節點數量、unassign shard數量。

經過上述步驟,最終日誌就可以在kibana上進行查詢。第一階段,日誌系統的整體架構為:

系統迭代

隨著接入的日誌量越來越大,漸漸出現一些問題和新的需求,Billions主要在以下方面進行了升級迭代。

shard管理

最初採用了es默認的管理策略,所有的index對應5*2個shard(5個primary,5個replica),帶來的主要問題如下:

每個shard都是有額外的開銷的(內存、文件句柄),大部分的index的數量都比較小,完全沒有必要創建5個shard。

某些index的數據量很大(大於500GB/day),單個shard對應的數據量就會很大,這樣會導致檢索的速度不是最優, 並且磁碟write IO集中在少數機器上。

針對上述問題,開發了index管理模塊(shard mng),根據index的歷史數據量(昨日數據),決定創建明日index對應shard數量,目前策略為30GB/shard,shard數量上限為15。通過以上優化,集群shard數量降低了70%+,磁碟IO使用也更加高效。

日誌採樣

某些業務的日誌量很大(大於500GB/day),多為業務的訪問日誌,對日誌而言,「大量數據中的一小部分就足以進行問題排查和趨勢發現」,與研發和運維進行溝通,這個觀點也得到認同。

因此在數據採集源頭log agent(collector模塊)中增加了日誌採樣(log sample)功能:

日誌採樣以app_id為維度,INFO級別以下日誌按照比例進行隨機採樣,WARN以上日誌全部保留。

log agent接入公司配置中心,採樣比例保存在配置中心,可以動態生效。

有個細節額外說明下:由於要獲取日誌內的app_id欄位,如果直接進行json解析, cpu消耗將非常之高。後續我們改進為字元查找(bytes.Index ),解決了這個問題。

針對日誌量大的業務進行採樣,在不影響使用的情況下,節省了大量的es資源。目前每天減少3T+的日誌寫入。

data node硬體瓶頸解決

晚上20:00-24:00是B站業務的高峰期,同時也是日誌流量的高峰期。隨著流量的增長,經常收到日誌延遲的報警(日誌沒有及時的寫入es),通過觀察監控,主要發現兩個現象:

hot node出現了較多bulk request rejected,同時logstash收到了很多的429響應。嘗試調大了thread pool size和 queue_size,但是問題依然存在。

通過以上現象,懷疑是SSD IO不足導致的es寫入拒絕。後續對SSD進行了性能測試和對比,發現此型機器上SSD的寫性能較差。為了減少SSD IO壓力,我們將一部分實時寫流量遷移到了stale node(stale node之前不接受實時寫流量,寫入壓力很小),日誌延遲的問題暫時得以解決。

終極解決辦法:data node的機型為40 core CPU,256G內存,1T SSD+4*6T SATA,很明顯此機型SSD從性能和容量上都是瓶頸,為了提升此機型的利用率和解決SSD IO性能瓶頸,最終我們為每台機器添加了2*1.2T pcie SSD,一勞永逸!

logstash性能解決

在解決了上述es寫入瓶頸後,過了一段時間,高峰期日誌延遲的問題又出現了。這次es並沒有出現bulk request rejected的問題。 從整條鏈路進行排查,日誌收集和日誌傳輸上都沒有出現日誌延遲的現象,最終把注意力放在了日誌切分模塊(logstash)。

logstash性能差是社區內公認的,進一步針對logstash進行性能測試,在(2 core+4G memory)情況下,不斷調整worker數量和pipeline.batch.size, 極限性能為8000qps,性能的確很差,高峰期的流量為40W/s, 因此至少需要50個logstash實例才能滿足要求,顯然這樣的資源消耗無法接受。考慮到業務日誌對應的切分功能較為單一,因此我們使用go自研了日誌切分模塊(billions index)。

自研的模塊性能有了很大的提升,2 core+4G memory條件下,極限性能提升到5w+qps,並且內存只消耗了150M。 線上的資源消耗從(2 core+4G memory) 30 減少到了(2 core+150M memory)15,性能問題也得到解決。

日誌監控

隨著越來越多的業務的接入,日誌監控的需求越來越強烈。目前社區的解決方案中,Yelp的elastalert最為成熟,功能豐富,並且也方便進行進一步的定製化。因此我們選擇基於elastalert實現日誌監控。

結合自身需求,通過查看文檔和閱讀代碼,elastalert也有一些不足之處:

rule存儲在文件中,不可靠並且無法進行分散式擴展。

rule配置比較複雜,不夠友好和易用。

程序單點,高可用無法保證。

監控規則順序執行,效率低(如果所有規則執行時間大於執行間隔,單條規則的定期執行將無法保證)。

針對上述不足和自身需要,我們對於elastalert進行了二次開發:

主要的改進點包括:

將所有的rule存儲在elasticsearch中,即增加了rule存儲的可靠性,也為elastalert的分散式實現做好準備。

所有類型的日誌監控rule使用模板進行封裝,以降低配置複雜度。例如限制使用query string過濾日誌,屏蔽某些配置項等等。

封裝出一套Restful api進行監控規則的增刪改查。

與公司現有監控系統(Bili Moni)結合:基於web配置日誌監控,通過報警平台發送報警。

利用全局鎖解決單點問題:兩個進程一熱一冷,熱進程故障後冷會自動接手,並進行報警。

對於報警內容進行了調整(格式調整,漢化),表述更加清晰。

日誌監控1.0目前已經投入使用,並且還在持續迭代。

  • 最新Billions的架構如下:

現有問題和下一步工作

目前日誌系統還存在很多不足的地方,主要有:

缺乏許可權控制:目前許可權控制缺失,後續需要實現統一認證、基於index的授權、操作審計等功能,類比xpack。

缺乏全鏈路監控:日誌從產生到可以檢索,經過多級模塊,目前監控各層獨立實現,未進行串聯,因此無法對堆積和丟失情況進行精準監控。

日誌監控性能瓶頸:目前日誌監控為單節點(一個熱節點工作)並且規則順序執行,後續需要優化為分散式架構+規則並行執行。

日誌切分配置複雜:對於非標準格式日誌,基於logstash實現日誌切分,每一種日誌需要單獨的logstash實例進行消費,配置和上線過程複雜,後續需要平台化的系統進行支撐。

[轉自:mp.weixin.qq.com/s?]


推薦閱讀:

優維科技融資3000萬,DevOps 運維時代已來!
【玖陸零電力科技】配電室運維,讓您更省心。

TAG:日誌分析 | 運維自動化 | ELK |