頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

個推2018發表於2020-05-09

引言

如何在有限的資源下解決效能瓶頸問題是運維永恆的痛點。這期文章,Mr.Tech 邀請了在效能最佳化方面有著豐富經驗的個推高階運維工程師白子畫,為大家分享寬頻最佳化之Flume Avro在個推的實踐。

在異地日誌資料互傳的場景下,我們從傳輸資料著手,藉助Avro的特性使資料壓縮率達80%以上,解決了個推在實際生產過程中遇到的頻寬不夠用的問題。 本文我們將向大家介紹Flume Avro在資料傳輸過程中所承擔的不同角色,以及如何保證資料的完整性和傳輸的高效性,並分享在實際業務中取得的最佳化效果。

頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

作者 個推高階運維工程師  白子畫

背景

個推作為專業的資料智慧服務商,已經成功服務了數十萬APP,每日的訊息下發量達百億級別,由此產生了海量日誌資料。為了應對業務上的各種需求,我們需要採集並集中化日誌進行計算,為此個推選用了高可用的、高可靠的、分散式的Flume系統以對海量日誌進行採集、聚合和傳輸。此外,個推也不斷對Flume進行迭代升級,以實現自己對日誌的特定需求。

原有的異地機房日誌匯聚方式,整個流程相對來說比較簡單,A機房業務產生的日誌透過多種方式寫入該機房Kafka叢集,然後B機房的Flume透過網路專線實時消費A機房Kafka的日誌資料後寫入本機房的Kafka叢集,所有機房的資料就是透過相同方式在B機房Kakfa叢集中集中化管理。如圖一所示:


頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

圖一:原有異地日誌傳輸模式

但是隨著業務量的不斷增加,日誌資料在逐漸增多的過程中對頻寬要求變高,頻寬的瓶頸問題日益凸顯。按照1G的專線頻寬成本2~3w/月來計算,一個異地機房一年僅專線頻寬擴容成本就高達30w以上。對此,如何找到一種成本更加低廉且符合當前業務預期的傳輸方案呢?Avro有快速壓縮的二進位制資料形式,並能有效節約資料儲存空間和網路傳輸頻寬,從而成為優選方案。

最佳化思路

Avro簡介

Avro是一個資料序列化系統。它是Hadoop的一個子專案,也是Apache的一個獨立的專案,其主要特點如下:

● 豐富的資料結構;

● 可壓縮、快速的二進位制資料型別;

● 可持久化儲存的檔案型別;

● 遠端過程呼叫(RPC);

● 提供的機制使動態語言可以方便地處理資料。

具體可參考官方網站:

Flume Avro方案

Flume的RPC Source是Avro Source,它被設計為高擴充套件的RPC服務端,能從其他Flume Agent 的Avro Sink或者Flume SDK客戶端,接收資料到Flume Agent中,具體流程如圖二所示:

頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

圖二:Avro Source流程

針對該模式,我們的日誌傳輸方案計劃變更為A機房部署Avro Sink用以消費該機房Kafka叢集的日誌資料,壓縮後傳送到B機房的Avro Source,然後解壓寫入B機房的Kafka叢集,具體的傳輸模式如圖三所示:

頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

圖三:Flume Avro傳輸模式

可能存在的問題

我們預估可能存在的問題主要有以下三點:

● 當專線故障的時候,資料是否能保證完整性;

● 該模式下CPU和記憶體等硬體的消耗評估;

● 傳輸效能問題。

驗證情況

針對以上的幾個問題,我們做了幾項對比實驗。

環境準備情況說明:

1. 兩臺伺服器192.168.10.81和192.168.10.82,以及每臺伺服器上對應一個Kakfa叢集,模擬A機房和B機房;

2.   兩個Kafka叢集中對應topicA(源端)和topicB(目標端)。在topicA中寫入合計大小11G的日誌資料用來模擬原始端日誌資料。

3.   192.168.10.82上部署一個Flume,模擬原有傳輸方式。

4.  192.168.10.81伺服器部署Avro Sink,192.168.10.82部署Avro Source,模擬Flume Avro傳輸模式。

原有Flume模式驗證(非Avro)

 監控Kafka消費情況:


頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

 81流量統計:


頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

  82流量統計:


頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

消費全部訊息耗時:20min

消費總日誌條數統計:129,748,260

總流量:13.5G

Avro模式驗證

 配置說明:

Avro Sink配置:

#kafkasink 是kafkatokafka的sinks的名字,可配多個,空格分開kafkatokafka.sources = kafka_dmc_bulletkafkatokafka.channels = channel_dmc_bulletkafkatokafka.sinks = kafkasink_dmc_bulletkafkatokafka.sources.kafka_dmc_bullet.type = org.apache.flume.source.kafka.KafkaSourcekafkatokafka.sources.kafka_dmc_bullet.channels = channel_dmc_bulletkafkatokafka.sources.kafka_dmc_bullet.zookeeperConnect =192.168.10.81:2181kafkatokafka.sources.kafka_dmc_bullet.topic = topicAkafkatokafka.sources.kafka_dmc_bullet.kafka.zookeeper.connection.timeout.ms =150000kafkatokafka.sources.kafka_dmc_bullet.kafka.consumer.timeout.ms =10000kafkatokafka.sources.kafka_dmc_bullet.kafka.group.id = flumeavrokafkatokafka.sources.kafka_dmc_bullet.batchSize =5000#source kafkasink_dmc_bullet的配置,可配置多個sink提高壓縮傳輸效率kafkatokafka.sinks.kafkasink_dmc_bullet.type = org.apache.flume.sink.AvroSinkkafkatokafka.sinks.kafkasink_dmc_bullet.hostname =192.168.10.82kafkatokafka.sinks.kafkasink_dmc_bullet.port =55555//與source的rpc埠一一對應kafkatokafka.sinks.kafkasink_dmc_bullet.compression-type = deflate//壓縮模式kafkatokafka.sinks.kafkasink_dmc_bullet.compression-level =6//壓縮率1~9kafkatokafka.sinks.kafkasink_dmc_bullet.channel = channel_dmc_bulletkafkatokafka.sinks.kafkasink_dmc_bullet.channel = channel_dmc_bulletkafkatokafka.sinks.kafkasink_dmc_bullet.requiredAcks =1kafkatokafka.sinks.kafkasink_dmc_bullet.batchSize =5000#source kafkasink_dmc_bullet配的channel,只配一個kafkatokafka.channels.channel_dmc_bullet.type = memorykafkatokafka.channels.channel_dmc_bullet.capacity =100000#kafkatokafka.channels.channel_dmc_bullet.byteCapacity = 10000#kafkatokafka.channels.channel_dmc_bullet.byteCapacityBufferPercentage = 10kafkatokafka.channels.channel_dmc_bullet.transactionCapacity =5000kafkatokafka.channels.channel_dmc_bullet.keep-alive =60

Avro Source配置:

#kafkasink 是kafkatokafka的sinks的名字,可配多個,空格分開kafkatokafka.sources = kafka_dmc_bulletkafkatokafka.channels = channel_dmc_bulletkafkatokafka.sinks = kafkasink_dmc_bulletkafkatokafka.sources.kafka_dmc_bullet.type= avrokafkatokafka.sources.kafka_dmc_bullet.channels = channel_dmc_bulletkafkatokafka.sources.kafka_dmc_bullet.bind =0.0.0.0kafkatokafka.sources.kafka_dmc_bullet.port =55555//rpc埠繫結kafkatokafka.sources.kafka_dmc_bullet.compression-type= deflate//壓縮模式kafkatokafka.sources.kafka_dmc_bullet.batchSize =100#source kafkasink_dmc_bullet的配置kafkatokafka.sinks.kafkasink_dmc_bullet.type= org.apache.flume.sink.kafka.KafkaSinkkafkatokafka.sinks.kafkasink_dmc_bullet.kafka.partitioner.class = com.gexin.rp.base.kafka.SimplePartitionerkafkatokafka.sinks.kafkasink_dmc_bullet.channel = channel_dmc_bulletkafkatokafka.sinks.kafkasink_dmc_bullet.topic = topicBkafkatokafka.sinks.kafkasink_dmc_bullet.brokerList =192.168.10.82:9091,192.168.10.82:9092,192.168.10.82:9093kafkatokafka.sinks.kafkasink_dmc_bullet.requiredAcks =1kafkatokafka.sinks.kafkasink_dmc_bullet.batchSize =500kafkatokafka.channels.channel_dmc_bullet.type= memorykafkatokafka.channels.channel_dmc_bullet.capacity =100000kafkatokafka.channels.channel_dmc_bullet.transactionCapacity =1000

監控Kafka消費情況


頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

81流量統計:


頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

82流量統計:


頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

消費全部訊息耗時:26min

消費總日誌條數統計:129,748,260

總流量:1.69G

故障模擬

1.   模擬專線故障,在A、B兩機房不通的情況下,Avro Sink報錯如下:

頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

2. 監控Kafka消費情況,發現消費者已停止消費:

頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

3. 故障處理恢復後繼續消費剩餘日誌,經統計,總日誌條數為:129,747,255。

結論

1.   當專線發生故障時,正在網路傳輸中的通道外資料可能會有少部分丟失,其丟失原因為網路原因,與Avro模式無關;故障後停止消費的資料不會有任何的丟失問題,由於網路原因丟失的資料需要評估其重要性以及是否需要補傳。

2.   流量壓縮率達80%以上,同時我們也測試了等級為1~9的壓縮率,6跟9非常接近,CPU和記憶體的使用率與原有傳輸模式相差不大,頻寬的最佳化效果比較明顯。

3.   傳輸效能由於壓縮的原因適當變弱,單Sink由原先20分鐘延長至26分鐘,可適當增加Sink的個數來提高傳輸速率。

生產環境實施結果

頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上

實施結果如下:

1.   由於還有其它業務的頻寬佔用,總頻寬使用率節省了50%以上,現階段高峰期頻寬速率不超過400Mbps;

2.   每個Sink傳輸速率的極限大概是3000條每秒,壓縮傳輸速率問題透過增加Sink的方式解決,但會適當增加CPU和記憶體的損耗。

全文總結

Flume作為個推日誌傳輸的主要工具之一,Source的型別選擇尤為重要(如avro、thrif、exec、kafka和spooling directory等等)。無論選擇哪種Source,都是為了實現日誌資料的高效傳輸。本文透過Avro的方式,解決了頻寬資源瓶頸的問題。

未來,我們希望與更多開發者一起探索如何用更多的技術手段來節約控制成本,並滿足更多的業務場景需求。




頻寬不夠用,靠這個方法我讓資料壓縮率達到了80%以上


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556026/viewspace-2690884/,如需轉載,請註明出處,否則將追究法律責任。

相關文章