Flume快速入門(二):設計從簡

      上一篇文章簡單介紹了下Flume的背景,接下來本文說說Flume NG的內部設計。注意:本文針對的是Flume1.6.0版本。

      上一篇:http://manzhizhen.iteye.com/blog/2298150

      我們先來看看爲什麼需要Flume,在大數據分析領域,最重要的就是數據,而日誌作爲首選數據來源之一,有着舉足輕重的地位,如今企業的線上業務服務器,少則幾十臺上百臺,多則上千臺,這麼多臺線上服務器,按照每臺每天平均產生出50G的日誌來算,如果線上共有100臺服務器,則每天就可以產生差不多5TB的日誌量,而將些日誌流數據高效可靠的寫入hdfs,我們應該怎麼做?有人會說每臺業務服務器自己往HDFS寫啊,no,no,no,這樣做的話hdfs表示受不了,我們一定要考慮到“供需穩定和平衡”,又有人馬上會說:用Kafka!的確,Kafka作爲高吞吐量的MQ實現之一,性能上肯定是沒問題,而且Kafka作爲Apache另一頂級項目,最初就是作爲日誌系統出生。Kafka現在作爲流行的發佈/訂閱消息中間件,有Scala語言開發,廣泛的用於體統之間的異步通信,特別適合異構系統之間使用。在日誌傳輸領域,是選擇Flume還是Kafka,就像皇馬打巴薩那樣,誰都沒有壓倒性的優勢,但Flume純粹爲日誌傳輸而生,開箱即用,幾乎零編程,而且提供日誌過濾、自定義分發等功能,並對寫入HDFS等有良好的支持,如果想偷懶,則選Flume絕對沒錯。但現如今,Kafka+Flume+HDFS等諸多將Kafka和Flume結合起來使用的方案。

       如果沒有成熟的日誌傳輸方案,我們來討論討論如果自己做,需要解決哪些問題。最容易想到的第一點就是效率和性能,秒級的延遲我們可以接受,但如果說線上業務系統產生一條日誌數據,過了十幾分鍾甚至一個小時才能寫到HDFS中,那是忍無可忍的。其實這點不難做到,只要架構設計的簡單實用,效率和性能一般不是問題。第二點就是可靠性,只要是經過網絡傳輸的數據,都存在丟失的可能,要做到一條日誌從生產者發送到消費者,而且消費者有且僅僅消費一次,是很困難的,在某些情況下甚至是不可能的,如果做不到,那至少得做到保證至少消費一次。可靠性還涉及到Failover和可恢復,如果發生故障,能切換到其他正常服務的節點,並且出故障的節點能快速恢復。第三點就是可擴展性,可擴展性是分佈式系統的標配了,如果日誌量增大,我們可以動態的添加服務節點,來增加日誌傳輸的吞吐量。第四點,得支持異構源,日誌不可能只需要些到HDFS,某些日誌還需要寫入目的地。其實要做到以上這些點,並不容易,我們不需要重複造輪子了,因爲已經有Flume了。

       接下來,我們看看Flume的設計,Flume是以Agent作爲基本的服務單位,類似於MQ中的Broker,一個Agent啓動後就是一個Java進程,它暴露一個或多個端口來提供服務。於是你可以發現,可以疊加多個Agent來提高我們的日誌服務能力,比如你可以在一個服務器上啓動多個Agent的Java進程,來通過暴露多個端口來實現日誌服務的橫向擴展,增加日誌傳輸能力,但也不是越多越好,應該根據CPU內核數來確定。每個Agent都對應一個配置文件,配置文件中有該Agent的所有細節。

       任何日誌數據在進入Agent之前會被包裝成Event,所以,對於Agent來說,生命週期所基礎到的每一行日誌,其實都是一個Event。Event下篇會詳細介紹,接下來我們看看Agent的內部結構,如果把Agent當做一個黑盒,你肯定能想到它得有個輸入和輸出,輸入是Event的入口,而輸入則表明日誌將發往其他某個地方或者直接寫入我們的離線數據的倉庫HDFS。這個輸入就是Agent三大組成部分之一的Source,輸出指的是Sink,最後一個就是Channel,Channel是Event存放的地方。沒錯,一個Flume Agent實例就是由多個Source、多個Channel和多個Sink組成的,也就是說,你可以在Agent的配置你文件中定義多個Source、Channel和Sink。但需要注意,Source可以指定多個Channel,但一個Sink實例只能指定一個Channel,換句話說,就是Source能同時向多個Channel寫入數據,但一個Sink只能從一個Channel中取數據。大體設計如下圖:

Agent component diagram

       Source實例會在配置文件指定的端口來監聽數據,用來接收客戶端發來的Event並將其存儲到Channel之中。Flume提供了多種類型的Source,用來從不同的渠道來接收Event,比如Avro Source、Thrift Source、 Kafka Source、Http Source等,Source的選型需要根據日誌發送客戶端來決定,如果是Avro的Client,那麼它的接收源只能是Avro Source,而不能是Thrift Source。Source中有攔截器(interceptor)的概念, 用於過濾掉不符合要求的Event,或者給Event添加必要的信息,攔截器也可以組合成攔截器鏈,就像Servlet中的過濾器鏈一樣。前面說過,一個Source至少要指定一個接收的Channel,當一個Source指定多個Channel時,有人肯定得問,這時一個Event會被複制多份分別放入這些Channel呢?還是負載均衡的只放入其中一個Channel呢?這個問題很好,答案是:都可以!當一個Source綁定多個Channel時,Flume提供了兩種Channel寫入策略:複製(replicating)和複用(multiplexing),當使用複製策略時每個Channel都會接收到一個Event的副本,而在使用複用策略時,一個Event只會下發到其中一個合格的Channel中。Flume中默認的分發策略是複用。當使用默認的複用策略時,Source接收到的消息會不會是輪詢一次發給綁定的Channel來達到“負載均衡”的目的呢?其實仔細想想就知道,從寫入的角度來說,將一份數據寫到一個Channel和均勻的寫到多個Channel,性能上會有多大差別嗎?所以,Flume採用的不是簡單的負載均衡的思路,而是給複用策略添加了選擇器(selector)的功能,可以通過配置來做到根據Event頭中的鍵值來決定該Event寫入哪些(注意,這裏是哪些,因爲有可能是寫入多個)Channel,還可以設置一個默認Channel,當沒有匹配的鍵值時,就直接寫入設置的默認的Channel中。那麼問題來了,如果Source r1需要寫入(複製策略或複用策略)到三個Channel c1,c2和c3中,如果其中的c2寫入失敗了,這時Source會怎麼處理?大家能想到兩種可能的處理方案,第一種就是打印告警日誌,然後只在失敗的c2上嘗試重新寫入。第二種就是作爲一種事務來處理,c2的寫入失敗將導致該Event會重新再次嘗試寫入到c1,c2和c3中。這裏,當使用的是複用策略時,我們可以在Selector上配置可選( optional)的Channel,沒有配置可選標記的都是要求(required)的Channel,對於被配置可選的這些Channel來說(注意,如果某可選的Channel還出現在了required的Channel中,那麼它還是required的),Source將其當做備份方案,即Source可以不必保證一定將對應的Event寫入成功,Source只會向其嘗試寫入一次。但對於required的Channel,Source將保證其寫入成功(具體細節後面後面回來補充)。

       Channel用來存儲Agent接收到的Event,像Source一樣,Flume也提供了多種類型的Channel,常用的比如Memory Channel、File Channel、JDBC Channel、Kafka Channel。效率最高的肯定是Memory Channel,但它是不可靠的,一旦重啓,全部沒有消費的Event就會丟失。最常用最簡單的就是File Channel,它將Event先寫入指定的文件中,所以重啓的話大部分沒有消費的Event還是會保留。爲了保證端到端(end to end)的可靠性,只有Sink成功消費了Event,Event纔會從Channel中刪除。

       Sink用於將Event寫入到其他的目的地,這個目的地可以是HDFS、Kafka等開源實現,或者是另一個Flume Agent,Flume提供了足夠多的Sink的實現,達到配置後開箱即用。常用的Sink實現有Avro Sink、HDFS Sink、Kafka Sink、Thrift Sink、Null Sink、Logger Sink等。如果使用Null Sink,將直接丟棄從Channel取出來的Event,而Logger Sink一般用來測試,它將從Channel取出來的Event直接打印在Flume的日誌文件中。

       說到這裏,大家應該對Flume Agent有一個大體瞭解了,後面的文章我再來給大家一一介紹其內部細節。下一篇:http://manzhizhen.iteye.com/blog/2298394

發佈了48 篇原創文章 · 獲贊 49 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章