Flume日誌收集系統架構詳解--轉

來源:互聯網
上載者:User

標籤:avr   崩潰   resource   擴充性   緩衝   store   現象   格式化   hello   

 2017-09-06 朱潔 大資料和雲端運算技術

任何一個生產系統在運行過程中都會產生大量的日誌,日誌往往隱藏了很多有價值的資訊。在沒有分析方法之前,這些日誌儲存一段時間後就會被清理。隨著技術的發展和分析能力的提高,日誌的價值被重新重視起來。在分析這些日誌之前,需要將分散在各個生產系統中的日誌收集起來。本節介紹廣泛應用的Flume日誌收集系統。

一、概述    

Flume是Cloudera公司的一款高效能、高可用的分布式日誌收集系統,現在已經是Apache的頂級項目。同Flume相似的日誌收集系統還有Facebook Scribe、Apache Chuwka。

二、Flume發展曆程    

Flume 初始的發行版本目前被統稱為Flume OG(Original Generation),屬於Cloudera。但隨著 Flume 功能的擴充,Flume OG 代碼工程臃腫、核心組件設計不合理、核心配置不標準等缺點逐漸暴露出來,尤其是在 Flume OG 的最後一個發行版本0.94.0中,日誌傳輸不穩定現象尤為嚴重。為瞭解決這些問題,2011 年 10 月 22日,Cloudera 完成了 Flume-728,對Flume進行了裡程碑式的改動:重構核心組件、核心配置及代碼架構,重構後的版本統稱為 Flume NG(Next Generation);改動的另一原因是將 Flume 納入Apache 旗下,Cloudera Flume 更名為 Apache Flume。

三、Flume架構分析    
1. 系統特點① 可靠性

當節點出現故障時,日誌能夠被傳送到其他節點上而不會丟失。Flume提供了三種層級的可靠性保障,從強到弱依次為:end-to-end(收到資料後,Agent首先將事件寫到磁碟上,當資料傳送成功後,再刪除;如果資料發送失敗,則重新發送)、Store on Failure(這也是Scribe採用的策略,當資料接收方崩潰時,將資料寫到本地,待恢複後繼續發送)、Best Effort(資料發送到接收方後,不會進行確認)。

② 可擴充性

Flume採用了三層架構,分別為Agent、Collector和Storage,每一層均可以水平擴充。其中,所有的Agent和Collector均由Master統一管理,這使得系統容易被監控和維護。並且Master允許有多個(使用ZooKeeper進行管理和負載平衡),這樣就避免了單點故障問題。

③ 可管理性

當有多個Master時,Flume利用ZooKeeper和Gossip保證動態配置資料的一致性。使用者可以在Master上查看各個資料來源或者資料流執行情況,並且可以對各個資料來源進行配置和動態載入。Flume提供了Web和Shell Script Command兩種形式對資料流進行管理。

④ 功能可擴充性

使用者可以根據需要添加自己的Agent、Collector或Storage。此外,Flume內建了很多組件,包括各種Agent(如File、Syslog等)、Collector和Storage(如File、HDFS等)。

2. 系統架構

是Flume OG的架構。

Flume NG的架構如所示。Flume採用了分層架構,分別為Agent、Collector和Storage。其中,Agent和Collector均由Source和Sink兩部分組成,Source是資料來源,Sink是資料去向。

Flume使用了兩個組件:Master和Node。Node根據在Master Shell或Web中的動態配置,決定其是作為Agent還是作為Collector。

① Agent

Agent的作用是將資料來源的資料發送給Collector。Flume內建了很多直接可用的資料來源(Source),如下。

text("filename"):將檔案filename作為資料來源,按行發送。

tail("filename"):探測filename新產生的資料,按行發送。

fsyslogTcp(5140):監聽TCP的5140連接埠,並將接收到的資料發送。

tailDir("dirname"[,fileregex=".*"[,startFromEnd=false[,recurseDepth=0]]]):監聽目錄中的檔案末尾,使用Regex選定需要監聽的檔案(不包含目錄),recurseDepth為遞迴監聽其下子目錄的深度,同時提供了很多Sink,如console[("format")],直接將資料顯示在console上。

text("txtfile"):將資料寫到檔案txtfile中。

dfs("dfsfile"):將資料寫到HDFS上的dfsfile檔案中。

syslogTcp("host",port):將資料通過TCP傳遞給host節點。

agentSink[("machine"[,port])]:等價於agentE2ESink,如果省略machine參數,則預設使用flume.collector.event.host與flume.collector.event.port作為預設collectro。

agentDFOSink[("machine"[,port])]:本地熱備Agent。Agent發現Collector節點故障後,不斷檢查Collector的存活狀態以便重新發送Event,在此期間產生的資料將緩衝到本地磁碟中。

agentBESink[("machine"[,port])]:不負責的Agent。如果Collector出現故障,將不作任何處理,它發送的資料也將被直接丟棄。

agentE2EChain:指定多個Collector,以提高可用性。當向主Collector發送Event失效後,將轉向第二個Collector發送;當所有的Collector都失效後,它還會再發送一遍。

② Collector

Collector的作用是將多個Agent的資料匯總後,載入到Storage中。它的Source和Sink與Agent類似。

Source如下。

collectorSource[(port)]:Collector Source,監聽連接埠匯聚資料。

autoCollectorSource:通過Master協調物理節點自動匯聚資料。

logicalSource:邏輯Source,由Master分配連接埠並監聽rpcSink。

Sink如下。

collectorSink("fsdir","fsfileprefix",rollmillis):collectorSink,資料通過Collector匯聚之後發送到HDFS,fsdir是HDFS目錄,fsfileprefix為檔案首碼碼。

customdfs("hdfspath"[,"format"]):自訂格式DFS。

③ Storage

Storage是儲存系統,可以是一個普通File,也可以是HDFS、Hive、HBase、分布式儲存等。

④ Master

Master負責管理、協調Agent和Collector的配置資訊,是Flume叢集的控制器。

在Flume中,最重要的抽象是Data Flow(資料流)。Data Flow描述了資料從產生、傳輸、處理到最終寫入目標的一條路徑,如所示。

 

對於Agent資料流配置,就是從哪裡得到資料,就把資料發送到哪個Collector。

對於Collector,就是接收Agent發送過來的資料,然後把資料發送到指定的目標機器上。

註:Flume架構對Hadoop和ZooKeeper的依賴只存在於JAR包上,並不要求Flume啟動時必須將Hadoop和ZooKeeper服務同時啟動。

3. 組件介紹

本文所說的Flume基於1.4.0版本。

① Client

路徑:apache-flume-1.4.0-src\flume-ng-clients。

操作最初的資料,把資料發送給Agent。在Client與Agent之間建立資料溝通的方式有兩種。

第一種方式:建立一個iclient繼承Flume已經存在的Source,如AvroSource或者SyslogTcpSource,但是必須保證所傳輸的資料Source可以理解。

第二種方式:寫一個Flume Source通過IPC或者RPC協議直接與已經存在的應用通訊,需要轉換成Flume可以識別的事件。

Client SDK:是一個基於RPC協議的SDK庫,可以通過RPC協議使應用與Flume直接建立串連。可以直接調用SDK的api函數而不用關注底層資料是如何互動的,提供append和appendBatch兩個介面,具體的可以看看代碼apache-flume-1.4.0-src\flume-ng-sdk\src\main\java\org\apache\ flume\api\RpcClient.java。

② NettyAvroRpcClient

Avro是預設的RPC協議。NettyAvroRpcClient和ThriftRpcClient分別對RpcClient介面進行了實現,具體實現可以看下代碼apache-flume-1.4.0-src\flume-ng-sdk\src\main\java\org\apache\flume\api\ NettyAvroRpcClient.java和apache-flume-1.4.0-src\flume-ng-sdk\src\main\java\org\apache\flume\api\ ThriftRpcClient.java。

下面給出一個使用SDK與Flume建立串連的範例如下,實際使用中可以參考實現:

import org.apache.flume.Event;

import org.apache.flume.EventDeliveryException;

import org.apache.flume.api.RpcClient;

import org.apache.flume.api.RpcClientFactory;

import org.apache.flume.event.EventBuilder;

import java.nio.charset.Charset;

public class MyApp {

public static void main(String[] args) {

MyRpcClientFacade client = new MyRpcClientFacade();

// Initialize client with the remote Flume agent‘s host and port

client.init("host.example.org",41414);

// Send 10 events to the remote Flume agent. That agent should be

// configured to listen with an AvroSource.

String sampleData = "Hello Flume!";

for (int i = 0; i < 10; i++) {

client.sendDataToFlume(sampleData);

}

client.cleanUp();

}

}

class MyRpcClientFacade {

private RpcClient client;

private String hostname;

private int port;

public void init(String hostname,int port) {

// Setup the RPC connection

this.hostname = hostname;

this.port = port;

this.client = RpcClientFactory.getDefaultInstance(hostname,port);

// Use the following method to create a thrift client (instead of the above line):

// this.client = RpcClientFactory.getThriftInstance(hostname,port);

}

public void sendDataToFlume(String data) {

// Create a Flume Event object that encapsulates the sample data

Event event = EventBuilder.withBody(data,Charset.forName("UTF-8"));

// Send the event

try {

client.append(event);

} catch (EventDeliveryException e) {

// clean up and recreate the client

client.close();

client = null;

client = RpcClientFactory.getDefaultInstance(hostname,port);

// Use the following method to create a thrift client (instead of the above line):

// this.client = RpcClientFactory.getThriftInstance(hostname,port);

}

}

public void cleanUp() {

// Close the RPC connection

client.close();

}

}

為了能夠監聽到關聯末端口,需要在設定檔中增加連接埠和Host配置資訊(設定檔apache-flume- 1.4.0-src\conf\flume-conf.properties.template)。

client.type = default (for avro) or thrift (for thrift)

hosts = h1                         # default client accepts only 1 host

                                    # (additional hosts will be ignored)

hosts.h1 = host1.example.org:41414 # host and port must both be specified

                                    # (neither has a default)

batch-size = 100                 # Must be >=1 (default:100)

connect-timeout = 20000         # Must be >=1000 (default:20000)

request-timeout = 20000         # Must be >=1000 (default:20000)

除了以上兩類實現外,FailoverRpcClient.java和LoadBalancingRpcClient.java也分別對RpcClient介面進行了實現。

③ FailoverRpcClient

該介面主要實現了主備切換,採用<host>:<port>的形式,一旦當前串連失敗,就會自動尋找下一個串連。

④ LoadBalancingRpcClient

該介面在有多個Host的時候起到負載平衡的作用。

 

 

 

⑤ Embeded Agent

 

 

Flume允許使用者在自己的Application裡內嵌一個Agent。這個內嵌的Agent是一個輕量級的Agent,不支援所有的Source Sink Channel。

 

 

 

⑥ Transaction

 

 

Flume的三個主要組件——Source、Sink、Channel必須使用Transaction來進行訊息收發。在Channel的類中會實現Transaction的介面,不管是Source還是Sink,只要串連上Channel,就必須先擷取Transaction對象,如所示。

 

具體使用執行個體如下,可以供產生環境中參考:

Channel ch = new MemoryChannel();

Transaction txn = ch.getTransaction();

txn.begin();

try {

Event eventToStage = EventBuilder.withBody("Hello Flume!",Charset.forName ("UTF-8"));

ch.put(eventToStage);

txn.commit();

} catch (Throwable t) {

txn.rollback();

if (t instanceof Error) {

throw (Error)t;

}

} finally {

txn.close();

}

 

 

 

⑦ Sink

 

 

Sink的一個重要作用就是從Channel裡擷取事件,然後把事件發送給下一個Agent,或者把事件儲存到另外的倉庫內。一個Sink會關聯一個Channel,這是配置在Flume的設定檔裡的。SinkRunner.start()函數被調用後,會建立一個線程,該線程負責管理Sink的整個生命週期。Sink需要實現LifecycleAware介面的start()和stop()方法。

Sink.start():初始化Sink,設定Sink的狀態,可以進行事件收發。

Sink.stop():進行必要的cleanup動作。

Sink.process():負責具體的事件操作。

Sink使用參考代碼執行個體如下:

public class MySink extends AbstractSink implements Configurable {

private String myProp;

@Override

public void configure(Context context) {

String myProp = context.getString("myProp","defaultValue");

// Process the myProp value (e.g. validation)

// Store myProp for later retrieval by process() method

this.myProp = myProp;

}

@Override

public void start() {

// Initialize the connection to the external repository (e.g. HDFS) that

// this Sink will forward Events to ..

}

@Override

public void stop () {

// Disconnect from the external respository and do any

// additional cleanup (e.g. releasing resources or nulling-out

// field values) ..

}

@Override

public Status process() throws EventDeliveryException {

Status status = null;

// Start transaction

Channel ch = getChannel();

Transaction txn = ch.getTransaction();

txn.begin();

try {

// This try clause includes whatever Channel operations you want to do

Event event = ch.take();

// Send the Event to the external repository.

// storeSomeData(e);

txn.commit();

status = Status.READY;

} catch (Throwable t) {

txn.rollback();

// Log exception,handle individual exceptions as needed

status = Status.BACKOFF;

// re-throw all Errors

if (t instanceof Error) {

throw (Error)t;

}

} finally {

txn.close();

}

return status;

}

}

 

 

 

⑧ Source

 

 

Source的作用是從Client端接收事件,然後把事件儲存到Channel中。PollableSourceRunner.start()用於建立一個線程,管理PollableSource的生命週期。同樣也需要實現start()和stop()兩種方法。需要注意的是,還有一類Source,被稱為EventDrivenSource。區別是EventDrivenSource有自己的回呼函數用於捕捉事件,並不是每個線程都會驅動一個EventDrivenSource。

以下是一個PollableSource的例子:

public class MySource extends AbstractSource implements Configurable, PollableSource {

private String myProp;

@Override

public void configure(Context context) {

String myProp = context.getString("myProp","defaultValue");

// Process the myProp value (e.g. validation,convert to another type,...)

// Store myProp for later retrieval by process() method

this.myProp = myProp;

}

@Override

public void start() {

// Initialize the connection to the external client

}

@Override

public void stop () {

// Disconnect from external client and do any additional cleanup

// (e.g. releasing resources or nulling-out field values) ..

}

@Override

public Status process() throws EventDeliveryException {

Status status = null;

// Start transaction

Channel ch = getChannel();

Transaction txn = ch.getTransaction();

txn.begin();

try {

// This try clause includes whatever Channel operations you want to do

// Receive new data

Event e = getSomeData();

// Store the Event into this Source‘s associated Channel(s)

getChannelProcessor().processEvent(e)

txn.commit();

status = Status.READY;

} catch (Throwable t) {

txn.rollback();

// Log exception,handle individual exceptions as needed

status = Status.BACKOFF;

// re-throw all Errors

if (t instanceof Error) {

throw (Error)t;

}

} finally {

txn.close();

}

return status;

}

}

 

 

4. Flume使用模式

 

 

 

Flume的資料流由事件(Event)貫穿始終。事件是Flume的基本資料單位,它攜帶日誌資料(位元組數組形式)並且攜帶有頭資訊,這些Event由Agent外部的Source,比如中的Web Server產生。當Source捕獲事件後會進行特定的格式化,然後Source會把事件推入(單個或多個)Channel中。你可以把Channel看作是一個緩衝區,它將儲存事件直到Sink處理完該事件。Sink負責持久化日誌或者把事件推向另一個Source。

很直白的設計,其中值得注意的是,Flume提供了大量內建的Source、Channel和Sink類型。不同類型的Source,Channel和Sink可以自由組合。多Agent串聯,如所示。

 

或者多Agent合并,如所示。

如果你以為Flume就這些能耐那就大錯特錯了。Flume支援使用者建立多級流,也就是說,多個agent可以協同工作,並且支援Fan-in、Fan-out、Contextual Routing、Backup Routes。如所示。

 

 

 

參考文獻    

 

 

  • 參考http://www.aboutyun.com/thread-7848-1-1.html官網使用者手冊,http://flume.apache.org/FlumeUserGuide.html。 

  • Github地址https://github.com/apache/flume。 

  • 參考http://flume.apache.org/FlumeUserGuide.html。 

Flume日誌收集系統架構詳解--轉

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.