kafka 基礎知識梳理及叢集環境部署記錄

散盡浮華發表於2018-05-10

 

一、kafka基礎介紹

Kafka是最初由Linkedin公司開發,是一個分散式、支援分割槽的(partition)、多副本的(replica),基於zookeeper協調的分散式訊息系統,它的最大的特性就是可以實時的處理大量資料以滿足各種需求場景:比如基於hadoop的批處理系統、低延遲的實時系統、storm/Spark流式處理引擎,web/nginx日誌、訪問日誌,訊息服務等等,用scala語言編寫,Linkedin於2010年貢獻給了Apache基金會併成為頂級開源 專案。

kafka是一種高吞吐量的分散式釋出訂閱訊息系統,它可以處理消費者規模的網站中的所有動作流資料。這種動作(網頁瀏覽,搜尋和其他使用者的行動)是在現代網路上的許多社會功能的一個關鍵因素。這些資料通常是由於吞吐量的要求而通過處理日誌和日誌聚合來解決。

訊息佇列的效能好壞,其檔案儲存機制設計是衡量一個訊息佇列服務技術水平和最關鍵指標之一,Kafka可以實現高效檔案儲存,實際應用效果極好。

1.1) kafka名詞解釋(架構的四個部分)
- producer:生產者。
- consumer:消費者。
- topic: 訊息以topic為類別記錄,Kafka將訊息種子(Feed)分門別類,每一類的訊息稱之為一個主題(Topic)。
- broker:以叢集的方式執行,可以由一個或多個服務組成,每個服務叫做一個broker;消費者可以訂閱一個或多個主題(topic),並從Broker拉資料,從而消費這些已釋出的訊息。
每個訊息(也叫作record記錄,也被稱為訊息)是由一個key,一個value和時間戳構成。

1.2)Kafka的特性
- 高吞吐量、低延遲:kafka每秒可以處理幾十萬條訊息,它的延遲最低只有幾毫秒,每個topic可以分多個partition, consumer group 對partition進行consume操作
- 可擴充套件性:kafka叢集支援熱擴充套件
- 永續性、可靠性:訊息被持久化到本地磁碟,並且支援資料備份防止資料丟失
- 容錯性:允許叢集中節點失敗(若副本數量為n,則允許n-1個節點失敗)
- 高併發:支援數千個客戶端同時讀寫

1.3)kafka有四個核心API
- 應用程式使用producer API釋出訊息到1個或多個topic中。
- 應用程式使用consumer API來訂閱一個或多個topic,並處理產生的訊息。
- 應用程式使用streams API充當一個流處理器,從1個或多個topic消費輸入流,併產生一個輸出流到1個或多個topic,有效地將輸入流轉換到輸出流。
- connector API允許構建或執行可重複使用的生產者或消費者,將topic連結到現有的應用程式或資料系統。

1.4)kafka基本原理
通常來講,訊息模型可以分為兩種:佇列和釋出-訂閱式。佇列的處理方式是一組消費者從伺服器讀取訊息,一條訊息只有其中的一個消費者來處理。在釋出-訂閱模型中,訊息被廣播給所有的消費者,接收到訊息的消費者都可以處理此訊息。Kafka為這兩種模型提供了單一的消費者抽象模型: 消費者組(consumer group)。消費者用一個消費者組名標記自己。

一個釋出在Topic上訊息被分發給此消費者組中的一個消費者。假如所有的消費者都在一個組中,那麼這就變成了queue模型。假如所有的消費者都在不同的組中,那麼就完全變成了釋出-訂閱模型。更通用的, 我們可以建立一些消費者組作為邏輯上的訂閱者。每個組包含數目不等的消費者,一個組內多個消費者可以用來擴充套件效能和容錯。

並且,kafka能夠保證生產者傳送到一個特定的Topic的分割槽上,訊息將會按照它們傳送的順序依次加入,也就是說,如果一個訊息M1和M2使用相同的producer傳送,M1先傳送,那麼M1將比M2的offset低,並且優先的出現在日誌中。消費者收到的訊息也是此順序。如果一個Topic配置了複製因子(replication facto)為N,那麼可以允許N-1伺服器當機而不丟失任何已經提交(committed)的訊息。此特性說明kafka有比傳統的訊息系統更強的順序保證。但是,相同的消費者組中不能有比分割槽更多的消費者,否則多出的消費者一直處於空等待,不會收到訊息。

1.5)kafka應用場景

- 日誌收集:一個公司可以用Kafka可以收集各種服務的log,通過kafka以統一介面服務的方式開放給各種consumer,例如hadoop、Hbase、Solr等。
- 訊息系統:解耦和生產者和消費者、快取訊息等。
- 使用者活動跟蹤:Kafka經常被用來記錄web使用者或者app使用者的各種活動,如瀏覽網頁、搜尋、點選等活動,這些活動資訊被各個伺服器釋出到kafka的topic中,然後訂閱者通過訂閱這些topic來做實時的監控分析,或者裝載到hadoop、資料倉儲中做離線分析和挖掘。
- 運營指標:Kafka也經常用來記錄運營監控資料。包括收集各種分散式應用的資料,生產各種操作的集中反饋,比如報警和報告。
- 流式處理:比如spark streaming和storm
- 事件源
- 構建實時的流資料管道,可靠地獲取系統和應用程式之間的資料。
- 構建實時流的應用程式,對資料流進行轉換或反應。

1.6)主題和日誌 (Topic和Log)

每一個分割槽(partition)都是一個順序的、不可變的訊息佇列,並且可以持續的新增。分割槽中的訊息都被分了一個序列號,稱之為偏移量(offset),在每個分割槽中此偏移量都是唯一的。Kafka叢集保持所有的訊息,直到它們過期,無論訊息是否被消費了。實際上消費者所持有的僅有的後設資料就是這個偏移量,也就是消費者在這個log中的位置。 這個偏移量由消費者控制:正常情況當消費者消費訊息的時候,偏移量也線性的的增加。但是實際偏移量由消費者控制,消費者可以將偏移量重置為更老的一個偏移量,重新讀取訊息。 可以看到這種設計對消費者來說操作自如, 一個消費者的操作不會影響其它消費者對此log的處理。 再說說分割槽。Kafka中採用分割槽的設計有幾個目的。一是可以處理更多的訊息,不受單臺伺服器的限制。Topic擁有多個分割槽意味著它可以不受限的處理更多的資料。第二,分割槽可以作為並行處理的單元,稍後會談到這一點。

1.7)分散式(Distribution)

 Log的分割槽被分佈到叢集中的多個伺服器上。每個伺服器處理它分到的分割槽。根據配置每個分割槽還可以複製到其它伺服器作為備份容錯。 每個分割槽有一個leader,零或多個follower。Leader處理此分割槽的所有的讀寫請求,而follower被動的複製資料。如果leader當機,其它的一個follower會被推舉為新的leader。 一臺伺服器可能同時是一個分割槽的leader,另一個分割槽的follower。 這樣可以平衡負載,避免所有的請求都只讓一臺或者某幾臺伺服器處理。

1.8)Kakfa Broker Leader的選舉
Kakfa Broker叢集受Zookeeper管理。所有的Kafka Broker節點一起去Zookeeper上註冊一個臨時節點,因為只有一個Kafka Broker會註冊成功,其他的都會失敗,所以這個成功在Zookeeper上註冊臨時節點的這個Kafka Broker會成為Kafka Broker Controller,其他的Kafka broker叫Kafka Broker follower。(這個過程叫Controller在ZooKeeper註冊Watch)。這個Controller會監聽其他的Kafka Broker的所有資訊,如果這個kafka broker controller當機了,在zookeeper上面的那個臨時節點就會消失,此時所有的kafka broker又會一起去Zookeeper上註冊一個臨時節點,因為只有一個Kafka Broker會註冊成功,其他的都會失敗,所以這個成功在Zookeeper上註冊臨時節點的這個Kafka Broker會成為Kafka Broker Controller,其他的Kafka broker叫Kafka Broker follower。例如:一旦有一個broker當機了,這個kafka broker controller會讀取該當機broker上所有的partition在zookeeper上的狀態,並選取ISR列表中的一個replica作為partition leader(如果ISR列表中的replica全掛,選一個倖存的replica作為leader; 如果該partition的所有的replica都當機了,則將新的leader設定為-1,等待恢復,等待ISR中的任一個Replica"活"過來,並且選它作為Leader;或選擇第一個"活"過來的Replica(不一定是ISR中的)作為Leader),這個broker當機的事情,kafka controller也會通知zookeeper,zookeeper就會通知其他的kafka broker。

順便說下曾經發生過的一個bug:TalkingData使用Kafka0.8.1的時候,kafka controller在Zookeeper上註冊成功後,它和Zookeeper通訊的timeout時間是6s,也就是如果kafka controller如果有6s中沒有和Zookeeper做心跳,那麼Zookeeper就認為這個kafka controller已經死了,就會在Zookeeper上把這個臨時節點刪掉,那麼其他Kafka就會認為controller已經沒了,就會再次搶著註冊臨時節點,註冊成功的那個kafka broker成為controller,然後,之前的那個kafka controller就需要各種shut down去關閉各種節點和事件的監聽。但是當kafka的讀寫流量都非常巨大的時候,TalkingData的一個bug是,由於網路等原因,kafka controller和Zookeeper有6s中沒有通訊,於是重新選舉出了一個新的kafka controller,但是原來的controller在shut down的時候總是不成功,這個時候producer進來的message由於Kafka叢集中存在兩個kafka controller而無法落地。導致資料淤積。
這裡曾經還有一個bug,TalkingData使用Kafka0.8.1的時候,當ack=0的時候,表示producer傳送出去message,只要對應的kafka broker topic partition leader接收到的這條message,producer就返回成功,不管partition leader 是否真的成功把message真正存到kafka。當ack=1的時候,表示producer傳送出去message,同步的把message存到對應topic的partition的leader上,然後producer就返回成功,partition leader非同步的把message同步到其他partition replica上。當ack=all或-1,表示producer傳送出去message,同步的把message存到對應topic的partition的leader和對應的replica上之後,才返回成功。但是如果某個kafka controller 切換的時候,會導致partition leader的切換(老的 kafka controller上面的partition leader會選舉到其他的kafka broker上),但是這樣就會導致丟資料。

1.9) Topic & Partition
Topic相當於傳統訊息系統MQ中的一個佇列queue,producer端傳送的message必須指定是傳送到哪個topic,但是不需要指定topic下的哪個partition,因為kafka會把收到的message進行load balance,均勻的分佈在這個topic下的不同的partition上( hash(message) % [broker數量] )。物理上儲存上,這個topic會分成一個或多個partition,每個partiton相當於是一個子queue。在物理結構上,每個partition對應一個物理的目錄(資料夾),資料夾命名是[topicname]_[partition]_[序號],一個topic可以有無數多的partition,根據業務需求和資料量來設定。在kafka配置檔案中可隨時更高num.partitions引數來配置更改topic的partition數量,在建立Topic時通過引數指定parittion數量。Topic建立之後通過Kafka提供的工具也可以修改partiton數量。
一般來說,a)一個Topic的Partition數量大於等於Broker的數量,可以提高吞吐率;b)同一個Partition的Replica儘量分散到不同的機器,高可用。
當add a new partition的時候,partition裡面的message不會重新進行分配,原來的partition裡面的message資料不會變,新加的這個partition剛開始是空的,隨後進入這個topic的message就會重新參與所有partition的load balance

1.10)Partition Replica
每個partition可以在其他的kafka broker節點上存副本,以便某個kafka broker節點當機不會影響這個kafka叢集。存replica副本的方式是按照kafka broker的順序存。例如有5個kafka broker節點,某個topic有3個partition,每個partition存2個副本,那麼partition1存broker1,broker2,partition2存broker2,broker3。。。以此類推(replica副本數目不能大於kafka broker節點的數目,否則報錯。這裡的replica數其實就是partition的副本總數,其中包括一個leader,其他的就是copy副本)。這樣如果某個broker當機,其實整個kafka內資料依然是完整的。但是,replica副本數越高,系統雖然越穩定,但是回來帶資源和效能上的下降;replica副本少的話,也會造成系統丟資料的風險。
a)怎樣傳送訊息:producer先把message傳送到partition leader,再由leader傳送給其他partition follower。(如果讓producer傳送給每個replica那就太慢了)
b) 在向Producer傳送ACK前需要保證有多少個Replica已經收到該訊息:根據ack配的個數而定
c) 怎樣處理某個Replica不工作的情況:如果這個部工作的partition replica不在ack列表中,就是producer在傳送訊息到partition leader上,partition leader向partition follower傳送message沒有響應而已,這個不會影響整個系統,也不會有什麼問題。如果這個不工作的partition replica在ack列表中的話,producer傳送的message的時候會等待這個不工作的partition replca寫message成功,但是會等到time out,然後返回失敗因為某個ack列表中的partition replica沒有響應,此時kafka會自動的把這個部工作的partition replica從ack列表中移除,以後的producer傳送message的時候就不會有這個ack列表下的這個部工作的partition replica了。
d)怎樣處理Failed Replica恢復回來的情況:如果這個partition replica之前不在ack列表中,那麼啟動後重新受Zookeeper管理即可,之後producer傳送message的時候,partition leader會繼續傳送message到這個partition follower上。如果這個partition replica之前在ack列表中,此時重啟後,需要把這個partition replica再手動加到ack列表中。(ack列表是手動新增的,出現某個部工作的partition replica的時候自動從ack列表中移除的)

1.11)Partition leader與follower
partition也有leader和follower之分。leader是主partition,producer寫kafka的時候先寫partition leader,再由partition leader push給其他的partition follower。partition leader與follower的資訊受Zookeeper控制,一旦partition leader所在的broker節點當機,zookeeper會衝其他的broker的partition follower上選擇follower變為parition leader。

1.12)訊息投遞可靠性
一個訊息如何算投遞成功,Kafka提供了三種模式:
- 第一種是啥都不管,傳送出去就當作成功,這種情況當然不能保證訊息成功投遞到broker;
- 第二種是Master-Slave模型,只有當Master和所有Slave都接收到訊息時,才算投遞成功,這種模型提供了最高的投遞可靠性,但是損傷了效能;
- 第三種模型,即只要Master確認收到訊息就算投遞成功;實際使用時,根據應用特性選擇,絕大多數情況下都會中和可靠性和效能選擇第三種模型
訊息在broker上的可靠性,因為訊息會持久化到磁碟上,所以如果正常stop一個broker,其上的資料不會丟失;但是如果不正常stop,可能會使存在頁面快取來不及寫入磁碟的訊息丟失,這可以通過配置flush頁面快取的週期、閾值緩解,但是同樣會頻繁的寫磁碟會影響效能,又是一個選擇題,根據實際情況配置。
訊息消費的可靠性,Kafka提供的是“At least once”模型,因為訊息的讀取進度由offset提供,offset可以由消費者自己維護也可以維護在zookeeper裡,但是當訊息消費後consumer掛掉,offset沒有即時寫回,就有可能發生重複讀的情況,這種情況同樣可以通過調整commit offset週期、閾值緩解,甚至消費者自己把消費和commit offset做成一個事務解決,但是如果你的應用不在乎重複消費,那就乾脆不要解決,以換取最大的效能

Kafka相關特性說明

- message狀態:在Kafka中,訊息的狀態被儲存在consumer中,broker不會關心哪個訊息被消費了被誰消費了,只記錄一個offset值(指向partition中下一個要被消費的訊息位置),這就意味著如果consumer處理不好的話,broker上的一個訊息可能會被消費多次。
- message持久化:Kafka中會把訊息持久化到本地檔案系統中,並且保持o(1)極高的效率。我們眾所周知IO讀取是非常耗資源的效能也是最慢的,這就是為了資料庫的瓶頸經常在IO上,需要換SSD硬碟的原因。但是Kafka作為吞吐量極高的MQ,卻可以非常高效的message持久化到檔案。這是因為Kafka是順序寫入o(1)的時間複雜度,速度非常快。也是高吞吐量的原因。由於message的寫入持久化是順序寫入的,因此message在被消費的時候也是按順序被消費的,保證partition的message是順序消費的。一般的機器,單機每秒100k條資料。
- message有效期:Kafka會長久保留其中的訊息,以便consumer可以多次消費,當然其中很多細節是可配置的。
- Produer : Producer向Topic傳送message,不需要指定partition,直接傳送就好了。kafka通過partition ack來控制是否傳送成功並把資訊返回給producer,producer可以有任意多的thread,這些kafka伺服器端是不care的。Producer端的delivery guarantee預設是At least once的。也可以設定Producer非同步傳送實現At most once。Producer可以用主鍵冪等性實現Exactly once
- Kafka高吞吐量: Kafka的高吞吐量體現在讀寫上,分散式併發的讀和寫都非常快,寫的效能體現在以o(1)的時間複雜度進行順序寫入。讀的效能體現在以o(1)的時間複雜度進行順序讀取, 對topic進行partition分割槽,consume group中的consume執行緒可以以很高能效能進行順序讀。
- Kafka delivery guarantee(message傳送保證):(1)At most once訊息可能會丟,絕對不會重複傳輸;(2)At least once 訊息絕對不會丟,但是可能會重複傳輸;(3)Exactly once每條資訊肯定會被傳輸一次且僅傳輸一次,這是使用者想要的。
- 批量傳送:Kafka支援以訊息集合為單位進行批量傳送,以提高push效率。
- push-and-pull : Kafka中的Producer和consumer採用的是push-and-pull模式,即Producer只管向broker push訊息,consumer只管從broker pull訊息,兩者對訊息的生產和消費是非同步的。
- Kafka叢集中broker之間的關係:不是主從關係,各個broker在叢集中地位一樣,我們可以隨意的增加或刪除任何一個broker節點。
- 負載均衡方面: Kafka提供了一個 metadata API來管理broker之間的負載(對Kafka0.8.x而言,對於0.7.x主要靠zookeeper來實現負載均衡)。
- 同步非同步:Producer採用非同步push方式,極大提高Kafka系統的吞吐率(可以通過引數控制是採用同步還是非同步方式)。
- 分割槽機制partition:Kafka的broker端支援訊息分割槽partition,Producer可以決定把訊息發到哪個partition,在一個partition 中message的順序就是Producer傳送訊息的順序,一個topic中可以有多個partition,具體partition的數量是可配置的。partition的概念使得kafka作為MQ可以橫向擴充套件,吞吐量巨大。partition可以設定replica副本,replica副本存在不同的kafka broker節點上,第一個partition是leader,其他的是follower,message先寫到partition leader上,再由partition leader push到parition follower上。所以說kafka可以水平擴充套件,也就是擴充套件partition。
- 離線資料裝載:Kafka由於對可擴充的資料持久化的支援,它也非常適合向Hadoop或者資料倉儲中進行資料裝載。
- 實時資料與離線資料:kafka既支援離線資料也支援實時資料,因為kafka的message持久化到檔案,並可以設定有效期,因此可以把kafka作為一個高效的儲存來使用,可以作為離線資料供後面的分析。當然作為分散式實時訊息系統,大多數情況下還是用於實時的資料處理的,但是當cosumer消費能力下降的時候可以通過message的持久化在淤積資料在kafka。
- 外掛支援:現在不少活躍的社群已經開發出不少外掛來擴充Kafka的功能,如用來配合Storm、Hadoop、flume相關的外掛。
- 解耦: 相當於一個MQ,使得Producer和Consumer之間非同步的操作,系統之間解耦。
- 冗餘: replica有多個副本,保證一個broker node當機後不會影響整個服務。
- 擴充套件性: broker節點可以水平擴充套件,partition也可以水平增加,partition replica也可以水平增加。
- 峰值: 在訪問量劇增的情況下,kafka水平擴充套件, 應用仍然需要繼續發揮作用。
- 可恢復性: 系統的一部分元件失效時,由於有partition的replica副本,不會影響到整個系統。
- 順序保證性:由於kafka的producer的寫message與consumer去讀message都是順序的讀寫,保證了高效的效能。
- 緩衝:由於producer那面可能業務很簡單,而後端consumer業務會很複雜並有資料庫的操作,因此肯定是producer會比consumer處理速度快,如果沒有kafka,producer直接呼叫consumer,那麼就會造成整個系統的處理速度慢,加一層kafka作為MQ,可以起到緩衝的作用。
- 非同步通訊:作為MQ,Producer與Consumer非同步通訊。

Kafka部分名詞解釋

Kafka中釋出訂閱的物件是topic。我們可以為每類資料建立一個topic,把向topic釋出訊息的客戶端稱作producer,從topic訂閱訊息的客戶端稱作consumer。Producers和consumers可以同時從多個topic讀寫資料。一個kafka叢集由一個或多個broker伺服器組成,它負責持久化和備份具體的kafka訊息。
- Broker:Kafka節點,一個Kafka節點就是一個broker,多個broker可以組成一個Kafka叢集。
- Topic:一類訊息,訊息存放的目錄即主題,例如page view日誌、click日誌等都可以以topic的形式存在,Kafka叢集能夠同時負責多個topic的分發。
- Partition:topic物理上的分組,一個topic可以分為多個partition,每個partition是一個有序的佇列。
- Segment:partition物理上由多個segment組成,每個Segment存著message資訊。
- Producer : 生產message傳送到topic。
- Consumer : 訂閱topic消費message, consumer作為一個執行緒來消費。
- Consumer Group:一個Consumer Group包含多個consumer, 這個是預先在配置檔案中配置好的。各個consumer(consumer 執行緒)可以組成一個組(Consumer group ),partition中的每個message只能被組(Consumer group ) 中的一個consumer(consumer 執行緒 )消費,如果一個message可以被多個consumer(consumer 執行緒 ) 消費的話,那麼這些consumer必須在不同的組。Kafka不支援一個partition中的message由兩個或兩個以上的consumer thread來處理,即便是來自不同的consumer group的也不行。它不能像AMQ那樣可以多個BET作為consumer去處理message,這是因為多個BET去消費一個Queue中的資料的時候,由於要保證不能多個執行緒拿同一條message,所以就需要行級別悲觀所(for update),這就導致了consume的效能下降,吞吐量不夠。而kafka為了保證吞吐量,只允許一個consumer執行緒去訪問一個partition。如果覺得效率不高的時候,可以加partition的數量來橫向擴充套件,那麼再加新的consumer thread去消費。這樣沒有鎖競爭,充分發揮了橫向的擴充套件性,吞吐量極高。這也就形成了分散式消費的概念。

kafka一些原理概念
持久化
kafka使用檔案儲存訊息(append only log),這就直接決定kafka在效能上嚴重依賴檔案系統的本身特性.且無論任何OS下,對檔案系統本身的優化是非常艱難的.檔案快取/直接記憶體對映等是常用的手段.因為kafka是對日誌檔案進行append操作,因此磁碟檢索的開支是較小的;同時為了減少磁碟寫入的次數,broker會將訊息暫時buffer起來,當訊息的個數(或尺寸)達到一定閥值時,再flush到磁碟,這樣減少了磁碟IO呼叫的次數.對於kafka而言,較高效能的磁碟,將會帶來更加直接的效能提升.

效能
除磁碟IO之外,我們還需要考慮網路IO,這直接關係到kafka的吞吐量問題.kafka並沒有提供太多高超的技巧;對於producer端,可以將訊息buffer起來,當訊息的條數達到一定閥值時,批量傳送給broker;對於consumer端也是一樣,批量fetch多條訊息.不過訊息量的大小可以通過配置檔案來指定.對於kafka broker端,似乎有個sendfile系統呼叫可以潛在的提升網路IO的效能:將檔案的資料對映到系統記憶體中,socket直接讀取相應的記憶體區域即可,而無需程式再次copy和交換(這裡涉及到"磁碟IO資料"/"核心記憶體"/"程式記憶體"/"網路緩衝區",多者之間的資料copy).
其實對於producer/consumer/broker三者而言,CPU的開支應該都不大,因此啟用訊息壓縮機制是一個良好的策略;壓縮需要消耗少量的CPU資源,不過對於kafka而言,網路IO更應該需要考慮.可以將任何在網路上傳輸的訊息都經過壓縮.kafka支援gzip/snappy等多種壓縮方式.

負載均衡
kafka叢集中的任何一個broker,都可以向producer提供metadata資訊,這些metadata中包含"叢集中存活的servers列表"/"partitions leader列表"等資訊(請參看zookeeper中的節點資訊). 當producer獲取到metadata資訊之後, producer將會和Topic下所有partition leader保持socket連線;訊息由producer直接通過socket傳送到broker,中間不會經過任何"路由層".
非同步傳送,將多條訊息暫且在客戶端buffer起來,並將他們批量傳送到broker;小資料IO太多,會拖慢整體的網路延遲,批量延遲傳送事實上提升了網路效率;不過這也有一定的隱患,比如當producer失效時,那些尚未傳送的訊息將會丟失。

Topic模型
其他JMS實現,訊息消費的位置是有prodiver保留,以便避免重複傳送訊息或者將沒有消費成功的訊息重發等,同時還要控制訊息的狀態.這就要求JMS broker需要太多額外的工作.在kafka中,partition中的訊息只有一個consumer在消費,且不存在訊息狀態的控制,也沒有複雜的訊息確認機制,可見kafka broker端是相當輕量級的.當訊息被consumer接收之後,consumer可以在本地儲存最後訊息的offset,並間歇性的向zookeeper註冊offset.由此可見,consumer客戶端也很輕量級。
kafka中consumer負責維護訊息的消費記錄,而broker則不關心這些,這種設計不僅提高了consumer端的靈活性,也適度的減輕了broker端設計的複雜度;這是和眾多JMS prodiver的區別.此外,kafka中訊息ACK的設計也和JMS有很大不同,kafka中的訊息是批量(通常以訊息的條數或者chunk的尺寸為單位)傳送給consumer,當訊息消費成功後,向zookeeper提交訊息的offset,而不會向broker交付ACK.或許你已經意識到,這種"寬鬆"的設計,將會有"丟失"訊息/"訊息重發"的危險.

訊息傳輸一致
Kafka提供3種訊息傳輸一致性語義:最多1次,最少1次,恰好1次。
最少1次:可能會重傳資料,有可能出現資料被重複處理的情況;
最多1次:可能會出現資料丟失情況;
恰好1次:並不是指真正只傳輸1次,只不過有一個機制。確保不會出現“資料被重複處理”和“資料丟失”的情況。

at most once: 消費者fetch訊息,然後儲存offset,然後處理訊息;當client儲存offset之後,但是在訊息處理過程中consumer程式失效(crash),導致部分訊息未能繼續處理.那麼此後可能其他consumer會接管,但是因為offset已經提前儲存,那麼新的consumer將不能fetch到offset之前的訊息(儘管它們尚沒有被處理),這就是"at most once".
at least once: 消費者fetch訊息,然後處理訊息,然後儲存offset.如果訊息處理成功之後,但是在儲存offset階段zookeeper異常或者consumer失效,導致儲存offset操作未能執行成功,這就導致接下來再次fetch時可能獲得上次已經處理過的訊息,這就是"at least once".
"Kafka Cluster"到消費者的場景中可以採取以下方案來得到“恰好1次”的一致性語義:
最少1次+消費者的輸出中額外增加已處理訊息最大編號:由於已處理訊息最大編號的存在,不會出現重複處理訊息的情況。

副本
kafka中,replication策略是基於partition,而不是topic;kafka將每個partition資料複製到多個server上,任何一個partition有一個leader和多個follower(可以沒有);備份的個數可以通過broker配置檔案來設定。leader處理所有的read-write請求,follower需要和leader保持同步.Follower就像一個"consumer",消費訊息並儲存在本地日誌中;leader負責跟蹤所有的follower狀態,如果follower"落後"太多或者失效,leader將會把它從replicas同步列表中刪除.當所有的follower都將一條訊息儲存成功,此訊息才被認為是"committed",那麼此時consumer才能消費它,這種同步策略,就要求follower和leader之間必須具有良好的網路環境.即使只有一個replicas例項存活,仍然可以保證訊息的正常傳送和接收,只要zookeeper叢集存活即可.
選擇follower時需要兼顧一個問題,就是新leader server上所已經承載的partition leader的個數,如果一個server上有過多的partition leader,意味著此server將承受著更多的IO壓力.在選舉新leader,需要考慮到"負載均衡",partition leader較少的broker將會更有可能成為新的leader.

log
每個log entry格式為"4個位元組的數字N表示訊息的長度" + "N個位元組的訊息內容";每個日誌都有一個offset來唯一的標記一條訊息,offset的值為8個位元組的數字,表示此訊息在此partition中所處的起始位置..每個partition在物理儲存層面,有多個log file組成(稱為segment).segment file的命名為"最小offset".kafka.例如"00000000000.kafka";其中"最小offset"表示此segment中起始訊息的offset.
獲取訊息時,需要指定offset和最大chunk尺寸,offset用來表示訊息的起始位置,chunk size用來表示最大獲取訊息的總長度(間接的表示訊息的條數).根據offset,可以找到此訊息所在segment檔案,然後根據segment的最小offset取差值,得到它在file中的相對位置,直接讀取輸出即可.

分散式
kafka使用zookeeper來儲存一些meta資訊,並使用了zookeeper watch機制來發現meta資訊的變更並作出相應的動作(比如consumer失效,觸發負載均衡等)
Broker node registry: 當一個kafka broker啟動後,首先會向zookeeper註冊自己的節點資訊(臨時znode),同時當broker和zookeeper斷開連線時,此znode也會被刪除.
Broker Topic Registry: 當一個broker啟動時,會向zookeeper註冊自己持有的topic和partitions資訊,仍然是一個臨時znode.
Consumer and Consumer group: 每個consumer客戶端被建立時,會向zookeeper註冊自己的資訊;此作用主要是為了"負載均衡".一個group中的多個consumer可以交錯的消費一個topic的所有partitions;簡而言之,保證此topic的所有partitions都能被此group所消費,且消費時為了效能考慮,讓partition相對均衡的分散到每個consumer上.
Consumer id Registry: 每個consumer都有一個唯一的ID(host:uuid,可以通過配置檔案指定,也可以由系統生成),此id用來標記消費者資訊.
Consumer offset Tracking: 用來跟蹤每個consumer目前所消費的partition中最大的offset.此znode為持久節點,可以看出offset跟group_id有關,以表明當group中一個消費者失效,其他consumer可以繼續消費.
Partition Owner registry: 用來標記partition正在被哪個consumer消費.臨時znode。此節點表達了"一個partition"只能被group下一個consumer消費,同時當group下某個consumer失效,那麼將會觸發負載均衡(即:讓partitions在多個consumer間均衡消費,接管那些"遊離"的partitions)
當consumer啟動時,所觸發的操作:
A) 首先進行"Consumer id Registry";
B) 然後在"Consumer id Registry"節點下注冊一個watch用來監聽當前group中其他consumer的"leave"和"join";只要此znode path下節點列表變更,都會觸發此group下consumer的負載均衡.(比如一個consumer失效,那麼其他consumer接管partitions).
C) 在"Broker id registry"節點下,註冊一個watch用來監聽broker的存活情況;如果broker列表變更,將會觸發所有的groups下的consumer重新balance.

總結:
1) Producer端使用zookeeper用來"發現"broker列表,以及和Topic下每個partition leader建立socket連線併傳送訊息.
2) Broker端使用zookeeper用來註冊broker資訊,已經監測partition leader存活性.
3) Consumer端使用zookeeper用來註冊consumer資訊,其中包括consumer消費的partition列表等,同時也用來發現broker列表,並和partition leader建立socket連線,並獲取訊息。

Leader的選擇
Kafka的核心是日誌檔案,日誌檔案在叢集中的同步是分散式資料系統最基礎的要素。
如果leaders永遠不會down的話我們就不需要followers了!一旦leader down掉了,需要在followers中選擇一個新的leader.但是followers本身有可能延時太久或者crash,所以必須選擇高質量的follower作為leader.必須保證,一旦一個訊息被提交了,但是leader down掉了,新選出的leader必須可以提供這條訊息。大部分的分散式系統採用了多數投票法則選擇新的leader,對於多數投票法則,就是根據所有副本節點的狀況動態的選擇最適合的作為leader.Kafka並不是使用這種方法。
Kafka動態維護了一個同步狀態的副本的集合(a set of in-sync replicas),簡稱ISR,在這個集合中的節點都是和leader保持高度一致的,任何一條訊息必須被這個集合中的每個節點讀取並追加到日誌中了,才回通知外部這個訊息已經被提交了。因此這個集合中的任何一個節點隨時都可以被選為leader.ISR在ZooKeeper中維護。ISR中有f+1個節點,就可以允許在f個節點down掉的情況下不會丟失訊息並正常提供服。ISR的成員是動態的,如果一個節點被淘汰了,當它重新達到“同步中”的狀態時,他可以重新加入ISR.這種leader的選擇方式是非常快速的,適合kafka的應用場景。
一個邪惡的想法:如果所有節點都down掉了怎麼辦?Kafka對於資料不會丟失的保證,是基於至少一個節點是存活的,一旦所有節點都down了,這個就不能保證了。
實際應用中,當所有的副本都down掉時,必須及時作出反應。可以有以下兩種選擇:
1. 等待ISR中的任何一個節點恢復並擔任leader。
2. 選擇所有節點中(不只是ISR)第一個恢復的節點作為leader.
這是一個在可用性和連續性之間的權衡。如果等待ISR中的節點恢復,一旦ISR中的節點起不起來或者資料都是了,那叢集就永遠恢復不了了。如果等待ISR意外的節點恢復,這個節點的資料就會被作為線上資料,有可能和真實的資料有所出入,因為有些資料它可能還沒同步到。Kafka目前選擇了第二種策略,在未來的版本中將使這個策略的選擇可配置,可以根據場景靈活的選擇。
這種窘境不只Kafka會遇到,幾乎所有的分散式資料系統都會遇到。

副本管理
以上僅僅以一個topic一個分割槽為例子進行了討論,但實際上一個Kafka將會管理成千上萬的topic分割槽.Kafka儘量的使所有分割槽均勻的分佈到叢集所有的節點上而不是集中在某些節點上,另外主從關係也儘量均衡這樣每個幾點都會擔任一定比例的分割槽的leader.
優化leader的選擇過程也是很重要的,它決定了系統發生故障時的空窗期有多久。Kafka選擇一個節點作為“controller”,當發現有節點down掉的時候它負責在游泳分割槽的所有節點中選擇新的leader,這使得Kafka可以批量的高效的管理所有分割槽節點的主從關係。如果controller down掉了,活著的節點中的一個會備切換為新的controller.

Leader與副本同步
對於某個分割槽來說,儲存正分割槽的"broker"為該分割槽的"leader",儲存備份分割槽的"broker"為該分割槽的"follower"。備份分割槽會完全複製正分割槽的訊息,包括訊息的編號等附加屬性值。為了保持正分割槽和備份分割槽的內容一致,Kafka採取的方案是在儲存備份分割槽的"broker"上開啟一個消費者程式進行消費,從而使得正分割槽的內容與備份分割槽的內容保持一致。一般情況下,一個分割槽有一個“正分割槽”和零到多個“備份分割槽”。可以配置“正分割槽+備份分割槽”的總數量,關於這個配置,不同主題可以有不同的配置值。注意,生產者,消費者只與儲存正分割槽的"leader"進行通訊。

Kafka允許topic的分割槽擁有若干副本,這個數量是可以配置的,你可以為每個topic配置副本的數量。Kafka會自動在每個副本上備份資料,所以當一個節點down掉時資料依然是可用的。
Kafka的副本功能不是必須的,你可以配置只有一個副本,這樣其實就相當於只有一份資料。
建立副本的單位是topic的分割槽,每個分割槽都有一個leader和零或多個followers.所有的讀寫操作都由leader處理,一般分割槽的數量都比broker的數量多的多,各分割槽的leader均勻的分佈在brokers中。所有的followers都複製leader的日誌,日誌中的訊息和順序都和leader中的一致。followers向普通的consumer那樣從leader那裡拉取訊息並儲存在自己的日誌檔案中。
許多分散式的訊息系統自動的處理失敗的請求,它們對一個節點是否著(alive)”有著清晰的定義。Kafka判斷一個節點是否活著有兩個條件:
1. 節點必須可以維護和ZooKeeper的連線,Zookeeper通過心跳機制檢查每個節點的連線。
2. 如果節點是個follower,他必須能及時的同步leader的寫操作,延時不能太久。
符合以上條件的節點準確的說應該是“同步中的(in sync)”,而不是模糊的說是“活著的”或是“失敗的”。Leader會追蹤所有“同步中”的節點,一旦一個down掉了,或是卡住了,或是延時太久,leader就會把它移除。至於延時多久算是“太久”,是由引數replica.lag.max.messages決定的,怎樣算是卡住了,怎是由引數replica.lag.time.max.ms決定的。
只有當訊息被所有的副本加入到日誌中時,才算是“committed”,只有committed的訊息才會傳送給consumer,這樣就不用擔心一旦leader down掉了訊息會丟失。Producer也可以選擇是否等待訊息被提交的通知,這個是由引數acks決定的。
Kafka保證只要有一個“同步中”的節點,“committed”的訊息就不會丟失。

===========================================================================
二、kafka叢集環境部署記錄

1)伺服器資訊

ip地址            主機名          安裝軟體
192.168.10.202    kafka01         zookeeper、kafka
192.168.10.203    kafka02         zookeeper、kafka
192.168.10.205    kafka03         zookeeper、kafka
192.168.10.206    kafka-manager   kafka-manager
 
4臺機器關閉iptables和selinux
[root@kafka01 ~]# /etc/init.d/iptables stop
[root@kafka01 ~]# vim /etc/sysconfig/selinux
......
SELINUX=disabled
[root@kafka01 ~]# setenforce 0
[root@kafka01 ~]# getenforce
Permissive
 
4臺機器做hosts繫結
[root@kafka01 ~]# vim /etc/hosts
......
192.168.10.202    kafka01    
192.168.10.203    kafka02
192.168.10.205    kafka03
192.168.10.206    kafka-manager

2)jdk安裝(四臺機器都要操作,安裝1.7以上版本)

將jdk-8u131-linux-x64.rpm下載到/opt目錄下
下載地址:https://pan.baidu.com/s/1pLaAjPp
提取密碼:x27s
 
[root@kafka01 ~]# cd /usr/local/src/
[root@kafka01 src]# ll jdk-8u131-linux-x64.rpm
-rw-r--r--. 1 root root 169983496 Sep 28  2017 jdk-8u131-linux-x64.rpm
[root@kafka01 src]# rpm -ivh jdk-8u131-linux-x64.rpm
 
[root@kafka01 src]# vim /etc/profile
......
JAVA_HOME=/usr/java/jdk1.8.0_131
JAVA_BIN=/usr/java/jdk1.8.0_131/bin
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/bin:/sbin/
CLASSPATH=.:/lib/dt.jar:/lib/tools.jar
export JAVA_HOME JAVA_BIN PATH CLASSPATH
 
[root@kafka01 src]# source /etc/profile
[root@kafka01 src]# java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

3)安裝及配置kafka(192.168.10.202、192.168.10.203、192.168.10.205三臺機器如下同樣操作)

1)安裝三個節點的zookeeper(zookeeper叢集部署可以參考:http://www.cnblogs.com/kevingrace/p/7879390.html)
[root@kafka01 ~]# cd /usr/local/src/
[root@kafka01 src]# wget http://apache.forsale.plus/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
[root@kafka01 src]# tar -zvxf zookeeper-3.4.10.tar.gz
[root@kafka01 src]# mkdir /data
[root@kafka01 src]# mv zookeeper-3.4.10 /data/zk

修改三個節點的zookeeper的配置檔案,內容如下所示:
[root@kafka01 src]# mkdir -p /data/zk/data
[root@kafka01 src]# cp /data/zk/conf/zoo_sample.cfg /data/zk/conf/zoo_sample.cfg.bak
[root@kafka01 src]# cp /data/zk/conf/zoo_sample.cfg /data/zk/conf/zoo.cfg
[root@kafka01 src]# vim /data/zk/conf/zoo.cfg           #清空之前的內容,配置成下面內容
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zk/data/zookeeper
dataLogDir=/data/zk/data/logs
clientPort=2181
maxClientCnxns=60
autopurge.snapRetainCount=3
autopurge.purgeInterval=1
server.1=192.168.10.202:2888:3888
server.2=192.168.10.203:2888:3888
server.3=192.168.10.205:2888:3888

===============
配置引數說明:
server.id=host:port:port:表示了不同的zookeeper伺服器的自身標識,作為叢集的一部分,每一臺伺服器應該知道其他伺服器的資訊。
使用者可以從"server.id=host:port:port" 中讀取到相關資訊。
在伺服器的data(dataDir引數所指定的目錄)下建立一個檔名為myid的檔案,這個檔案的內容只有一行,指定的是自身的id值。
比如,伺服器"1"應該在myid檔案中寫入"1"。這個id必須在叢集環境中伺服器標識中是唯一的,且大小在1~255之間。
這一樣配置中,zoo1代表第一臺伺服器的IP地址。第一個埠號(port)是從follower連線到leader機器的埠,第二個埠是用來進行leader選舉時所用的埠。
所以,在叢集配置過程中有三個非常重要的埠:clientPort=2181、port:2888、port:3888。
===============

注意:如果想更換日誌輸出位置,除了在zoo.cfg加入"dataLogDir=/data/zk/data/logs"外,還需要修改zkServer.sh檔案,大概修改方式地方在
125行左右,內容如下:
[root@kafka01 src]# cp /data/zk/bin/zkServer.sh /data/zk/bin/zkServer.sh.bak
[root@kafka01 src]# vim /data/zk/bin/zkServer.sh
.......
125 ZOO_LOG_DIR="$($GREP "^[[:space:]]*dataLogDir" "$ZOOCFG" | sed -e 's/.*=//')"     #新增這一行
126 if [ ! -w "$ZOO_LOG_DIR" ] ; then
127 mkdir -p "$ZOO_LOG_DIR"
128 fi

[root@kafka01 src]# diff /data/zk/bin/zkServer.sh /data/zk/bin/zkServer.sh.bak
125d124
< ZOO_LOG_DIR="$($GREP "^[[:space:]]*dataLogDir" "$ZOOCFG" | sed -e 's/.*=//')"

在啟動zookeeper服務之前,還需要分別在三個zookeeper節點機器上建立myid,方式如下:
[root@kafka01 src]# mkdir /data/zk/data/zookeeper/
[root@kafka01 src]# echo 1 >  /data/zk/data/zookeeper/myid

=================================================================
另外兩個節點的myid分別為2、3(注意這三個節點機器的myid決不能一樣,配置檔案等其他都是一樣配置)
[root@kafka02 src]# mkdir /data/zk/data/zookeeper
[root@kafka02 src]# echo 2 >  /data/zk/data/zookeeper/myid

[root@kafka03 src]# mkdir /data/zk/data/zookeeper
[root@kafka03 src]# echo 3 >  /data/zk/data/zookeeper/myid
=================================================================

啟動三個節點的zookeeper服務
[root@kafka01 src]# /data/zk/bin/zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /data/zk/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
[root@kafka01 src]# ps -ef|grep zookeeper
root     25512     1  0 11:49 pts/0    00:00:00 /usr/java/jdk1.8.0_131/bin/java -Dzookeeper.log.dir=/data/zk/data/logs -Dzookeeper.root.logger=INFO,CONSOLE -cp /data/zk/bin/../build/classes:/data/zk/bin/../build/lib/*.jar:/data/zk/bin/../lib/slf4j-log4j12-1.6.1.jar:/data/zk/bin/../lib/slf4j-api-1.6.1.jar:/data/zk/bin/../lib/netty-3.10.5.Final.jar:/data/zk/bin/../lib/log4j-1.2.16.jar:/data/zk/bin/../lib/jline-0.9.94.jar:/data/zk/bin/../zookeeper-3.4.10.jar:/data/zk/bin/../src/java/lib/*.jar:/data/zk/bin/../conf:.:/lib/dt.jar:/lib/tools.jar -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /data/zk/bin/../conf/zoo.cfg
root     25555 24445  0 11:51 pts/0    00:00:00 grep zookeeper
[root@kafka01 src]# lsof -i:2181
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java    25512 root   23u  IPv6 8293793      0t0  TCP *:eforward (LISTEN)

檢視三個節點的zookeeper角色
[root@kafka01 src]# /data/zk/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /data/zk/bin/../conf/zoo.cfg
Mode: follower

[root@kafka02 src]# /data/zk/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /data/zk/bin/../conf/zoo.cfg
Mode: leader

[root@kafka03 src]# /data/zk/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /data/zk/bin/../conf/zoo.cfg
Mode: follower

—————————————————————————————————————————————————————————————————————————————————————————————
2)安裝kafka(三個節點同樣操作)
下載地址:http://kafka.apache.org/downloads.html
[root@kafka01 ~]# cd /usr/local/src/
[root@kafka01 src]# wget http://mirrors.shu.edu.cn/apache/kafka/1.1.0/kafka_2.11-1.1.0.tgz
[root@kafka01 src]# tar -zvxf kafka_2.11-1.1.0.tgz
[root@kafka01 src]# mv kafka_2.11-1.1.0 /data/kafka

進入kafka下面的config目錄,修改配置檔案server.properties:
[root@kafka01 src]# cp /data/kafka/config/server.properties /data/kafka/config/server.properties.bak
[root@kafka01 src]# vim /data/kafka/config/server.properties
broker.id=0
delete.topic.enable=true
listeners=PLAINTEXT://192.168.10.202:9092
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600
log.dirs=/data/kafka/data
num.partitions=1
num.recovery.threads.per.data.dir=1
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1
log.flush.interval.messages=10000
log.flush.interval.ms=1000
log.retention.hours=168
log.retention.bytes=1073741824
log.segment.bytes=1073741824
log.retention.check.interval.ms=300000
zookeeper.connect=192.168.10.202:2181,192.168.10.203:2181,192.168.10.205:2181
zookeeper.connection.timeout.ms=6000
group.initial.rebalance.delay.ms=0

其他兩個節點的server.properties只需要修改下面兩行,其他配置都一樣
[root@kafka02 src]# vim /data/kafka/config/server.properties 
[root@kafka02 src]# cat /data/kafka/config/server.properties
broker.id=1
......
listeners=PLAINTEXT://192.168.10.203:9092
.......

[root@kafka03 src]# vim /data/kafka/config/server.properties 
[root@kafka03 src]# cat /data/kafka/config/server.properties
broker.id=2
......
listeners=PLAINTEXT://192.168.10.205:9092
......

啟動三個節點的kafka服務
[root@kafka01 src]# nohup /data/kafka/bin/kafka-server-start.sh /data/kafka/config/server.properties >/dev/null 2>&1 &
[root@kafka01 src]# lsof -i:9092
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java    26114 root   97u  IPv6 8298666      0t0  TCP kafka01:XmlIpcRegSvc (LISTEN)
java    26114 root  113u  IPv6 8298672      0t0  TCP kafka01:53112->kafka01:XmlIpcRegSvc (ESTABLISHED)
java    26114 root  114u  IPv6 8298673      0t0  TCP kafka01:XmlIpcRegSvc->kafka01:53112 (ESTABLISHED)

驗證服務
隨便在其中一臺節點主機執行
[root@kafka01 src]# /data/kafka/bin/kafka-topics.sh --create --zookeeper 192.168.10.202:2181,192.168.10.203:2181,192.168.10.205:2181 --replication-factor 1 --partitions 1 --topic test
出現下面資訊說明建立成功
Created topic "test".

然後再在其他主機檢視上面建立的topic
[root@kafka02 src]# /data/kafka/bin/kafka-topics.sh --list --zookeeper 192.168.10.202:2181,192.168.10.203:2181,192.168.10.205:2181
test

到此,kafka叢集環境已部署完成!

4)安裝kafka叢集管理工具kafka-manager
為了簡化開發者和服務工程師維護Kafka叢集的工作,yahoo構建了一個叫做Kafka管理器的基於Web工具,叫做 Kafka Manager。kafka-manager 專案地址:https://github.com/yahoo/kafka-manager。這個管理工具可以很容易地發現分佈在叢集中的哪些topic分佈不均勻,或者是分割槽在整個叢集分佈不均勻的的情況。它支援管理多個叢集、選擇副本、副本重新分配以及建立Topic。同時,這個管理工具也是一個非常好的可以快速瀏覽這個叢集的工具,kafka-manager有如下功能:
- 管理多個kafka叢集
- 便捷的檢查kafka叢集狀態(topics,brokers,備份分佈情況,分割槽分佈情況)
- 選擇你要執行的副本
- 基於當前分割槽狀況進行
- 可以選擇topic配置並建立topic(0.8.1.1和0.8.2的配置不同)
- 刪除topic(只支援0.8.2以上的版本並且要在broker配置中設定delete.topic.enable=true)
- Topic list會指明哪些topic被刪除(在0.8.2以上版本適用)
- 為已存在的topic增加分割槽
- 為已存在的topic更新配置
- 在多個topic上批量重分割槽
- 在多個topic上批量重分割槽(可選partition broker位置)

kafka-manager安裝過程如下

下載安裝 kafka-manager
想要檢視和管理Kafka,完全使用命令並不方便,我們可以使用雅虎開源的Kafka-manager,GitHub地址如下:
https://github.com/yahoo/kafka-manager

也可以使用Git或者直接從Releases中下載,此處從下面的地址下載 1.3.3.7 版本:
https://github.com/yahoo/kafka-manager/releases

需要注意:
上面下載的是原始碼,下載後需要按照後面步驟進行編譯。如果覺得麻煩,可以直接下載編譯好的kafka-manager-1.3.3.7.zip。
下載地址:https://pan.baidu.com/s/12j2DEt94WsWRY6dD9aR6BQ
提取密碼:8x57

[root@kafka-manager src]# ls kafka-manager-1.3.3.7.zip 
kafka-manager-1.3.3.7.zip
[root@kafka-manager src]# unzip kafka-manager-1.3.3.7.zip
[root@kafka-manager src]# mv kafka-manager-1.3.3.7 /data/
[root@kafka-manager src]# cd /data/kafka-manager-1.3.3.7
[root@kafka-manager kafka-manager-1.3.3.7]# cd conf/
[root@kafka-manager conf]# cp application.conf application.conf.bak
[root@kafka-manager conf]# vim application.conf
......
#kafka-manager.zkhosts="localhost:2181"                  #註釋這一行,下面新增一行
kafka-manager.zkhosts="192.168.10.202:2181,192.168.10.203:2181,192.168.10.205:2181"

啟動kafka-manager
[root@kafka-manager conf]# nohup /data/kafka-manager-1.3.3.7/bin/kafka-manager >/dev/null 2>&1 &

----------------------------------------------------------------------------------------------------
需要注意:
kafka-manager 預設的埠是9000,可通過 -Dhttp.port,指定埠; -Dconfig.file=conf/application.conf指定配置檔案:
[root@kafka-manager conf]# nohup bin/kafka-manager -Dconfig.file=/data/kafka-manager-1.3.3.7/conf/application.conf -Dhttp.port=8080 &
----------------------------------------------------------------------------------------------------

啟動完畢後可以檢視埠是否啟動,由於啟動過程需要一段時間,埠起來的時間可能會延後。
[root@kafka-manager conf]# lsof -i:9000
COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
java    27218 root  114u  IPv6 3766984      0t0  TCP *:cslistener (LISTEN)

最後就可以使用http://192.168.10.206:9000訪問了

 

kafka-mamager測試
新建 Cluster1
點選【Cluster】>【Add Cluster】開啟如下新增叢集的配置介面:
輸入叢集的名字(如Kafka-Cluster-test)和 Zookeeper 伺服器地址(如localhost:2181),選擇最接近的Kafka版本(如0.10.1.1)
-------------------------------------------------------------------
注意:如果沒有在 Kafka 中配置過 JMX_PORT,千萬不要選擇第一個核取方塊。
Enable JMX Polling
如果選擇了該核取方塊,Kafka-manager 可能會無法啟動。
-------------------------------------------------------------------

其他broker的配置可以根據自己需要進行配置,預設情況下,點選【儲存】時,會提示幾個預設值為1的配置錯誤,需要配置為>=2的值。提示如下。

新建完成後,執行介面如下:

檢視TOPIC 資訊

檢視broker資訊

管理 kafka-mamager
新建主題
點選【Topic】>【Create】可以方便的建立並配置主題。如下顯示。

由於叢集只有三個節點,故replication factor最多隻能設定為3

================================================
針對上面Topic->Create新建主題的配置,下面根據一張圖講解

在上圖一個Kafka叢集中,有兩個伺服器,每個伺服器上都有2個分割槽。P0,P3可能屬於同一個主題,也可能是兩個不同的主題。
如果設定的Partitons和Replication Factor都是2,這種情況下該主題的分步就和上圖中Kafka叢集顯示的相同,此時P0,P3是同一個主題的兩個分割槽。P1,P2也是同一個主題的兩個分割槽,Server1和Server2其中一個會作為Leader進行讀寫操作,另一個通過複製進行同步。
如果設定的Partitons和Replication Factor都是1,這時只會根據演算法在某個Server上建立一個分割槽,可以是P0~4中的某一個(分割槽都是新建的,不是先存在4個然後從中取1個)。

相關文章