如何用Flume實現實時日志收集系統
本文是野狗資深工程師廖斌旭在“iGeek Camp”第4期北京站上進行的《基于Flume的日志收集和報警系統的實戰》的演講實錄,主要分為兩個部分:野狗日志系統的架構演進和優化方案。
業務決定架構,在講解日志架構之前,先介紹一下我們野狗的業務。野狗云為應用開發提供數據存儲和實時通信服務。使用野狗的SDK即可獲得可擴容的數據存儲與毫秒級的實時通信。我們的業務共有兩類SDK,基于兩種連接技術。第一類是websocket長連接或用Long polling模擬的長連接,另外一類是HTTP REST短連接。
大家看這張圖,野狗的業務架構分為兩層,第一層是接入層,包括NodeJs接入層、Nginx Rest API接入層;第二層是核心業務處理層,包括數據處理和Push server同步推送。SDK通過長連接或短連接與接入層相連接。所有的請求都通過SDK發送到接入層,接入層轉化協議,然后轉發到業務處理層。所以接入層是用戶訪問的入口,天生適合做流控和統計。
野狗的日志業務主要分為兩類:日常日志和計費服務。日常統計包括UV、PV以及客戶的API操作記錄。后面又因為業務需求,增加了計費服務,主要包括流量統計和連接數統計。
我們的第一版,很簡單。使用crontab命令來定時執行rsync命令,同步日志文件。
從這張圖可以看到,接入層通過打本地日志的方式,把請求信息記錄下來。然后使用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被消費事件,而我們在流量較低時也有收集日志的需求,所以在原生系統上又增加了空閑超時檢測。
謝謝大家。
-END-
本站內容采用 知識共享署名 4.0 國際許可協議 進行許可。