1. 程式人生 > 實用技巧 >Kafka詳解

Kafka詳解

Kafka是一種分散式的、基於釋出/訂閱的訊息快取系統。(依賴於zookeeper)

一、特性:

  • 訊息持久化
  • 高吞吐量,每秒百萬級
  • 擴充套件能力強
  • 支援多種語言
  • 實時性:生產者的message立即被消費者可見

二、要點:

1、kafka是一個分散式的訊息快取系統。

2、kafka叢集中的伺服器都叫做broker。

3、kafka有兩類客戶端,一類叫producer(訊息生產者),一類叫做consumer(訊息消費者),客戶端和broker伺服器之間採用TCP協議連線。

4、kafka中不同業務系統的訊息可以通過topic進行區分(partition),而且每一個訊息topic都會被分割槽,以分擔訊息讀寫的負載。

5、每一個分割槽都可以有多個副本,以防止資料的丟失。

6、某一個分割槽中的資料如果需要更新,都必須通過該分割槽所有副本中的leader來更新。

7、消費者可以分組,比如有兩個消費者組A和B,消費同一個topic,A和B各自消費各自的訊息,互不影響。但是,在同一個消費者組下的不同消費者的消費是互補的。

8、消費者在具體消費某個topic中的訊息時,可以指定起始偏移量。

三、基本元件詳解:

Broker每臺機器叫一個broker,也即當前伺服器上的Kafka程序,只管資料儲存,不管是誰生產,不管是誰消費。且Kafka代理(broker)是無狀態的,即代理並不知道消費者是否已經使用了該訊息,當訊息在代理中超過一定時間後,將會被自動刪除。叢集中每個broker都有一個唯一broker_id,不得重複。

Producer訊息生產者,資料的分發策略由producer決定,預設是defaultPartition Utils.abs(key.hashCode) % numPartitions。生產者可以釋出資料到指定的topic中,並可以指定在topic中哪些訊息分配到哪些分割槽。生產者直接把訊息傳送給對應分割槽的broker,而不需要任何路由層。批處理髮送:當message積累到一定數量或等待一定時間後進行傳送。

Consumer訊息消費者

ConsumerGroup:資料消費者組,ConsumerGroup可以有多個,每個ConsumerGroup消費的資料都是一樣的。可以把多個consumer執行緒劃分為一個組,組裡面所有成員共同消費一個topic的資料,組員之間不能重複消費。

Topic不同的消費者去指定topic中讀,不同的生產者向不同topic中寫。這是一個邏輯上的概念,落到磁碟上是一個partition的目錄。partition的目錄中有多個segment組合(index,log)。一個Topic對應多個partition[0,1,2,3…],一個partition對應多個segment組合。一個segment有預設的大小是1G。每個partition可以設定多個副本(replication-factor 1),會從所有的副本中選取一個leader出來。所有讀寫操作都是通過leader來進行的。特別強調,在kafka中讀寫操作都是leader。無論釋出的訊息是否被消費,kafka都會持久化一定時間(可配置,預設7天)每個消費者都會持久化offset到日誌中,且offset的位置由消費者控制。

Partition在topic基礎上做了進一步區分,partition是一個磁碟目錄。

Kafka內部是分散式的,一個kafka叢集通常有多個broker。

負載均衡:將topic分成多個分割槽,每個broker儲存一個或多個partition,如果Broker數大於Partition數,那麼有Broker中沒有對應的Partition;如果Broker小於Partition數,Broker中會存在多個Partition。

多個producer和consumer同時生產和消費訊息。

四、consumerGroup的組員和partition之間如何做負載均衡?

最好是一一對應,一個partition對應一個consumer。

如果某consumer group中consumer數量少於partition數量,則至少有一個consumer會消費多個partition的資料,如果consumer的數量與partition數量相同,則正好一個consumer消費一個partition的資料,而如果consumer的數量多於partition的數量時,會有部分consumer無法消費該topic中任何一條訊息。實際上,Kafka保證的是穩定狀態下每一個Consumer例項只會消費某一個或多個特定Partition的資料,而某個Partition的資料只會被同一個消費組中某一個特定的Consumer例項所消費。

每一個consumer例項都屬於一個consumer group,每一條訊息只會被同一個consumer group裡的一個consumer例項消費。(不同consumer group可以同時消費同一條訊息)

五、如何保證kafka消費者消費資料是全域性有序的?

偽命題。如果要全域性有序的,必須保證生產有序,儲存有序,消費有序。由於生產可以做叢集,儲存可以分片,消費可以設定為一個consumerGroup,要保證全域性有序,就需要保證每個環節都有序。只有一個可能,就是一個生產者,一個partition,一個消費者。這種場景和大資料應用場景相悖。

六、持久化

Topic的每個partition對應一個邏輯日誌。

每次生產者釋出訊息到一個分割槽,代理就將訊息追加到最後一個段檔案中。當釋出的訊息數量達到設定值或者經過一定的時間後(可配置),一段檔案真正flush到磁碟中,寫入完成後,訊息公開給消費者。

partition內部是有一個真正落地的資料,這個資料叫segment,用多個segment去把這個大的segment給它拆分,這樣的話比如說我先寫1號segment,寫完之後再寫2號segment,2號寫完了寫3號。當查詢歷史資料時,通過offset在segment中用二分查詢

與傳統的訊息系統不同,kafka系統中儲存的訊息沒有明確的訊息id。訊息通過日誌中的邏輯偏移量來公開。

七、傳輸效率

生產者提交一批訊息作為一個請求,消費者雖然是一個一個遍歷訊息,但背後也是一次請求獲取一批資料,從而減少網路請求數量。

Kafka不快取訊息在程序中,而是依賴於底層的檔案系統頁快取,故GC開銷很小。

八、kafka如何保證資料的完全生產(producer

ack機制:broker表示發來的資料已確認接收無誤,表示資料已經儲存到磁碟。通過初始化producer時的producerconfig可以通過配置request.required.acks不同的值來實現。

0:不等待broker返回確認訊息

1:等待topic中某個partition leader儲存成功的狀態反饋

-1:等待topic中某個partition 所有副本都儲存成功的狀態反饋

九、資料傳輸保證

Kafka預設採用at least once的訊息投遞策略。

三種保證策略:

at most once:訊息可能會丟,但不會重複傳輸

at least once:訊息不會丟,但可能會重複傳輸

exactly once:每條訊息僅傳輸一次

十、副本管理

Kafka將日誌複製到多個伺服器,副本的單元是partition,每個分割槽都有一個leader和0到多個follower,Leader處理分割槽上的所有讀寫請求,leader也是分散式的,leader的日誌和follower的日誌是相同的,且follower是被動複製,如果leader掛了,其中一個follower自動變成新的leader。

十一、Zookeeper在kafka中的作用

1、探測broker和consumer的新增和移除

2、當1發生時,觸發每個消費者程序的重新負載

3、維護消費關係和追蹤消費者在分割槽消費資訊的offset

Zookeeper具體使用:

1、broker啟動時在/brokers/ids下建立一個臨時節點znode,把broker id寫進去,broker宕機或沒響應該節點就會被刪除。

2、每個Broker會把自己儲存和維護的partition資訊註冊到/broker/topics/…路徑下。

3、consumers也會在zookeeper上註冊臨時節點,用以保持消費負載平衡和offset記錄。

4、每個consumer在/consumers/[group_id]/ids下建立一個臨時consumer_id,用來描述當前group下哪些consumer是alive的。

5、group id相同的多個consumer構成一個消費組,共同消費一個topic,並儘量消費均衡。

十二、訊息傳遞過程

Producer在釋出訊息到某個Partition時,先通過Zookeeper找到該Partition的Leader,然後無論該Topic的Replication Factor為多少(也即該Partition有多少個Replica),Producer只將該訊息傳送到該Partition的Leader。Leader會將該訊息寫入其本地Log。每個Follower都從Leader pull資料。這種方式上,Follower儲存的資料順序與Leader保持一致。Follower在收到該訊息並寫入其Log後,向Leader傳送ACK。一旦Leader收到了ISR中的所有Replica的ACK,該訊息就被認為已經commit了,Leader將增加HW(即offset)並且向Producer傳送ACK。

為了提高效能,每個Follower在接收到資料後就立馬向Leader傳送ACK,而非等到資料寫入Log中。因此,對於已經commit的訊息,Kafka只能保證它被存於多個Replica的記憶體中,而不能保證它們被持久化到磁碟中,也就不能完全保證異常發生後該條訊息一定能被Consumer消費。但考慮到這種場景非常少見,可以認為這種方式在效能和資料持久化上做了一個比較好的平衡。在將來的版本中,Kafka會考慮提供更高的永續性。Consumer讀訊息也是從Leader讀取,只有被commit過的訊息(offset低於HW的訊息)才會暴露給Consumer。

具體步驟總結下來如下:

1. producer 先從 zookeeper 的 "/brokers/.../state" 節點找到該 partition 的 leader

2. producer 將訊息傳送給該 leader

3. leader 將訊息寫入本地 log

4. followers 從 leader pull 訊息,寫入本地 log 後向leader 傳送 ACK

5. leader 收到所有 ISR 中的 replica 的 ACK 後,增加 HW(high watermark,最後 commit 的 offset)並向 producer 傳送 ACK

十三、Kafka和flume的區別和聯絡:

1.kafka做日誌快取, flume偏向於資料採集,flume可以定製很多資料來源,減少開發量。所以比較流行flume+kafka模式。 如果為了利用flume寫hdfs的能力,可以採用kafka+flume的方式實現從Kafka到Hadoop的流資料,配置Kafka為Source讀取資料,就沒有必要實現自己的消費者。直接利用Flume與HDFS及HBase的結合的所有好處。使用Cloudera Manager對消費者的監控,甚至可以新增攔截器進行一些流處理。

2.Kafka和Flume都是可靠的系統,通過適當的配置能保證零資料丟失。然而,Flume不支援副本事件。如果Flume代理的一個節點崩潰了,即使使用了可靠的檔案管道方式,你也將丟失這些事件,直到你恢復這些磁碟。如果你需要一個高可靠行的管道,那麼使用Kafka是個更好的選擇。

十四、Kafka和redis的區別

1. redis是記憶體資料庫,只是它的list資料型別剛好可以用作訊息佇列而已;kafka是訊息佇列,訊息的儲存模型只是其中的一個環節,還提供了訊息ACK和佇列容量、消費速率等訊息相關的功能。

2. redis 釋出訂閱除了表示不同的 topic 外,並不支援分組。kafka每個consumer屬於一個特定的consumer group(default group), 同一topic的一條訊息只能被同一個consumer group內的一個consumer消費,但多個consumer group可同時消費這一訊息,這樣可以用作負載均衡。

3. redis訊息推送(基於分散式 pub/sub)多用於實時性較高的訊息推送,並不保證可靠,redis-pub/sub斷電就清空。其他的mq和kafka保證可靠但有一些延遲(非實時系統沒有保證延遲)。

4. 處理資料大小的級別不同。