Flume+HDFS實戰及遇到的坑

Flume Source組件實戰—Avro、Spool、Exec(詳細圖文)》一文中,我們介紹了集中不同的Source 組件的使用方式,Source監控取到的數據大多數都是通過LoggerSink輸出Cli端界面上,並沒有將這些數據真正下沉落地,那麼這裏LoggerSink記錄INFO級別的日誌,一般多數用來進行系統調試。在本文中,我們將着重介紹在生產環境中常用的sink組件:HDFS Sink

Flume Sink的目的是從Flume Channel中獲取數據然後輸出到存儲或者其他Flume Source中。Flume Agent啓動的時候,它會爲每一個Sink都啓動一個SinkRunner的對象,SinkRunner.start()方法會啓動一個新的線程去管理每一個Sink的生命週期。每一個Sink需要實現start()、Stop()和process()方法。本文只是例舉幾個Sink而已,Flume本身含有豐富的Source 和Sink組件,並且支持隨意組合,只要你按照配置的規則來生產數據、傳輸數據即可,使用非常方便。

HDFS Sink 實戰

在本節我們要實現Flume實時監測日誌文件,並將新增的日誌數據寫入到HDFS文件中

讀其名可知,HDFS Sink就是Sink將從Channel中get到的時間寫入到Hadoop分佈式文件系統HDFS,從而完成日誌文件的持久化操作。目前Flume支持創建文本文件和序列化文件,這些文件可以按照指定的時間或數據量或事件的數量爲基礎進行存放,HDFS的目錄路徑可以包含將要由HDFS替換格式的轉移序列用以生成存儲事件的目錄/文件名。agent從WebServer拿到數據之後再存放到HDFS,整個過程如下圖所示:

1、添加配置文件內容  cd /usr/flume/conf  在conf目錄下,將我們之前寫的exec.conf直接copy過來進行修改即可,cp exec.conf exec_hdfs_sink.conf,增加以下內容:

#example.conf: A single-node flume configuration
#use hdfsSink 

#Name the components on this agent
a1.sources = r1
a1.sinks = k1
a1.channels = c1

#配置source
a1.sources.r1.type = exec
a1.sources.r1.command = tail -F /usr/flume/logs/exec_tail_test.log
a1.sources.r1.channels = c1

#配置HDFS sink
a1.sinks.k1.type = hdfs
a1.sinks.k1.hdfs.type = hdfs://master:9000/flume/data/logs/
a1.sinks.k1.hdfs.fileType = DataStream
a1.sinks.k1.hdfs.writeFormat = TEXT
#設置輸出文件的前綴
a1.sinks.k1.hdfs.filePrefix = flumeHdfs
#設置輸出文件的後綴
a1.sinks.k1.hdfs.fileSuffix = .log
a1.sinks.k1.hdfs.batchSize = 1000
a1.sinks.k1.hdfs.rollSize = 10240
a1.sinks.k1.hdfs.rollCount = 0
a1.sinks.k1.hdfs.rollInterval = 1
a1.sinks.k1.hdfs.useLocalTimeStamp = true

#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

參數解釋,但這三個參數都不是必須的,如不明確指定,Flume有默認給定值:

  • a1.sinks.k1.hdfs.rollSize = 10240  //設置文件大小,當文件達到一定大小才傳輸(默認爲1024字節)
  • a1.sinks.k1.hdfs.rollCount = 0  //設置接收的時間數目,當文件寫滿指定數量之後傳輸(默認10個事件)
  • a1.sinks.k1.hdfs.rollInterval = 1  //設置文件間隔多久發送,時間越長,獲取內容越多(默認30s),但是這個值不能設置爲0,否則flume在連接hdfs時會報超時連接的error,導致程序反覆在重連,cli界面處於等到狀態,如下圖:

2、啓動。使用命令,啓動flume agent。注意:在啓動之前我們首先要啓動hadoop,很多人在使用的時候直接運行了start-all.sh命令啓動了yarn和hdfs,其實沒必要,我們只需要start-dfs.sh 啓動分佈式文件系統HDFS即可,還可節約VM的資源佔用。

[root@master ~]# flume-ng agent -n a1 -c /usr/flume/conf/ --conf-file /usr/flume/conf/exec_hdfs_sink.conf -Dflume.root.logger=INFO,console 

3、成功啓動之後,如下所示,系統程序界面會一直處於監控狀態,監控該命令下文件是否出現變動,從上面的日誌信息可以看出,相關組件進程均已成功啓動。

4、因爲這裏我們選用的Source組價是Exec Source,監控的命令是tail -F /usr/flume/logs/exec_tail_test.log,在本次實驗之前,我們logs文件夾下不含有exec_tail_test.log文件,因此我們首先先創建一個並寫入下面圖片中的測試內容,vi /usr/flume/logs/exec_tail_test.log

在點擊保存文件之後,會發現agent的界面會出現連接hdfs,並創建我們在配置文件中設定好的文件路徑、文件名稱等。注:在實驗中我們發現,配置文件中設定的HDFS目錄,並不需要提前創建好然後賦成777權限,如果hdfs中不存在此文件夾,Flume會自行創建。如下圖所示。

5、登錄master:50070端口,去查看HDFS的目錄結構,並確認是否已經寫入我們測試的內容:

從上圖我們可以看出,不管是文件夾還是寫出的文件都已創建好,再查看一下文件的內容:hadoop fs -cat /flume/logs/flumeHdfs.1544687430036.log

可以看出測試內容已經全部寫入,HDFS Sink測試成功。

測試時錯誤:

當向檢測文件添加數據時,採用命令echo命令循環生成100+條數據,會報以下錯誤,提示Channel的Memo已經滿了

[root@master logs]# for i in {1..121};do echo "$i new insert data" >> exec_tail_test.log;done  

再去HDFS的文件系統上查看目錄,會發現ChannelSize沒有減少,hdfs裏的數據也一直在重複被寫入,但是前臺界面報錯,肯定不符合生產需要。於是我們開始看配置文件,發現我們的a1.channels.c1.transactionCapacity = 100,發現這個值設置成了100,而我們要同時寫入超過100條的數據,因此會產生channel隊列滿了的錯誤。

於是查閱資料,把整個問題都解決,發現這個錯誤關乎三個參數:channels.capacity 、channels.transactionCapacity 、sinks.hdfs.batchSize ;事情的真相原來是這樣,這個Channels的capacity是指整個隊列的緩存最大容量,transactionCapacity則是指事務event的最大容量,即每次傳輸的event最大爲多少,而這個sink的batchsize是什麼意思呢,就是sink會一次從channel中取多少個event去發送,而這個發送是要最終以事務的形式去發送的,因此這個batchsize的event會傳送到一個事務的緩存隊列中(takeList),這是一個雙向隊列,這個隊列可以在事務失敗時進行回滾(也就是把取出來的數據吐memeryChannel的queue中),它的初始大小就是transactionCapacity定義的大小,源碼中有: takeList = new LinkedBlockingDeque<Event>(transCapacity); 上面的錯誤的原因就是,本來隊列的最大容量只有100,而我想一次去121個events塞到takeList中。從上述分析中可知,三個參數容量大小應該是:capacity>transactionCapacity>batchSize ;因此,要是想同時將測試用例的121條數據成功寫入到hdfs的話,應該將transactionCapacity的值設置的稍微大一些,後來本小廚改成了500。

flume產生大量小文件的解決方法

從上面的HDFS的目錄結構可以看出,HDFS的block塊大小爲128M,但是每次不滿1k就輸出到第二個文件中,我們可以用兩種方法控制:第一控制輸出文件的大小a1.sinks.k1.hdfs.rollSize = 10240,這裏設置的是10M,但是每到10M就輸出了,是因爲我們下面設置的時間爲1s輸出一次;第二個就是通過控制輸出時間,a1.sinks.k1.hdfs.rollInterval = 1,可以將時間延長一些。

總結

在使用Source Channel Sink組合時,要特別注意各個參數的配合使用。本例中,我們使用的是Exec Source ,要是使用spool Source基本流程也是一樣,只需更改配置文件中的Source組件定義,如下:

a1.sources.r1.channels = c1
a1.sources.r1.type = spooldir
a1.sources.r1.spoolDir = /usr/flume/logs
a1.sources.r1.fileHeader = false

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章