本文是野狗實時後端雲 (www.wilddog.com)資深工程師廖斌旭在「iGeek Camp」第4期北京站上進行的《基於Flume的野狗實時日誌系統的演進和優化》的演講實錄,主要分爲兩個部分:野狗日誌系統的架構演進和優化方案。redis
在講解日誌架構以前,先介紹一下咱們野狗的業務。咱們的業務共有兩類SDK,基於兩種鏈接技術。第一類是WebSocket長鏈接或用Long polling模擬的長鏈接,另一類是HTTP REST短鏈接。shell
你們看這張圖,野狗的業務架構分爲兩層,第一層是接入層,包括NodeJs接入層、Nginx Rest API接入層;第二層是核心業務處理層,包括數據處理和Push server同步推送。SDK經過長鏈接或短鏈接與接入層相鏈接。全部的請求都經過SDK發送到接入層,接入層轉化協議,而後轉發到業務處理層。因此接入層是用戶訪問的入口,天生適合作流控和統計。數據庫
野狗的日誌業務主要分爲兩類:平常日誌和計費服務。平常統計包括UV、PV以及客戶的API操做記錄。後面又由於業務需求,增長了計費服務,主要包括流量統計和鏈接數統計。後端
咱們的初版,很簡單。使用crontab命令來定時執行rsync命令,同步日誌文件。api
從這張圖能夠看到,接入層經過打本地日誌的方式,把請求信息記錄下來。而後使用crontab定時執行rsync同步日誌到「日誌歸檔服務器」。處理統計業務的服務「cloud-stat」,定時從「日誌歸檔服務器」獲取日誌文件,而後把計算的流量統計結果保存到數據庫中。可是設計架構的目標並不只僅是完成需求,同時還要知道它的優點和劣勢,才能瞭解架構下一步的改進方向。接下來,咱們來看看v0.1版本的優缺點。緩存
最突出的優勢是簡單,使用兩條命令就能搞定。使用rsync命令比SCP更靈活,由於前者支持增量拷貝。還有一個優勢就是支持數據壓縮。服務器
可是由於有了流量數據,因此想作實時流控,仍是挺難的。由於定時同步最快可以作到分鐘級別,實時性不夠。文件在多臺服務器之間流轉,也增長管理的文件的成本。文件的多副本,同時也會形成存儲的浪費。架構
因此基於實時性的考慮, 咱們又改進了日誌系統的架構。這就是咱們的v0.2版。性能
介紹v0.2架構以前,先描述下項目背景。由於項目時間很是緊張,因此咱們引進了redis作流量數據的緩存。可是這個方案並非行業的最優的作法,不過當時已經搭建redis集羣,正好可以解決實時性的需求。優化
咱們來看下下面這張圖。Redis做爲生產者消費者模式的緩衝隊列,接收「接入層」的流程數據,並交給統計業務消費。NodeJs接入層和Nginx Rest API接入層,把流量數據經過redis的客戶端寫入Redis集羣。統計業務cloud-stat 則定時從redis集羣消費。時間從v0.1的最快分鐘級別,降到如今5秒內完成日誌產生、收集、處理整個過程。這對於咱們系統的實時性是一個很大的提高。
通過改進以後,日誌系統的延遲下降了,這也是咱們v0.2的主要目的。可是,任何系統都不是完美的。日誌文件記錄咱們的最原始的用戶訪問記錄,這些數據咱們不能丟。加上redis這套架構,並存兩套架構,就在無形中增長了咱們的維護成本。Redis緩存在帶來高性能的同時,也帶來了一個副產品,就是在接入層必須硬編碼redis的邏輯。
經歷兩版的系統改造,咱們有了一點心得:一是利用日誌幹更多的事情,二是日誌統計不要侵入原系統。
通過前兩版的積累,在v0.3咱們決定引入flume服務,來作日誌收集。主要體如今兩點:一是在日誌源服務器部署flume agent,第二個就是增長了中心化的收集服務flume collector。
如今的日誌系統分爲3層,一是部署在接入層機器上的flume agent,二是中心化收集服務器flume Collector,三是日誌處理服務。
接入層生成的日誌,由flume agent進程,經過avro rpc發送到flume Collector。日誌在collector彙總以後,主動發給第三層日誌處理服務。主要包括統計服務cloud-stat、 分析服務analyze和日誌歸檔服務log archive。
前面咱們講了v0.3的架構圖,如今詳細介紹一下flume。Flume的全名是Apache Flume,最初由 cloudera公司開發。捐給Apache基金會後,命名從flume-og更名爲flume-ng,又稱爲Apache Flume。
下面介紹一下flume相關的幾個術語:
Event:一個數據單元,帶有一個可選的消息頭。
Flow:Event從源點到達目的點的遷移的抽象。
Client:操做位於源點處的Event,將其發送到Flume Agent。
Agent:一個獨立的Flume進程,包含組件Source、Channel、Sink。
Source:用來消費傳遞到該組件的Event。
Channel:中轉Event的一個臨時存儲隊列,保存有Source組件傳遞過來的Event。
Sink:從Channel中消費Event,將Event傳遞到Flow Pipeline中的下一個Agent。
它的設計目標主要是可靠、可伸縮、易擴展和易管理。下面咱們介紹幾個經常使用的解決方案:
一是Flume串聯,它適用收集日誌的規模較小的場景。
二是Flume多路Agent,能實現更復雜的業務邏輯。
三是Flume 並聯,它提升了日誌匯聚效率,可是存在單點問題。
四是複雜均衡,主要用於解決單點問題。
介紹完Flume的架構和使用場景。下面講一講,Flume在野狗雲中的使用以及遇到的問題。野狗雲使用Agent的主要收集接入層產生的本地日誌文件。前面講到Source是Agent用於接收數據的一個組件。Flume提供了多種基於日誌文件的Source,包括兩種:ExecSource和SpoolingDirSource。
ExecSource 的主要做用是,在Agent中執行shell腳本或shell命令,而後經過管道接收前者的數據。咱們主要建立了兩種接入層的日誌。
一是Rest API 接入層流量日誌:日誌格式是 restapi.access.log, 天天零點把原來的日誌更名爲 restapi.access.log.date -d "a days ago" "+%Y-%m-%d"
, 而後再建立文件 restapi.access.log。這種機制叫作日誌輪轉。
二是NodeJs 接入層流量日誌:日誌格式是 longconnect.log.date "+%Y-%m-%d"
, 天天零點建立按天的日誌文件。
在這個過程咱們碰見了幾個問題。一是當發生日誌輪轉的時候,由於tail -f命令打開的仍是原來的文件描述符,因此就沒法獲取到當天新日誌文件的內容。不過tail命令的--retry選項會按期檢查文件名對應的文件描述符的變化。這就解決了咱們這個問題。另一個就是沒有辦法作到生產速率控制。這個咱們在下面的PPT會講到。
SpoolingDirSource用於監控文件目錄變化的,可是實際的使用中會有如下兩個問題:一是文件不能寫,只能讀。二是延遲比較高,須要等待日誌按期歸檔。
爲了解決速率控制的問題, 咱們用Java程序實現了「模擬tail -F」的功能,主要是使用ExceSource,定時修改Flume的配置文件。另外就是根據咱們的需求自定義Source。
Channel的功能是作緩存隊列,Flume提供兩種Channel。
MemoryChannel使用內存作緩衝隊列,全部數據都保存在內存。可是這樣作有兩個問題:一是可用性差,另外一個就是當隊列數量小於閾值時,會一直等待被消費。
FileChannel使用磁盤作緩衝隊列,全部數據都保存在磁盤。它的一個問題就是吞吐量比較低。
由於咱們野狗自身的需求,在要求實時的同時,還要保證必定的可用性。美團的解決方案是提供一種基於內存Channel和FileChannel的Channel。
而咱們野狗本身開發了一種基於MemoryChannel的加強Channel,主要增長了隊列序列化功能,而且在重啓的時候可以作到持久化。另外由於Flume低於閾值時纔會觸發Channel被消費事件,而咱們在流量較低時也有收集日誌的需求,因此在原生系統上又增長了空閒超時檢測。
謝謝你們。