kafka 解密:破除單機topic數多性能下降魔咒


https://bbs.huaweicloud.com/blogs/112956

版權歸PUMA項目組所有,轉載請聲明,多謝。

kakfa大規模集群能力在前面已給大家分享過,kafka作為消息總線,在支撐雲千萬tps上千節點的集群能力非常出色,本文繼續對業界關於單機多topic的性能瓶頸點問題(比如:https://yq.aliyun.com/articles/62832?spm=5176.100239.blogcont25379.8.KMUH1L),國內某雲使用RocketMQ,性能對比唱衰kafka 64分區時出現性能拐點,為此我們表示不服,從理論到實測數據,一步步揭開所謂單機性能拐點的秘密及解決之道。

1     簡介

本文分析了Kafka分區數量的支持情況,通過一系列的測試和分析需要確認分區的數目是否受到限制,並找到解決方案。

本文讀者包含分布式消息總線系統的開發者、測試者,以及應用該系統的客戶產品

硬件約束:2285服務器2台

軟件約束:無

2     需求背景

為什么要擴展Kafka分區數量呢?主要有以下幾點:

  1. 分區的數目關系消息隊列的並行度,消息發送是往分區里發送的,每個消費者都只能對每個分區啟動1個線程獲取數據。所以分區是消息隊列並行度的最大保證。
  2. 消息總線需要多業務接入,每個業務都要創建自己的Topic和分區,必然對隊列數目有需求(隊列數目包含Topic和分區)
  3. 終端有個IM的需求,是做一個類似一個微信和旺旺一樣的聊天工具。如果用消息總線來做,那么要求消息隊列為每個用戶分配一個隊列,這樣至少要支持幾億的消息隊列,這個在目前的消息隊列中完全沒辦法支持。
  4. 當消息隊列作為公有雲的服務提供的時候,我們分析每個用戶會獨占一個隊列(分區或Topic),同樣會對分區數量帶來要求。

正是這些需求和原因導致我們將分區個數作為了MQ的一個度量指標。同時從網上的一些分析,Kafka最多支持64個分區性能就下降得很厲害,為了驗證和解決分區數量限制的問題,我們就有本文檔的分析。

3     分析

3.1   原理分析

3.1.1    基本概念

3.1.1.1 分區

分區是Kafka中的最重要的概念之一,消息發送和接收都是按照分區為單位來處理的。

 

 

 

分區的幾個主要作用如下:

1、 Producer(消息發送者)的往消息Server的寫入並發數與分區數成正比。

2、 Consumer(消息消費者)消費某個Topic的並行度與分區數保持一致,假設分區數是20,那么Consumer的消費並行度最大為20。

3、 每個Topic由固定數量的分區數組成,分區數的多少決定了單台Broker能支持的Topic數量,Topic數量又決定了支持的業務數量。

簡單的說,有多少分區,就有多少對應的文件讀寫,Kafka的每個分區對應一個文件:

 

 

 

每條消息都被append到該Partition中,屬於順序寫磁盤,因此效率非常高,經驗證,順序寫磁盤效率比隨機寫內存還要高,這是Kafka高吞吐率的一個很重要的保證。

3.1.1.2 磁盤

在對消息存儲和緩存時,Kafka使用了文件系統。

Kafka的設計基於一種非常簡單的指導思想:不是要在內存中保存盡可能多的數據,在需要時將這些數據刷新(flush)到文件系統,而是要做完全相反的事情。所有數據都要立即寫入文件系統中持久化的日志中,但不進行刷新數據的任何調用。實際中這樣做意味着,數據被傳輸到OS內核的頁面緩存中了,OS隨后會將這些數據刷新到磁盤。

大家普遍為“磁盤很慢”,因而人們都對持久化(persistent structure)結構能夠提供說得過去的性能抱有懷疑態度。實際上,同人們的期望值相比,磁盤可以說是既很慢又很快,這取決決於磁盤的使用方式。設計的很好的磁盤結構可以和網絡一樣快。在一個由6個7200rpm的SATA硬盤組成的RAID-5磁盤陣列上,線性寫入(linear write)的速度大約是600MB/秒,但隨機寫入卻只有100k/秒,其中的差距接近6000倍。

Kafka並沒有在內存中創建緩沖區,然后再向磁盤write的方法,而是直接使用了PageCache。

OS在文件系統的讀寫上已經做了太多的優化,PageCache就是其中最重要的一種方法,詳細的說明請看3.1.2章節。

 

直接使用PageCache有如下幾個好處:

1)減少內存開銷: Java對象的內存開銷(overhead)非常大,往往是對象中存儲的數據所占內存的兩倍以上。

2)避免GC問題:Java中的內存垃圾回收會隨着堆內數據不斷增長而變得越來越不明確,回收所花費的代價也會越來越大。

3)簡單可靠:OS會調用所有的空閑內存作為PageCache,並在其上做了大量的優化:預讀,后寫,flush管理等,這些都不用應用層操心,而是由OS自動完成。

由於這些因素,使用文件系統並依賴於PageCache頁面緩存要優於自己在內存中維護一個緩存或者什么其他別的結構。

3.1.2    文件讀寫分析

Kafka借力於Linux內核的Page Cache,不(顯式)用內存,勝用內存,完全沒有別家那樣要同時維護內存中數據、持久化數據的煩惱——只要內存足夠,生產者與消費者的速度也沒有差上太多,讀寫便都發生在Page Cache中,完全沒有同步的磁盤訪問。

 

 

 

3.1.2.1 讀寫空中接力

Linux總會把系統中還沒被應用使用的內存挪來給Page Cache,在命令行輸入free,或者cat /proc/meminfo,"Cached"的部分就是Page Cache。

Page Cache中每個文件是一棵Radix樹(基樹),節點由4k大小的Page組成,可以通過文件的偏移量快速定位Page。

當寫操作發生時,它只是將數據寫入Page Cache中,並將該頁置上dirty標志。

當讀操作發生時,它會首先在Page Cache中查找內容,如果有就直接返回了,沒有的話就會從磁盤讀取文件再寫回Page Cache。

可見,只要生產者與消費者的速度相差不大,消費者會直接讀取之前生產者寫入Page Cache的數據,大家在內存里完成接力,根本沒有磁盤訪問。

而比起在內存中維護一份消息數據的傳統做法,這既不會重復浪費一倍的內存,Page Cache又不需要GC(可以放心使用大把內存了),而且即使Kafka重啟了,Page Cache還依然在。

3.1.2.2 后台異步flush的策略

這是大家最需要關心的,因為不能及時flush的話,OS crash(不是應用crash) 可能引起數據丟失,Page Cache瞬間從朋友變魔鬼。

當然,Kafka不怕丟,因為它的持久性是靠replicate保證,重啟后會從原來的replicate follower中拉缺失的數據。

內核線程pdflush負責將有dirty標記的頁面,發送給IO調度層。內核會為每個磁盤起一條pdflush線程,每5秒(/proc/sys/vm/dirty_writeback_centisecs)喚醒一次,根據下面三個參數來決定行為:

  1. /proc/sys/vm/dirty_expire_centiseconds:如果page dirty的時間超過了30秒(單位是10ms),就

會被刷到磁盤,所以crash時最多丟30秒左右的數據。

  1. /proc/sys/vm/dirty_background_ratio:如果dirty page的總大小已經超過了10%的可用內存(cat

/proc/meminfo里 MemFree+ Cached - Mapped),則會在后台啟動pdflush 線程寫盤,但不影響

當前的write(2)操作。增減這個值是最主要的flush策略里調優手段。

  1. /proc/sys/vm/dirty_ratio:如果wrte(2)的速度太快,比pdflush還快,dirty page 迅速漲到 10%

的總內存(cat /proc/meminfo里的MemTotal),則此時所有應用的寫操作都會被block,各自在自

己的時間片里去執行flush,因為操作系統認為現在已經來不及寫盤了,如果crash會丟太多數據,

要讓大家都冷靜點。這個代價有點大,要盡量避免。在Redis2.8以前,Rewrite AOF就經常導致

這個大面積阻塞,現在已經改為Redis每32Mb先主動flush()一下了。

詳細的文章可以看:http://www.westnet.com/~gsmith/content/linux-pdflush.htm

3.1.2.3 主動flush的方式

對於重要數據,應用需要自己觸發flush保證寫盤。

  1. 調用fsync() 和 fdatasync()

fsync(fd)將屬於該文件描述符的所有dirty page的寫入請求發送給IO調度層。

fsync()總是同時flush文件內容與文件元數據, 而fdatasync()只flush文件內容與后續操作必須

的文件元數據。元數據含時間戳,大小等,大小可能是后續操作必須,而時間戳就不是必須的。

因為文件的元數據保存在另一個地方,所以fsync()總是觸發兩次IO,性能要差一點。

  1. 打開文件時設置O_SYNC,O_DSYNC標志或O_DIRECT標志

O_SYNC、O_DSYNC標志表示每次write后要等到flush完成才返回,效果等同於write()后緊接一個fsync()或fdatasync(),不過按APUE里的測試,因為OS做了優化,性能會比自己調write() + fsync()好一點,但與只是write相比就慢很多了。O_DIRECT標志表示直接IO,完全跳過Page Cache。不過這也放棄了讀文件時的Cache,必須每次讀取磁盤文件。而且要求所有IO請求長度,偏移都必須是底層扇區大小的整數倍。所以使用直接IO的時候一定要在應用層做好Cache。
 

Kafka的默認機制中,fsync的間隔時間和消息個數都是最大值,所以基本上都是依賴OS層面的flush。

3.1.2.4 Page Cache的清理策略

當內存滿了,就需要清理Page Cache,或把應用占的內存swap到文件去。有一個swappiness的參數(/proc/sys/vm/swappiness)決定是swap還是清理page cache,值在0到100之間,設為0表示盡量不要用swap,這也是很多優化指南讓你做的事情,因為默認值居然是60,Linux認為Page Cache更重要。

Page Cache的清理策略是LRU的升級版。如果簡單用LRU,一些新讀出來的但可能只用一次的數據會占滿了LRU的頭端。因此將原來一條LRU隊列拆成了兩條,一條放新的Page,一條放已經訪問過好幾次的Page。Page剛訪問時放在新LRU隊列里,訪問幾輪了才升級到舊LRU隊列(想想JVM Heap的新生代老生代)。清理時就從新LRU隊列的尾端開始清理,直到清理出足夠的內存。

 

Linux 提供了這樣一個參數min_free_kbytes,用來確定系統開始回收內存的閥值,控制系統的空閑內存。值越高,內核越早開始回收內存,空閑內存越高。

 

 

 

3.1.2.5 預讀策略

根據清理策略,Apache Kafka里如果消費者太慢,堆積了幾十G的內容,Cache還是會被清理掉的。這時消費者就需要讀盤了。

內核這里又有個動態自適應的預讀策略,每次讀請求會嘗試預讀更多的內容(反正都是一次讀操作)。內核如果發現一個進程一直使用預讀數據,就會增加預讀窗口的大小,否則會關掉預讀窗口。連續讀的文件,明顯適合預讀。

 

 

 

3.1.2.6 調度層優化

IO調度層主要做兩個事情,合並和排序。

合並是將相同和相鄰扇區(每個512字節)的操作合並成一個,比如現在要讀扇區1,2,3,那可以合並成一個讀扇區1-3的操作。

排序就是將所有操作按扇區方向排成一個隊列,讓磁盤的磁頭可以按順序移動,有效減少了機械硬盤尋址這個最慢最慢的操作。

排序看上去很美,但可能造成嚴重的不公平,比如某個應用在相鄰扇區狂寫盤,其他應用就都干等在那了,pdflush還好等等沒所謂,讀請求都是同步的,耗在那會很慘。所有又有多種算法來解決這個問題,其中內核2.6的默認算法是CFQ(完全公正排隊)。

3.1.3    原理分析結論

1、Kafka使用文件系統來交換消息,性能是否比使用內存來交換消息的系統要低很多?

在Apache Kafka里,消息的讀寫都發生在內存中(Pagecache),真正寫盤的就是那條pdflush內核線程,根本不在Kafka的主流程中,讀操作大多數會命中Pagecache,同時由於預讀機制存在,所以性能非常好,從原理上有保證的。

2、 每個分區一個文件,那么多個分區會有多個文件同時讀寫,是否會極大的降低性能?

1)        首先,由於Kafka讀寫流程是發生在PageCache中,后台的flush不在主流程中觸發,所以正常情況下理論上是沒有影響的,除非PageCache占用內存過大,或是釋放導致讀寫消耗Kafka進程的CPU時間。

2)        再次,文件都是順序讀寫,OS層面有預讀和后寫機制,即使一台服務器上有多個Partition文件,經過合並和排序后都能獲得很好的性能,不會出現文件多了變成隨機讀寫的情況,但是當達到相當多的數量之后,也會存在一定的影響。

3)        當PageCache過大,大量觸發磁盤I/O的時候,超過了/proc/sys/vm/dirty_ratio,Flush會占用各個應用自己的CPU時間,會對主流程產生影響,讓主流程變慢。

3.2   性能測試

3.2.1    測試環境

 

 

 

 

同時啟動消息發送和消費。

 

 

 

指標說明:

TPS

在客戶端側由代碼統計的每秒發送和接收到的消息個數。

wai

系統因為io導致的進程wait。再深一點講就是:這時候系統在做io,導致沒有進程在干活,cpu在執行idle進程空轉,所以說iowait的產生要滿足兩個條件,一是進程在等io,二是等io時沒有進程可運行。

%util

使用iostat測試得到。Percentage of CPU time during which I/O requests   were issued to the device (bandwidth utilization for the device). Device   saturation occurs when this value is close to 100%。一秒中有百分之多少的時間用於 I/O 操作,或者說一秒中有多少時間   I/O 隊列是非空的。如果 %util 接近 100%,說明產生的I/O請求太多,I/O系統已經滿負荷,該磁盤可能存在瓶頸。

IOPS

該設備每秒的傳輸次數(Indicate the number of   transfers per second that were issued to the device.)。“一次傳輸”意思是“一次I/O請求”。多個邏輯請求可能會被合並為“一次I/O請求”。“一次傳輸”請求的大小是未知的。IOPS=reads+writes

reads

在用例運行過程中,每秒讀io的個數均值

writes

在用例運行過程中,每秒寫io的個數均值

 從流程來看,影響性能的幾個主要點為:客戶端,網絡,服務器端CPU,內存,文件系統(磁盤)。

3.2.2    單硬盤測試

當系統只有一個硬盤的時候,所有的分區文件集中在一個磁盤上,測試數據如下:

 

從數據來看,cpu,內存,網絡問題都不大。

 

 

 

隨着分區數目的增加,吞吐量會下降。從圖上來看,2000的分區下,生產者和消費者TPS下降幅度已經較大了。1000左右的分區TPS浮動不大。

備注:Consumer的TPS下降的原因,根據JProfile分析,主要是客戶端問題,后面章節有專門分析。

 

 

 

從磁盤的IOPS來看,超過1000之后,會急劇上升,3000之后因為TPS的下降,反而有所下降。

特別注意的是:讀操作一直為0,證明基本上所有的Consumer消息都是從PageCache中獲取的。

 

 

 

接下來,看一下util和wai,超過1000之后,util會急劇上升,到了3000左右,基本滿負荷了。

這個和TPS是能對上的。

根據以上的測試數據,我們可以得到一個初步的結論:

1、 當分區超過了2000之后,util急劇上升,磁盤性能會成為瓶頸,導致Producer TPS下降。

2、 由於Read操作一直為0,證明磁盤對Consumer的影響不大。Consumer的TPS下降是客戶端原因。(后面的章節給出證據)

建議:單台服務器單硬盤下,分區數量不超過2000,推薦值在1000以下。

3.2.3    多硬盤測試

啟動8個磁盤,1個磁盤跑zookeeper和OS,其他7個磁盤分擔所有的分區文件。

 

Util和IOPS是7個硬盤加起來的值,實際上每個硬盤的負荷是平均分擔的。

 

 

 

1、可以看到,3000分區下,Producer的TPS很平穩,實際上還要超過單硬盤下單分區的TPS。

證明追加硬盤的方法可以明顯的提高TPS。

2、Consumer TPS,在多硬盤下其實和單硬盤是一致的,超過2000分區之后,一直都是18w左右。證明硬盤並不是Consumer的瓶頸。

 

 

 

磁盤的IOPS和Util是隨分區增加而增加的,但是實際上被7個硬盤平均分擔,每個硬盤的負荷除以7之后很小了。

當分區達到5000之后,TPS會下降,但是磁盤負荷還遠沒有達到瓶頸。

CPU,網絡,內存也同樣沒有問題。

3.2.4    客戶端分析

3.2.4.1 Consumer客戶端

Consumer客戶端,使用的是Scala的客戶端。

多硬盤,單分區下,JProfile如下:

 

 

 

400分區如下:

 

 

 

3000分區如下:

 

 

 

3000分區的時候,可以看到,97.8的cpu時間被用來執行了parseFull這個函數,這個函數是創建Streams的時候,對從zk獲取的json文件進行解析,每次只執行一次。

但是由於分區越多,這個文件越大越復雜,導致執行時間非常長,影響了Consumer的TPS。

由於這個函數只執行一次,不會大量被執行,所以當Consumer運行時間越長,那么影響會越小。

3.2.4.2 Producer Scala客戶端

最開始使用Scala客戶端的測試,發現多分區下,大量的時間被消耗在日志打印參數的format函數上:

25分區:

 

 

 

這里的代碼,會在分個消息發送的時候,對分區的MAP循環執行如下的函數,這個代碼里面會多次拼接字符串很耗時。

通過屏蔽日志打印函數,避免執行format,可以大大提升TPS:

    partitionMetadata.map { m =>

      m.leader match {

        case Some(leader) =>

          //debug("Partition [%s,%d] has leader %d".format(topic, m.partitionId, leader.id))

          new PartitionAndLeader(topic, m.partitionId, Some(leader.id))

        case None =>

          //debug("Partition [%s,%d] does not have a leader yet".format(topic, m.partitionId))

          new PartitionAndLeader(topic, m.partitionId, None)

      }

    }.sortWith((s, t) => s.partitionId < t.partitionId)

那兩句debug信息打印注釋掉,能大大的提升TPS。

估計還有其他的瓶頸點,之后我們將測試客戶端切換到了java客戶端。

3.2.4.3 Producer Java客戶端

多硬盤一分區下,客戶端的情況(ACK=1):

 

 

 

多硬盤5000分區下,Producer客戶端(ACK=1):

 

 

 

多硬盤5000分區下,Producer客戶端(ACK=0)

 

 

 

我們可以看到,分區數量越大,send函數耗時越長,5000分區下,耗時大半。

ACK=0的時候,客戶端是不需要等待server的響應的,可以說基本上客戶端的TPS和服務器端沒有關系,但是,TPS照樣降低,send照樣消耗大量的時間。

所以,我們判斷,多硬盤下,當分區達到5000以上的時候,瓶頸在客戶端代碼上,可以通過優化客戶端代碼來提升性能。

4     分析結論

4.1   結論

一、單Broker的分區,主要受以下幾個方面的瓶頸限制:

1、 OS限制:Kafka代碼中沒有對分區做限制,但是分區數量受到OS的文件句柄的數量限制。可以用ulimit –a查看。需要調整該數目到一個較大的值。

2、 文件系統(磁盤刷盤):單硬盤下,磁盤IO和util會隨着分區數目增大而增大,導致Kafka的性能會下降。

主要原因:

刷盤是一個很昂貴的操作,雖然OS提供了Group Commit和排序等優化機制,但是當分區數量太多之后,無法完全消除影響。每個分區寫入是磁盤順序寫,但是多個分區同時順序寫入在操作系統層面變為了隨機寫入。

另外,當Pagecache的dirty數據達到一定限制之后,刷盤操作會阻塞應用的write操作,也會帶來影響。

3、 客戶端瓶頸:

通過追加硬盤可以解決單硬盤下的文件系統瓶頸。但是當達到5000以上,客戶端會成為瓶頸。

這個是由於發送消息的時候需要獲取Topic下的分區信息而產生的。

實際生產中,這個限制的影響應該不大,因為不會在1個Topic下划分太多的分區,而是會有多個Topic,每個Topic下有一些分區。測試的時候為了測試方便,采取了一種比較極端的測試方法(單個Topic下掛上數千的分區)。

當有需要的時候,也可以考慮優化。

建議分區數量:

1、單台服務器單硬盤下,推薦值1000,最好不超過2000。

2、單台服務器多硬盤下(7個),推薦值3000,最好不要超過5000。(當分區被分散到多個Topic的時候,這個值會更高,預計至少可以達到7000以上)。

 

二、集群(多節點)的分區限制:

理論上是隨着節點增加而線性增加。但是實際還是受到Zookeeper的影響。節點最大支持數量估計在1w(zookeeper的限制)左右,那么整個集群分區的支持估計在百萬左右(但是實際上受網絡速度的影響,分區越大,存放在zookeeper的數據量越多等各種因素影響肯定會有個折扣)。

預計10w左右的分區支持問題不大。

1)        參考LinkedIn的Kafka集群部署規模:

http://www.slideshare.net/miguno/apache-kafka-08-basic-training-verisign

 

 

 

2)   在這篇文章中,提到曾經在單broker上使用了上萬的分區。

http://www.confluent.io/blog/how-to-choose-the-number-of-topicspartitions-in-a-kafka-cluster/

 

 

 

4.2   社區意見參考

這里,kafka的committer有很明確的答復,基本上和我們驗證的結果一致:

http://www.quora.com/How-many-topics-can-be-created-in-Apache-Kafka

 

 

 

 

 

 

有幾個主要觀點:

1、 Kafka的分區數量兩個因素的影響:文件系統和zookeeper。

2、 實際應用中,分區數量不應該成為一個問題。分區的數量在實際中應該隨着消費者數量擴展,不應該根據Data的特征來擴展。

4.3  解決方案

針對目前的幾個瓶頸的解決方案如下:

1、 OS限制:通過調整Server的支持文件數目的句柄來解決。

2、 文件系統(磁盤刷盤):通過追加硬盤或追加Broker Node的方式來解決。

單個硬盤支持的分區數量推薦1000。多個硬盤:N*1000。

3、 客戶端:當一個Topic下有過多的分區的時候(>3000),客戶端預計會成為瓶頸。

如果有這種需求,可以考慮優化客戶端來解決這里的瓶頸。

 

 

 

5     備注

5.1   參考資料

5.1.1    Cloudera配置Kafka的建議

http://blog.cloudera.com/blog/2015/07/deploying-apache-kafka-a-practical-faq/

非常好的實際經驗。

http://blog.cloudera.com/blog/category/kafka/

是否應當為Kafka Broker使用 固態硬盤 (SSD)

實際上使用SSD盤並不能顯著地改善 Kafka 的性能,主要有兩個原因:

  • Kafka寫磁盤是異步的,不是同步的。就是說,除了啟動、停止之外,Kafka的任何操作都不會去等待磁盤同步(sync)完成;而磁盤同步(syncs)總是在后台完成的。這就是為什么Kafka消息至少復制到三個副本是至關重要的,因為一旦單個副本崩潰,這個副本就會丟失數據無法同步寫到磁盤。
  • 每一個Kafka Partition被存儲為一個串行的WAL(Write Ahead Log)日志文件。因此,除了極少數的數據查詢,Kafka中的磁盤讀寫都是串行的。現代的操作系統已經對串行讀寫做了大量的優化工作。

如何對Kafka Broker上持久化的數據進行加密 

目前,Kafka不提供任何機制對Broker上持久化的數據進行加密。用戶可以自己對寫入到Kafka的數據進行加密,即是,生產者(Producers)在寫Kafka之前加密數據,消費者(Consumers)能解密收到的消息。這就要求生產者(Producers)把加密協議(protocols)和密鑰(keys)分享給消費者(Consumers)。

另外一種選擇,就是使用軟件提供的文件系統級別的加密,例如Cloudera Navigator Encrypt。Cloudera Navigator Encrypt是Cloudera企業版(Cloudera Enterprise)的一部分,在應用程序和文件系統之間提供了一個透明的加密層。

Apache Zookeeper正成為Kafka集群的一個痛點(pain point),真的嗎?

Kafka高級消費者(high-level consumer)的早期版本(0.8.1或更早)使用Zookeeper來維護讀的偏移量(offsets,主要是Topic的每個Partition的讀偏移量)。如果有大量生產者(consumers)同時從Kafka中讀數據,對Kafka的讀寫負載可能就會超出它的容量,Zookeeper就變成一個瓶頸(bottleneck)。當然,這僅僅出現在一些很極端的案例中(extreme cases),即有成百上千個消費者(consumers)在使用同一個Zookeeper集群來管理偏移量(offset)。

不過,這個問題已經在Kafka當前的版本(0.8.2)中解決。從版本0.8.2開始,高級消費者(high-level consumer)能夠使用Kafka自己來管理偏移量(offsets)。本質上講,它使用一個單獨的Kafka Topic來管理最近的讀偏移量(read offsets),因此偏移量管理(offset management)不再要求Zookeeper必須存在。然后,用戶將不得不面臨選擇是用Kafka還是Zookeeper來管理偏移量(offsets),由消費者(consumer)配置參數 offsets.storage 決定。

Cloudera強烈推薦使用Kafka來存儲偏移量。當然,為了保證向后兼容性,你可以繼續選擇使用Zookeeper存儲偏移量。(例如,你可能有一個監控平台需要從Zookeeper中讀取偏移量信息。) 假如你不得不使用Zookeeper進行偏移量(offset)管理,我們推薦你為Kafka集群使用一個專用的Zookeeper集群。假如一個專用的Zookeeper集群仍然有性能瓶頸,你依然可以通過在Zookeeper節點上使用固態硬盤(SSD)來解決問題。

Kafka是否支持跨數據中心的可用性

Kafka跨數據中心可用性的推薦解決方案是使用MirrorMaker。在你的每一個數據中心都搭建一個Kafka集群,在Kafka集群之間使用MirrorMaker來完成近實時的數據復制。

使用MirrorMaker的架構模式是為每一個”邏輯”的topic在每一個數據中心創建一個topic:例如,在邏輯上你有一個”clicks”的topic,那么你實際上有”DC1.clicks”和“DC2.clicks”兩個topic(DC1和DC2指得是你的數據中心)。DC1向DC1.clicks中寫數據,DC2向DC2.clicks中寫數據。MirrorMaker將復制所有的DC1 topics到DC2,並且復制所有的DC2 topics到DC1。現在每個DC上的應用程序都能夠訪問寫入到兩個DC的事件。這個應用程序能夠合並信息和處理相應的沖突。

另一種更復雜的模式是在每一個DC都搭建本地和聚合Kafka集群。這個模式已經被Linkedin使用,Linkedin Kafka運維團隊已經在 這篇Blog 中有詳細的描述(參見“Tiers and Aggregation”)。

5.1.2    大數據領域的架構圖

http://www.blogbus.com/navigating-logs/272257444.html

5.1.3    源代碼High level分析

http://ju.outofmemory.cn/entry/124628

5.1.4    Kafka的配置推薦

http://bbs.chinacloud.cn/archiver/showtopic-29836.aspx

http://liyonghui160com.iteye.com/blog/2163899

5.1.5    Zookeeper的討論

http://bbs.chinacloud.cn/archiver/showtopic-29836.aspx

 重要的記錄: 

5.1.6    Kafka跨集群同步方案

http://jingyan.baidu.com/article/8065f87fea4d3a233124989f.html

http://tangzhaohui.net/post/524

5.1.7    實踐部署與使用apache kafka

http://blog.csdn.net/zhongwen7710/article/details/41252649

5.1.8    從Apache Kafka 重溫文件高效讀寫

http://calvin1978.blogcn.com/articles/kafkaio.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM