介紹
概述
Apache Flume是為有效收集聚合和移動大量來自不同源到中心數據存儲而設計的可分布,可靠的,可用的系統。
Apache Flume的用途不僅限于日志數據聚合。由于數據源是可定制的,Flume可用于傳輸大量事物數據包括但不限于網絡流量數據,社交媒體產生的數據,Email消息和很多其它類型的數據源。
Apache Flume是Apache軟件基金會的頂級項目之一。
現在有兩個版本可用(版本0.9.x和 1.x)
0.9.x版本的文檔在the Flume 0.9.x User Guide。
此文檔適用于1.4.x以后的版本。
新用戶和現有用戶鼓勵使用1.x版本,這樣可以利用最新的架構提高性能和靈活配置。
系統需要
- Java運行環境 - Java 1.7 or later
- 內存 - 足夠配置文件中設置的內存
- 磁盤大小 - 足夠配置文件中設置的磁盤大小
- 文件夾權限 - 可讀寫agent文件夾
架構
數據流模型
一個Flume事件定義為,一個Flume agent是一個JVM包含這些從源到目標的所有組建的進程。
Flume source消耗外部數據源(如web服務器)發送給它的事件。外部數據源以Flume source理解的格式發送給Flume事件。例如,一個avro flume源可以 接受從avro客戶端或者其他avro sink的 flume agent發送的avro事件。類似的流程也可以使用Thrift Flume Source接受來自Thrift Sink或者Flume Thrift Rpc客戶端或者以任何語言編寫的符合Flume thrift協議的Thrift客戶端。當Flume source接收到一個時間,會把事件存儲到一個或多個channels中。channel是一個被動存儲(保存事件直到有Flume sink消耗)。舉個例子文件類型的channel——受本地系統支持。sink從channel中移除事件并把它推送到外部存儲如HDFS(通過Flume HDFS sink)或者把他傳到流的下一個Flume agent source中。agent的source和sink異步操作存儲在channel中的事件。
復雜流
Flume允許用戶建立多節點流,這種流的事件通過多個agent到達目的地。它也支持扇入和扇出流,上下文路由和為失敗的節點備份路由。
可靠性
事件存儲在agent的channel中,然后被傳到流的下一個agent或終端存儲(如HDFS)。只有在他們被存儲在下一個agent的channel中或這終端存儲時才會被移除。這是Flume單個流的消息傳遞機制提供流端到端的可靠性。
Flume使用事務保證事件的可靠傳輸。sources和sinks分別封裝在storage/retrieval,channel提供事件。這保證事件集合在流中點到點之間可靠傳輸。在多節點流的情況下,sink有著上一點的契約source有下一節點的契約,保證數據安全存儲到下一個節點的channel中。
可恢復性
事件存儲在channel中,channel負責災難回復。Flume支持由本地文件系統提供的持久文件channel。內存channel只是簡單的把事件存儲在內存隊列中,內存channel更快,但在agent進程掛掉時仍在內存的事件不能恢復。
安裝
安裝一個agent
Flume agent的配置存在一個本地的配置文件中。這是一個遵循Java properties文件格式的文本文件。一個或多個agent配置可放在同一個配置文件里。配置文件包含agent的source,sink和channel的各個屬性以及他們的數據流連接。
配置獨立組件
每個流組件(source,sink或者channel)都有一個name,type和一系列的基于其type或實例的屬性。例如,一個avro source需要有個hostname(或者ip地址)一個端口號來接受數據。一個內存channel有最大隊列長度的屬性(capacity),一個HDFS sink需要知曉文件系統的URI地址創建文件,文件訪問頻率(“hdfs.rollInterval”)等等。所有的這些組件屬性都需要在Flume配置文件中設置。
連接各個組件
agent需要知道加載什么組件,以及這些組件在流中的連接順序。通過列出在agent中的source,sink和channel名稱,定義每個sink和source的channel來完成。例如,一個從avroWeb的avro source來的agent流事件通過文件channel到HDFS sink集群。這個配置文件會包含三個組建,文件channel作為avroweb source 和hdfs sink的共享channel。
啟動agent
使用bin目錄中的flume-ng腳本啟動agent,你需要在命令行指定agent名稱,配置文件目錄,和配置文件。
$ bin/flume-ng agent -n $agent_name -c conf -f conf/flume-conf.properties.template
現在agent將運行配置腳本中的source和sink。
一個簡單的例子
再次,我們給一個簡單的配置文件,描述一個單一節點的Flume開發。此配置文件使用戶生成事件并把日志輸出到控制臺。
# 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
此配置定義了一個名為a1的agent。a1有一個source監聽44444端口,一個channel在內存中緩存事件數據,一個sink把日志輸出到控制臺。配置文件給各個組建命名描述他們的類型和配置參數。一個配置文件可能定義多個命名agent,當啟動Flume進程是傳遞標志告訴它運行哪些agent。
給出這個配置文件,我們可以如下啟動Flume:
$ bin/flume-ng agent --conf conf --conf-file example.conf --name a1 -Dflume.root.logger=INFO,console
注意在完整的部署中,我們通常包含多個--conf=<conf-dir>選項。這個<conf-dir>目錄將包含多個一個flume-env.sh shell腳本和一個潛在的log4j屬性文件。在此例中,我們傳遞一個java選項把日志輸出到控制臺而不需要一個自定義的文件腳本。
從另一個接口,我們可以telnet 44444端口發送一個Flume事件:
$ telnet localhost 44444
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
Hello world! <ENTER>
OK
原始的Flume終端將輸出事件日志消息。
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!. }
祝賀你——你已經成功配置并部署了一個Flume agent!隨后的章節將涉及agent 配置的更多細節。
記錄原始數據
從管道里記錄原始的流數據不是許多生產環境所關心的行為,因為可能導致敏感信息泄露或安全相關的配置,如密鑰輸出到Flume日志。默認情況下,Flume不記錄這么多信息。另一方面,如果數據管道損壞,FLume會嘗試提供調試錯誤的線索。
一個調試事件管道錯誤的方法是設置額外的內存管道連接到日志sink,它會輸出所有的事件數據到Flume日志。有些情況,這種方法還不足夠。
為了記錄事件和配置相關數據,必須設置一些java系統屬性在log4j屬性文件中。
為了記錄配置相關日志,設置-Dorg.apache.flume.log.printconfig=true
Java系統屬性。此屬性可放在命令行中或者設置在flume-env.sh的JAVA_OPTS
變量中。
為了記錄數據,如上設置-Dorg.apache.flume.log.rawdata=true
Java系統屬性。對于大多數組件,log4j日志級別必須設置為DEBUG或TRACE似的event-specific日志出現在Flume記錄中。
這是一個設置配置日志和原始數據日志的例子。同時設置了Log4j的記錄級別為DEBUG:
$ bin/flume-ng agent --conf conf --conf-file example.conf --name a1 -Dflume.root.logger=DEBUG,console -Dorg.apache.flume.log.printconfig=true -Dorg.apache.flume.log.rawdata=true
基于Zookeeper的配置
Flume支持使用Zookeeper配置agent。這個是一個實驗特性。配置文件需要上傳到zookeeper中,在一個可配置前綴下。配置文件存儲在Zookeeper節點數據里。下面是a1 和 a2 agent在Zookeeper節點樹的配置情況。
- /flume
|- /a1 [Agent config file]
|- /a2 [Agent config file]
一旦上傳完配置文件,使用下面參數啟動agent。
$ bin/flume-ng agent –conf conf -z zkhost:2181,zkhost1:2181 -p /flume –name a1 -Dflume.root.logger=INFO,console
Argument Name | Default | Description |
---|---|---|
z | - | Zookeeper連接字符串.以逗號分割的hostname:port |
p | /flume | Zookeeper中存儲agent配置的根目錄 |
安裝第三方插件
Flume有完整的插件架構。當Flume通過source,channel,sink,serializer等組件,存在許多實現分割Flume。
始終可以使用flume-env.sh文件中的FLUME_CLASSPATH變量路徑添加自定義的Flume組件,Flume現在支持一個特殊的文件夾pluguins.d
自動獲得組件。這允許更簡單的插件包管理問題,更簡單的調試和錯誤定位,特別是依賴包的沖突。
plugins.d文件夾
plugins.d文件夾在$FLUME_HOME/plugins.d
。在啟動時,flume-ng
啟動腳本查看plugins.d
目錄文件,檢查符合一下格式的插件把它們導入到java路徑中。
插件目錄布局
plugins.d
中的每個插件都可以有三個子目錄:
- lib - 插件的jar包
- libext - 插件的依賴包
- native - 任何需要的本地庫文件,如
.so
文件。
下面是plugins.d
目錄中包含兩個插件的例子
plugins.d/
plugins.d/custom-source-1/
plugins.d/custom-source-1/lib/my-source.jar
plugins.d/custom-source-1/libext/spring-core-2.5.6.jar
plugins.d/custom-source-2/
plugins.d/custom-source-2/lib/custom.jar
plugins.d/custom-source-2/native/gettext.so
數據提取
Flume支持很多從外部數據源提取數據的機制。
RPC
包含在Flume分布式系統的一個Avro客戶端可以使用avro遠程方法調用發送一個給定的文件給Flume Avro source:
$ bin/flume-ng avro-client -H localhost -p 41414 -F /usr/logs/log.10
上面的命令將把/usr/logs/log.10文件內容傳遞到Flume source的監聽端口。
執行命令
有一個exec類型的 source執行一個給定的命令并消耗輸出(例如一個以\r
、\n
或\r\n
分隔的單獨line
)。
注意:Flume不支持tail
作數據源,可以把tail
封裝在exec source中傳輸文件
網絡流
Flume支持一下流行的日志流類型讀取數據機制,如:
- Avro
- Thrift
- Syslog
- Netcat
設置多agent流
為了在多個agent之間流動數據,前一個agent的sink和當前的source需要都是avro類型設置相同的hostname和port。
結合
日志收集的常見場景是大量的日志生成客戶端發送數據到少量的消費者agent存儲子系統。例如,日志從幾百個web服務器發送數據到十幾個agents然后存儲到HDFS集群。
這可以通過Flume配置許多avro sink第一層agent,
多路復用流
Flume支持多路復用事件流到一個或多個目的地。這是通過定義一個flow multiplexer來實現的,它可以復制或選擇事件流到一個或多個channels。
上面的示例展示了從一個foo agent扇出流到多個channels中。這種扇出可以復制或選擇。在復制流的情況下,每個事件都被發送到所有的channels中。在選擇的情況下,如果一個事件被發送到一些channels中,當一個事件的屬性匹配一個預先配置的值。例如,如果一個事件的屬性
txnType
設置為customer
,name他會去channel1和channel3,如果設置為vendor
,會去channel2,否則去channel3。這種映射可以在agent的配置文件中設置。
配置
之前章節提到,Flume agent的配置是從一個類似Java多層次屬性文件格式的文件中提取的。
定義流
使用單一的agent定義流,你需要使用channel連接source和sink。需要列出給定agent的source,sink和channel,然后指定source和sink到一個channel。一個source可以指定多個channels而一個sink只能指定一個channel。格式如下:
# list the sources, sinks and channels for the agent
<Agent>.sources = <Source>
<Agent>.sinks = <Sink>
<Agent>.channels = <Channel1> <Channel2>
# set channel for source
<Agent>.sources.<Source>.channels = <Channel1> <Channel2> ...
# set channel for sink
<Agent>.sinks.<Sink>.channel = <Channel1>
例如,一個名為agent_foo的agent從外部avro客戶端讀取數據然后通過內存channel發送到HDFS。配置文件weblog.config可能如下所示:
# list the sources, sinks and channels for the agent
agent_foo.sources = avro-appserver-src-1
agent_foo.sinks = hdfs-sink-1
agent_foo.channels = mem-channel-1
# set channel for source
agent_foo.sources.avro-appserver-src-1.channels = mem-channel-1
# set channel for sink
agent_foo.sinks.hdfs-sink-1.channel = mem-channel-1
這可以使事件流通過mem-channel-1從avro-AppSrv-source到hdfs-Cluster1-sink。當agent從weblog.config配置文件開始,將會實例化這個流。
配置單獨的組件
定義流后,你需要每個source,sink和channel的屬性。你設置組件類型和其他的指定組件的屬性,是使用相同的層次命名格式完成的。
# properties for sources
<Agent>.sources.<Source>.<someProperty> = <someValue>
# properties for channels
<Agent>.channel.<Channel>.<someProperty> = <someValue>
# properties for sinks
<Agent>.sources.<Sink>.<someProperty> = <someValue>
每個組件的·type·屬性都要設置為Flume能理解的類型。每個source,sink和channel類型都有它們自己需要的屬性和功能集合。在需要的情況這些都需要設置,前一個例子中,我們有一個使用內存channel mem-channel-1從avro-AppSrv-source到hdfs-Cluster1-sink的流。這是展示每個組件的配置的例子:
agent_foo.sources = avro-AppSrv-source
agent_foo.sinks = hdfs-Cluster1-sink
agent_foo.channels = mem-channel-1
# set channel for sources, sinks
# properties of avro-AppSrv-source
agent_foo.sources.avro-AppSrv-source.type = avro
agent_foo.sources.avro-AppSrv-source.bind = localhost
agent_foo.sources.avro-AppSrv-source.port = 10000
# properties of mem-channel-1
agent_foo.channels.mem-channel-1.type = memory
agent_foo.channels.mem-channel-1.capacity = 1000
agent_foo.channels.mem-channel-1.transactionCapacity = 100
# properties of hdfs-Cluster1-sink
agent_foo.sinks.hdfs-Cluster1-sink.type = hdfs
agent_foo.sinks.hdfs-Cluster1-sink.hdfs.path = hdfs://namenode/flume/webdata
#...
添加在一個agent里添加多個流
一個Flume agent可以包含多個獨立流。你可以在一個配置文件列出多個sources,sinks和channels。這些組件可以同多個流連接。
# list the sources, sinks and channels for the agent
<Agent>.sources = <Source1> <Source2>
<Agent>.sinks = <Sink1> <Sink2>
<Agent>.channels = <Channel1> <Channel2>
然后你可以使用相應的channels連接sources和links設置兩個不同的流。例如,你需要在一個agent中設置兩個流,一個從外部的avro客戶端到外部的HDFS系統另外一個從外部的tail
命令輸出到avro sink,有一個配置文件可以做到:
# list the sources, sinks and channels in the agent
agent_foo.sources = avro-AppSrv-source1 exec-tail-source2
agent_foo.sinks = hdfs-Cluster1-sink1 avro-forward-sink2
agent_foo.channels = mem-channel-1 file-channel-2
# flow #1 configuration
agent_foo.sources.avro-AppSrv-source1.channels = mem-channel-1
agent_foo.sinks.hdfs-Cluster1-sink1.channel = mem-channel-1
# flow #2 configuration
agent_foo.sources.exec-tail-source2.channels = file-channel-2
agent_foo.sinks.avro-forward-sink2.channel = file-channel-2
配置一個多agent流
設置一個多層流,你需要有一個avro/thrift sink到一個avro/thrift source。這會把第一個flume agent結果轉發下一個flume agent中。例如,如果你定期的使用avro客戶端傳遞文件到本地的flume agent中,那么這個本地的agent可以轉發到另一個agent中存儲。
Weblog agent 配置:
# list sources, sinks and channels in the agent
agent_foo.sources = avro-AppSrv-source
agent_foo.sinks = avro-forward-sink
agent_foo.channels = file-channel
# define the flow
agent_foo.sources.avro-AppSrv-source.channels = file-channel
agent_foo.sinks.avro-forward-sink.channel = file-channel
# avro sink properties
agent_foo.sources.avro-forward-sink.type = avro
agent_foo.sources.avro-forward-sink.hostname = 10.1.1.100
agent_foo.sources.avro-forward-sink.port = 10000
# configure other pieces
#...
HDFS agent配置:
# list sources, sinks and channels in the agent
agent_foo.sources = avro-collection-source
agent_foo.sinks = hdfs-sink
agent_foo.channels = mem-channel
# define the flow
agent_foo.sources.avro-collection-source.channels = mem-channel
agent_foo.sinks.hdfs-sink.channel = mem-channel
# avro sink properties
agent_foo.sources.avro-collection-source.type = avro
agent_foo.sources.avro-collection-source.bind = 10.1.1.100
agent_foo.sources.avro-collection-source.port = 10000
# configure other pieces
#...
此處我們連接weblogagent的the avro-forward-sink到hdfs agent的avro-collection-source。這將會使來自外部appserver的事件最終存儲在HDFS系統。
扇出流
前一節討論過,Flume支持從一個source到多個channels的扇出流。有兩種模式的扇出方式:重復
和多路選擇
。在重復流中,事件被發送到配置的channels中。在多路選擇中,事件被發送到匹配的channels。為了實現扇出流,需要指定一個source的channels列表和定義扇出規則。這是通過添加一個selector
的channel,其支持重復和多路選擇。如果是多路選擇還要指定選擇的規則。如果你不定義一個selector,默認是重復。
# List the sources, sinks and channels for the agent
<Agent>.sources = <Source1>
<Agent>.sinks = <Sink1> <Sink2>
<Agent>.channels = <Channel1> <Channel2>
# set list of channels for source (separated by space)
<Agent>.sources.<Source1>.channels = <Channel1> <Channel2>
# set channel for sinks
<Agent>.sinks.<Sink1>.channel = <Channel1>
<Agent>.sinks.<Sink2>.channel = <Channel2>
<Agent>.sources.<Source1>.selector.type = replicating
多路選擇有更多的分叉流屬性。需要為channel設置映射事件屬性。選擇器檢查每個事件頭的配置屬性。如果陪陪指定的值,就會把事件發送給所有匹配的channel。如果沒有匹配的,事件會被發送到默認配置的channel。
# Mapping for multiplexing selector
<Agent>.sources.<Source1>.selector.type = multiplexing
<Agent>.sources.<Source1>.selector.header = <someHeader>
<Agent>.sources.<Source1>.selector.mapping.<Value1> = <Channel1>
<Agent>.sources.<Source1>.selector.mapping.<Value2> = <Channel1> <Channel2>
<Agent>.sources.<Source1>.selector.mapping.<Value3> = <Channel2>
#...
<Agent>.sources.<Source1>.selector.default = <Channel2>
映射允許每個channel值的覆蓋。
下面的例子有一個流選擇到兩條路徑。名為agent_too
的agent有一個avro source和兩個連接到兩個sinks的channels。
# list the sources, sinks and channels in the agent
agent_foo.sources = avro-AppSrv-source1
agent_foo.sinks = hdfs-Cluster1-sink1 avro-forward-sink2
agent_foo.channels = mem-channel-1 file-channel-2
# set channels for source
agent_foo.sources.avro-AppSrv-source1.channels = mem-channel-1 file-channel-2
# set channel for sinks
agent_foo.sinks.hdfs-Cluster1-sink1.channel = mem-channel-1
agent_foo.sinks.avro-forward-sink2.channel = file-channel-2
# channel selector configuration
agent_foo.sources.avro-AppSrv-source1.selector.type = multiplexing
agent_foo.sources.avro-AppSrv-source1.selector.header = State
agent_foo.sources.avro-AppSrv-source1.selector.mapping.CA = mem-channel-1
agent_foo.sources.avro-AppSrv-source1.selector.mapping.AZ = file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.mapping.NY = mem-channel-1 file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.default = mem-channel-1
選擇器檢查每個State的頭。如果值是CA
就發送到mem-channel-1,如果是AZ
就到file-channel-2如果是NY
就兩個都發。如果State頭沒有設置或者都不匹配,將會發送到默認的mem-channel-1。
選擇器也支持可選的channel。為了指定可選channel,配置參數optional
如下使用:
# channel selector configuration
agent_foo.sources.avro-AppSrv-source1.selector.type = multiplexing
agent_foo.sources.avro-AppSrv-source1.selector.header = State
agent_foo.sources.avro-AppSrv-source1.selector.mapping.CA = mem-channel-1
agent_foo.sources.avro-AppSrv-source1.selector.mapping.AZ = file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.mapping.NY = mem-channel-1 file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.optional.CA = mem-channel-1 file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.mapping.AZ = file-channel-2
agent_foo.sources.avro-AppSrv-source1.selector.default = mem-channel-1
選擇器首相嘗試發送到必須的channel中,如果有channel消費事件失敗,事務失敗。食物將再次嘗試發送到所有的channels中。如果所有的必須channels都消費了事物。那么選擇器試圖發送給可選的channel。可選channel消費事件的失敗簡單忽略不會導致重發。