Apache Flume 性能調優 (第一部分)
Apache Flume,是一個分布式的、可靠的、高可用的服務,用于收集、聚合、傳輸大量的事件型數據的應用組件。本篇文章是關于Apache Flume性能調優系列文章的第一部分。
在這篇文章中,我們將要討論Flume調優時的兩個基本概念:通道(Channel)和事務Batch Size(transaction batch Size)。
本文中的中文術語與英文術語對照:
Event : 事件
Channel : 通道
構建一個數據流
假設你希望將一個海量的流式的用戶行為日志從你的應用服務器中提取出來并存儲到Hadoop進行分析。這些日志來自于你已有的應用服務器集群,并且構建一個將大量節點的數據匯總到少數幾個節點的fan-in 架構 。
如果你將這些用戶事件每次發送一條,而且每次都需要等待這些事件送達,你的吞吐量很可能會非常受限于網絡延遲。自然,你希望將多個事件打包為一個事務,這樣事務確認的開銷就會攤薄到批量事務中的每一個事件,這樣可以大大的提高你的吞吐量。
通道(Channels)
下面,想象一下如果存儲層突然停止工作,比如存儲層網絡分區離線的時候會發生什么?如果Flume agent掛掉, 那些事件會怎么樣? 即使發生了這些故障,我們也希望通過某種方法繼續在應用層繼續服務我們的用戶,并且在服務恢復時可以恢復這些數據。為了達到這個目的,我們需要為agent建立一個緩沖機制來預防下游服務可能出現的緩慢和宕機。 在Flume中,通道就是事件在數據流中的跳板。 下面的圖向你說明了通道在Flume Agent架構中的位置。
內存通道與文件通道的對比
當設計Flume系統時,一個重要的選擇就是使用什么類型的通道(Channel)。在本文中,主要向你推薦兩種通道,即文件通道(File Channel) 與 內存通道(Memory Channel)。 文件通道是一個持久化的通道,它將所有的事件都持久化到硬盤中。所以,即使JVM被殺掉,操作系統重啟或宕機,沒有被傳輸到下一個數據處理流程的事件將在flume agent重啟時被恢復。內存通道是一個易失通道,它僅在內存中存儲事件,如果JVM被殺掉或者操作系統宕機,所有儲存在內存中的數據都會丟失,當然,與文件通道相比,內存通道也提供了更低的讀寫延遲,即使事件的Batch Size只有1。 由于在內存通道的容量受限于內存, 所以如果下游服務發生臨時失敗,它緩存的能力也非常有限。 而文件通道,由于硬盤空間一般比內存大得多且廉價得多,所以它可以緩存事件的能力也要比內存通道強得多。
Flume 事件的批量處理
在上文中提到,Flume可以批量處理事件。 Batch Size是Sink或者客戶端單次事務可以從通道中取得事件的最大值。調低Batch Size參數,會造成吞吐量的降低,但同時也降低了失敗時,發生事件多重記錄的風險。 調高Batch Size參數,可以顯著提高吞吐量,也會增加延遲,但是如果發生宕機,發生事件重復記錄的風險也會相應的變高。
事務(Transaction)在Flume中是一個重要概念,因為只有在后面的每一個事務都成功的時候,可靠存儲與送達才有保證。舉個例子來說,當數據源接收到或者生產了一條事件, 為了將事件存儲到通道,首先它必須先打開通道。在事務中, 數據源將Batch Size數量的事件送入通道中,然后才確認已經提交了事務。 Sink端需要經過同樣的過程,才能從通道中提取事件。
Batch Size 是由Sink配置的。Batch Size越大, Channel也就越快。 文件通道的速度差異主要體現在它必須將緩沖區完全同步到硬盤時,事務才算成功提交。 硬盤同步本身就是一個非常耗時的操作(百毫秒級別),因為它要保證數據的可靠性。同樣內存通道中每一個事務的提交也需要在內存中進行同步,不過在內存中這樣的操作要比硬盤要快得多了。 如果你想了解更多文件通道的技術內幕,可以去看Brock Noland 的article about the Apache Flume File Channel。
使用大的Batch Size還有一個不好的地方,如果在事務傳輸中發生了失敗,比如下游主機掛掉或者網絡斷開,會有一定的可能性發生數據重復。 舉個例子,如果你的Batch Size是1000,而且你的下游機器離線了,那么可能就會發生大小為1000的數據重復。 這種情況的發生有幾種可能,舉個例子,如果事件已經寫入了下游機器,在下游機器告知事務成功之前恰巧發生了連接斷開,那么就會出現數據重復。然而你并不太需要憂心這一點,因為這只會發生在極其特殊的情況下。
選擇一個適當的Batch Size
為了盡可能的壓榨Flume系統的性能, Batch Size 多次實驗并小心選擇。
再詳細探討Batch Size的選擇之前, 下面有幾條原則請大家參考:
-
Sink的 Batch Size 應該等于輸入流 Batch Size 的和。舉個例子,如果你有一個 flume agent, 上游的10個Flume agent通過avro以100的batch Size 向這個agent發送事件,那么這個agent的batch Size 就應該設置為10X100 = 1000。
-
如果你發現你需要將Batch Size設置的非常大,比如比10000還大,那么需要考慮多設置幾個channel來提高并發性(每一個channel都有一個自己的線程)。 實踐中, 使用一個batch Size 為20000的HDFS Sink的性能要比 使用 兩個batch Size 為10000的channel 性能要差。
-
在性能可接受的情況下,盡量選擇較小的Batch Size。
-
為了做更詳細的性能調優,要對channel做一些監控,例如Channel Size參數。(這個會在下一篇文章中講到)
不同情況下的不同Batch Size
由于Batch Size涉及到 性能/重復的權衡,我通常在不同應用場景下選用不同的batch Size。比如使用Flume 的HBase Sink ,經常采用100的Batch Size來降低系統的延遲。 而使用HDFS Sink的時候, 我就見到許多人使用10000的Batch Size來提高系統的吞吐,因為他們可以在接下來的MapReduce將重復的數據剔除掉。 值得注意的是, 當使用HDFS Sink且用以一個比較大的Batch Size的時候, 一些其他的參數也需要相應的提高。其中一個參數就是hdfs.callTimeout, 它或許需要提高到60s或更高來預防HDFS偶爾的慢響應。
另一方面,為了獲取最佳性能,實踐上會在收集端將Batch Size配置為1,channel也會配置為內存通道。并在下游的Flume Agent中配置比較大的Batch Size和文件通道,來獲取更好的性能和可靠性保證。 為了獲得更好的性能, 任意一層(包括應用層)都可以做一些盡可能的批量處理。
配置參數與陷阱
實際上我們在sink端配置的都是Batch Size,但是它們不一定叫同一個名。 對于HDFS來說,它的實際叫hdfs.batchSize(由于一些歷史原因)。 為了讓大家更好理解,我曾經建議叫hdfs.txnEventMax 。 由于歷史原因,HDFS Sink,從單個事務中提取的事件數和單次寫入到HDFS的事件數不是同一個參數。實踐上,確實有一些小原因這兩個參數不應該設置為同一個值。
一個可能令人迷惑的陷阱就是sink 的 Batch Size 必須小于或等于 相應Channel 的 transactionCapacity . transactionCapacity 應該設置為從這個channel中一次提取事件的最大值。
下面是一個表格, 包括了Sink類型 、 配置參數 和 典型值。
Sink Type | Config parameter | Typical value |
---|---|---|
Avro | batch-size | 100 |
HDFS | hdfs.batchsize, hdfs.txnEventMax | 1000 |
HBaseSink | batchSize | 1000 |
AsyncHBaseSink | batchSize | 100 |
來自: http://myg0u.com/hadoop/2016/05/04/flume-performance-tuning-part-1.html