kafka 訊息佇列

發表於2018-07-29

kafka是使用Java和Scala編寫的一個快速可擴充套件的高吞吐量的分散式訊息佇列系統。

kafka將資料持久化儲存到磁碟上,自帶分割槽和副本機制,因而具有較好的持久化保證。

但是kafka的訊息消費沒有確認機制,可能因為consumer崩潰導致訊息沒有完成處理。因此不建議將kafka用於一致性較高的業務場景,kafka經常被用做日誌收集和資料倉儲之間的快取。

比如將網站的瀏覽日誌快取到kafka,然後從kafka中取出批量寫入ElasticSearch, Hive或者HBase等資料倉儲中。這樣做可以極大的減輕離線分析系統的負載。

架構簡介

kafka架構中有下列角色參與:

  • broker: kafka 叢集中的伺服器例項稱為broker
  • producer: 向broker傳送訊息的客戶端
  • consumer: 向從borker中讀取訊息的客戶端
  • zookeeper: 儲存叢集狀態的註冊中心,不處理具體訊息。在負載均衡和叢集擴充套件等功能中有重要作用。

接下來介紹kafka的邏輯模型:

  • message: 訊息是kafka通訊的基本單元
  • topic: topic 在邏輯結構上類似於佇列, 每條訊息都屬於一個 topic。
  • consumer group: 每個group中可以包含若干 consumer 例項,每個topic可以被多個consumer group 訂閱。
    消費者組擁有唯一的 GroupID 進行標識, 每個 consumer 例項有且只有一個 GroupID。
  • partition: topic 被分為若干個 partition 進行儲存,每條訊息都屬於一個 partition。
  • offset: 每條訊息在 partition 中使用 offset (偏移量)作為唯一標識。

kafka 保證訂閱某個 topic 的所有 consumer group 都會收到該 topic 中所有訊息。

topic 中的一條訊息在一個 consumer group 中都會被一個 consumer 讀取,且僅會被該 consumer 讀取。

若每個 consumer 都屬於一個獨立的 consumer group 那麼訊息會被所有 consumer 讀取,即實現了訊息廣播。 若所有 consumer 屬於同一個 consumer group, 那麼訊息只會被一個 consumer 讀取,即實現訊息單播。

kafka 不會主動將訊息推送給消費者, 消費者需要主動從broker中讀取資料。

kafka 沒有訊息確認機制,由 consumer 自行控制消費的訊息。

partition與訊息傳遞的實現

kafka 將一個 topic 中的資料存儲存到多個 partition 中,每個 partition 分為多個段檔案儲存在 broker 節點上。

producer 會與 topic 下所有 partition 保持通訊,並根據配置的演算法(key-hash 或 round robin等)決定將訊息寫入哪個 partition 中。

partition 內部是有序的,但是同一個 topic 的多個 partition 之間不保證有序, 即 topic 不是整體有序的。

kafka 會為監聽 topic 的 consumer 分配一個 partition。 在一個消費者組內,一個 partition 最多分配給一個 consumer。

當組內 consumer 數量大於 partition 數量時,可能有 consumer 分配不到資料。

一個 partition 可以被屬於不同 group 的多個 consumer 監聽。

consumer 監聽不同 partition 的機制實現了訊息只能被組內一個 consumer 消費的特性,避免使用鎖機制極大提高了吞吐率簡化了 broker 實現。

消費者通過 offset 標記自己讀取的位置,主動讀取 parttion 中的資料

消費者向 broker 傳送包含 offset 和 max 引數的 fetch 請求來讀取 partition中的資料。 因此,消費者可以自由設定 offset 來控制讀取的位置,從而實現增量讀取或從頭讀取等功能。

當消費者訂閱某個 topic 時,kafka 會將最新的offset告知消費者。

消費者可以將自己當前的 offset 反饋給 kafka, kafka 會將狀態儲存到 zookeeper,使得消費者可以自由退出或者重新加入繼續消費。

kafka 沒有訊息確認機制,完全由 consumer 設定 offset 來進行消費。因此,kafka broker 不需要維護訊息狀態,有利於提高吞吐率。

與很多訊息佇列系統不同的是, kafka 不會刪除已消費的資訊, 而是根據配置的超時時間或者檔案大小限制,刪除較早傳送的訊息或過大的partition檔案。

replica

kafka 在0.8之後版本中支援了副本機制, 每個 topic 分為多個 partition, 每個 partition 存在多個 replica。

這些 replica 分佈於不同的 broker 節點上, 降低單個 broker 當機對系統可用性的影響。

kafka 的副本分佈策略是: 在擁有 n 個 broker 節點的叢集中, 將第 i 個 partition 的第 j 個 replica 儲存在第 (i + j) % n 個 broker 上。

同一個 partition 的 replica 中存在一個 leader,生產者消費者只與 leader replica 進行互動, 其它 replica 從leader中同步資料。

kafka提供了兩種主從複製機制:

  • 同步複製:訊息被 partition 的所有 alive 狀態 replica 複製訊息才會成功提交,這種方式保證一致性卻極大影響吞吐率。
  • 非同步提交:訊息被 partition 的 leader replica 寫入即提交成功, 其它 replica 會非同步同步資料。這種方式吞吐率較高但一致性較低,leader 崩潰可能導致訊息丟失。

kafka通過兩種機制判斷alive狀態:

  • zookeeper的心跳機制:broker必須維護zookeeper的session
  • slave 副本從 leader 複製資料的延遲不能超過閾值。

體驗kafka

安裝kafka

這裡作者選擇用homebrew進行安裝.

brew install kafka

配置檔案在/usr/local/etc/kafka/server.properties/usr/local/etc/kafka/zookeeper.properties

啟動zookeeper:

zookeeper-server-start /usr/local/etc/kafka/zookeeper.properties &

啟動kafka:

kafka-server-start /usr/local/etc/kafka/server.properties &

命令列工具

建立topic:

kafka-topics --zookeeper localhost:2181 --create --topic test --partitions 30  --replication-factor 2 
  • zookeeper: 叢集依賴的zookeeper服務地址
  • topic: topic 名稱
  • partitions: topic 的 partition 數
  • replication-factor: 每個 partition 的副本數

檢視 topic 資訊:

kafka-topics --zookeeper localhost:2181 --describe --topic test

刪除 topic:

kafka-topics --zookeeper localhost:2181 --delete --topic test

檢視所有 topic:

kafka-topics --zookeeper localhost:2181 --list

修改Topic設定:

kafka-topics --zookeeper localhost:2181 --alter --topic test --partitions 4

該命令可以修改 partition 和 replica 配置。

傳送訊息:

kafka-console-producer --broker-list localhost:9092 --topic test

接收新訊息:

kafka-console-consumer --zookeeper localhost:2181 --topic test

從頭讀取訊息:

kafka-console-consumer --zookeeper localhost:2181 --topic test --from-beginning

讀取 consumer group 狀態:

kafka-consumer-groups --describe --group test --bootstrap-server localhost:9092

結果:

TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
test 0 275 276 1 consumer-1-5230c9 /192.168.1.1 consumer-1
test 1 274 275 1 consumer-2-c9e79 /192.168.1.1 consumer-2

其中:

  • CURRENT-OFFSET: consumer 當前消費進度(OFFSET)
  • LOG-END-OFFSET: partition 最大消費進度(OFFSET)
  • LAG: 未處理的訊息數量,即 LOG-END-OFFSET - CURRENT-OFFSET

相關文章