概要
Apache Flume 是一個(gè)分布式,可靠且可用的系統(tǒng),用于有效地從許多不同的源收集、聚合和移動(dòng)大量日志數(shù)據(jù)到一個(gè)集中式的數(shù)據(jù)存儲(chǔ)區(qū)。
Flume 的使用不只限于日志數(shù)據(jù)。因?yàn)閿?shù)據(jù)源可以定制,flume 可以被用來(lái)傳輸大量事件數(shù)據(jù),這些數(shù)據(jù)不僅僅包括網(wǎng)絡(luò)通訊數(shù)據(jù)、社交媒體產(chǎn)生的數(shù)據(jù)、電子郵件信息等等。
Apache Flume 是 Apache 基金會(huì)的頂級(jí)項(xiàng)目,在加入 Apache 之前由 cloudera 公司開(kāi)發(fā)以及維護(hù)。
Apache Flume 目前有兩種主版本: 0.9.x 和 1.x。 其中 0.9.x 是歷史版本,我們稱之為 Flume OG(original generation)。2011 年 10 月 22 號(hào),cloudera 完成了 Flume-728,對(duì) Flume 進(jìn)行了里程碑式的改動(dòng):重構(gòu)核心組件、核心配置以及代碼架構(gòu),重構(gòu)后的版本統(tǒng)稱為 Flume NG(next generation),也就是這里說(shuō)的 1.x 版本。
本文主要對(duì) Flume 的作用以及核心概念進(jìn)行介紹,通過(guò)本文讀者可以大致了解 flume 的使用場(chǎng)景、核心組件以及各組件的運(yùn)行機(jī)制。關(guān)于如何配置 flume 以適應(yīng)不同場(chǎng)景,我們會(huì)在另一篇文章中詳細(xì)解讀。
架構(gòu)
數(shù)據(jù)流模型
一個(gè) Flume 事件被定義為一個(gè)數(shù)據(jù)流單元。Flume agent 其實(shí)是一個(gè) JVM 進(jìn)程,該進(jìn)程中包含完成任務(wù)所需要的各個(gè)組件,其中最核心的三個(gè)組件是 Source、Chanel 以及 Slink。

Source 消費(fèi)由外部源(如Web服務(wù)器)傳遞給它的事件。外部源以一定的格式發(fā)送數(shù)據(jù)給 Flume,這個(gè)格式的定義由目標(biāo) Flume Source 來(lái)確定。例如,一個(gè) Avro Flume source 可以從 Avro(Avro是一個(gè)基于二進(jìn)制數(shù)據(jù)傳輸?shù)母咝阅苤虚g件,是 hadoop 的一個(gè)子項(xiàng)目) 客戶端接收 Avro 事件,也可以從其他 Flume agents (該 Flume agents 有 Avro sink)接收 Avro 事件。 同樣,我們可以定義一個(gè) Thrift Flume Source 接收來(lái)自 Thrift Sink、Flume Thrift RPC 客戶端或者其他任意客戶端(該客戶端可以使用任何語(yǔ)言編寫(xiě),只要滿足 Flume thrift 協(xié)議)的事件。
channel 可以理解為緩存區(qū),用來(lái)保存從 Source 那拿到的數(shù)據(jù),直到 Flume slink 將數(shù)據(jù)消費(fèi)。file chanel 是一個(gè)例子,它將數(shù)據(jù)保存在文件系統(tǒng)中(當(dāng)然你可以將數(shù)據(jù)放在內(nèi)存中)。
slink 從 channel 消費(fèi)完數(shù)據(jù)就會(huì)將數(shù)據(jù)從 channel 中清除,隨后將數(shù)據(jù)放到外部存儲(chǔ)系統(tǒng)例如 HDFS (使用 Flume HDFS sink)或發(fā)送到其他 Flume agent 的 source 中。不管是 Source 還是 Slink 都是異步發(fā)送和消費(fèi)數(shù)據(jù)。
復(fù)雜的流
Flume 允許用戶構(gòu)建一個(gè)復(fù)雜的數(shù)據(jù)流,比如數(shù)據(jù)流經(jīng)多個(gè) agent 最終落地。It also allows fan-in and fan-out flows, contextual routing and backup routes (fail-over) for failed hops.
可靠性
事件被存儲(chǔ)在每個(gè) agent 的 channel 中。隨后這些事件會(huì)發(fā)送到流中的下一個(gè) agent 或者設(shè)備存儲(chǔ)中(例如 HDFS)。只有事件已經(jīng)被存儲(chǔ)在下一個(gè) agent 的 channel 中 或設(shè)備存儲(chǔ)中時(shí),當(dāng)前 channel 才會(huì)清除該事件。這種機(jī)制保證了流在端到端的傳輸中具有可靠性。
Flume使用事務(wù)方法(transactional approach)來(lái)保證事件的可靠傳輸。在 source 和 slink 中,事件的存儲(chǔ)以及恢復(fù)作為事務(wù)進(jìn)行封裝,存放事件到 channel 中以及從 channel 中拉取事件均是事務(wù)性的。這保證了流中的事件在節(jié)點(diǎn)之間傳輸是可靠的。
可恢復(fù)
事件在 channel 中進(jìn)行,該 channel 負(fù)責(zé)保障事件從故障中恢復(fù)。Flume 支持一個(gè)由本地文件系統(tǒng)支持的持久化文件(文件模式:channel.type = "file") channel。同樣也支持內(nèi)存模式(channel.type = "memmory"),即將事件保存在內(nèi)存隊(duì)列中。顯然,內(nèi)存模式相對(duì)與文件模型性能會(huì)更好,但是當(dāng) agent 進(jìn)程不幸掛掉時(shí),內(nèi)存模式下存儲(chǔ)在 channel 中的事件將丟失,無(wú)法進(jìn)行恢復(fù)。
構(gòu)建
構(gòu)建一個(gè) agent
Flume agent 的配置保存在一個(gè)本地配置文件中。它是一個(gè) text 文本,java 程序可以直接方便地讀取其屬性。可以在同一配置文件中指定一個(gè)或多個(gè) agent 的配置。配置文件指定了 agnet 中每個(gè) source、channel、slink 的屬性,以及三者如何組合形成數(shù)據(jù)流。
配置單個(gè)組件
流中的每一個(gè)組件(source、channel、slink)都有自己的名稱、類型以及一系列配置屬性。例如,一個(gè) Avro source 需要配置 hostname (或者 IP 地址)以及端口號(hào)來(lái)接收數(shù)據(jù)。一個(gè)內(nèi)存模式 channel 可以有最大隊(duì)列長(zhǎng)度的屬性("capacity": channel 中最大容納多少事件)。一個(gè) HDFS slink 則需要知道文件系統(tǒng)的 URL(hdfs://****)、文件落地的路徑、文件回滾的評(píng)率("hdfs.rollInterval": 每隔多少秒將零時(shí)文件回滾成最終文件保存到 HDFS 中)。所有這些關(guān)于各個(gè)組件的屬性需要在配置文件中進(jìn)行指定。
將各個(gè)部分組合起來(lái)
Agent 需要知道加載哪些組件以及如何將這些組件組合起來(lái)形成數(shù)據(jù)流。Flume 指定每個(gè)組件的名稱(source、channel、slink),同時(shí)明確地告訴我們 channel 與 哪些 source 和 slink 連接,這樣各個(gè)組件就能組合起來(lái)。例如,一個(gè)叫 "avroWeb" 的 source 通過(guò)一個(gè)叫 "file-channel" 的channel 將事件傳遞到 HDFS sink 中。配置文件需包含這些組件的名稱以及組合關(guān)系。
開(kāi)始一個(gè) agent
我們可以通過(guò) Flume bin 目錄下的腳本文件(flume-ng)來(lái)啟動(dòng) agent。在命令后面,你需要指定 agent 的名稱、配置文件:
$ bin/flume-ng agent -n $agent_name -c conf -f conf/flume-conf.properties.template
運(yùn)行以上命令,agent 將會(huì)按照配置文件里描述的方式來(lái)運(yùn)行組件。
一個(gè)簡(jiǎn)單的示例
這里,我們給出一個(gè)配置文件的示例,該示例為 flume 單節(jié)點(diǎn)部署的配置方式。
# example.conf: A single-node Flume configuration
# Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1
# Describe/configure the source
a1.sources.r1.type = netcat
a1.sources.r1.bind = localhost
a1.sources.r1.port = 44444
# Describe the sink
a1.sinks.k1.type = logger
# Use a channel which buffers events in memory
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100
# Bind the source and sink to the channel
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1
看看這個(gè)配置文件,我們可以發(fā)現(xiàn)這個(gè) agent 的名稱是 a1。其中該 agent 的 source 監(jiān)聽(tīng) 44444 端口。channel 采用內(nèi)存模式,而 slink 直接輸出數(shù)據(jù)到 控制臺(tái)上(logger)。配置文件指定了各個(gè)組件的名稱,并描述了它們的類型以及其他屬性。當(dāng)然,一個(gè)配置文件可以配置多個(gè) agent 屬性,當(dāng)希望運(yùn)行指定 agent 進(jìn)程時(shí),我們需要在命令行中顯示的給出該 agent 的名稱:
$ bin/flume-ng agent --conf conf --conf-file example.conf --name a1 -Dflume.root.logger=INFO,console
注意,在實(shí)際部署中,我們通常會(huì)包含一個(gè)選項(xiàng): --conf-file = <conf-dir>。 <conf-dir> 目錄將包含一個(gè) shell 腳本 flume-env.sh 以及一個(gè) log4j 屬性文件。 在這個(gè)例子中,我們傳遞一個(gè) Java 選項(xiàng)來(lái)強(qiáng)制 Flume 將日志輸出到控制臺(tái)。
下面的例子中,我們可以遠(yuǎn)程 telnet 訪問(wèn) 44444 端口來(lái)向 agent 發(fā)送數(shù)據(jù):
$ telnet localhost 44444
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
Hello world! <ENTER>
OK
agent 進(jìn)程的控制臺(tái)將會(huì)打印通過(guò) telnet 發(fā)送的數(shù)據(jù):
12/06/19 15:32:19 INFO source.NetcatSource: Source starting
12/06/19 15:32:19 INFO source.NetcatSource: Created serverSocket:sun.nio.ch.ServerSocketChannelImpl[/127.0.0.1:44444]
12/06/19 15:32:34 INFO sink.LoggerSink: Event: { headers:{} body: 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 0D Hello world!. }
完成這一步,恭喜你已經(jīng)成功地配置以及部署一個(gè) flume agent。
數(shù)據(jù)獲取(Data ingestion)
Flume 支持許多從外部源獲取數(shù)據(jù)的機(jī)制。
RPC
一個(gè) Avro client 可以使用 rpc 機(jī)制發(fā)送指定的文件到 source 中:
$ bin/flume-ng avro-client -H localhost -p 41414 -F /usr/logs/log.10
上面的命令會(huì)將 /usr/logs/log.10 發(fā)送到監(jiān)聽(tīng) 41414 端口的 source 上。
網(wǎng)絡(luò)流(Network streams)
Flume 支持從一些流行的日志流中讀取數(shù)據(jù),例如:
- Avro
- Thrift
- Syslog
- Netcat
設(shè)置多 agent 流(Setting multi-agent flow)

Flume 支持將多個(gè) agent 串聯(lián)起來(lái),完成這項(xiàng)操作。
合并(Consolidation)
當(dāng)需要從眾多主機(jī)上收集日志信息時(shí),我們可以在每臺(tái)主機(jī)上部署 agent,這些主機(jī)的 slink 均連接到最終日志落地主機(jī)的 source 上。落地主機(jī)將所有數(shù)據(jù)進(jìn)行組合,落地到 HDFS 上。

