Kafka簡介
Kafka 起初是由 LinkedIn 公司採用 Scala 語言開發的一個分散式、多分割槽、多副本且基於 zookeeper 協調的分散式訊息系統,現已捐獻給 Apache 基金會。它是一種高吞吐量的分散式釋出訂閱訊息系統,以可水平擴充套件和高吞吐率而被廣泛使用。目前越來越多的開源分散式處理系統如 Cloudera、Apache Storm、Spark、Flink 等都支援與 Kafka 整合。
kafka目前支援多種客戶端語言:java,python,c++,php等,跨語言的支援力度也可以從側面反映出一個訊息中介軟體的流行程度。
1. 建立背景
Kafka是一個訊息系統,原本開發自LinkedIn,用作LinkedIn的活動流(Activity Stream)和運營資料處理管道(Pipeline)的基礎。現在它已被多家不同型別的公司作為多種型別的資料管道和訊息系統使用。
- 活動流資料:網站使用者行為的相關資料,例如PV、UV等。這種資料通常的處理方式是先把各種活動以日誌的形式寫入某種檔案,然後週期性地對這些檔案進行統計分析。
- 運營資料:伺服器的效能資料(CPU、IO使用率、請求時間、服務日誌等等資料)。運營資料的統計方法種類繁多。
以上這些資料的特點:
資料不可變
海量資料
需要實時處理
傳統訊息系統並不能很好的支援。
2. 設計目標
Kafka是一種分散式的,基於釋出/訂閱的訊息系統。主要設計目標如下:
- 以時間複雜度為O(1)的方式提供訊息持久化能力,即使對TB級以上資料也能保證常數時間複雜度的訪問效能。
- 高吞吐率,即使在非常廉價的商用機器上也能做到單機支援每秒100K條以上訊息的傳輸
- 支援Kafka Server間的訊息分割槽,及分散式消費,同時保證每個Partition內的訊息順序傳輸
- 支援離線資料處理和實時資料處理
- 支援線上水平擴充套件
3. 為何使用訊息系統
- 解耦
在專案啟動之初來預測將來專案會碰到什麼需求,是極其困難的。訊息系統在處理過程中間插入了一個隱含的、基於資料的介面層,兩邊的處理過程都要實現這一介面。這允許你獨立的擴充套件或修改兩邊的處理過程,只要確保它們遵守同樣的介面約束。 - 冗餘
有些情況下,處理資料的過程會失敗。除非資料被持久化,否則將造成丟失。訊息佇列把資料進行持久化直到它們已經被完全處理,通過這一方式規避了資料丟失風險。許多訊息佇列所採用的”插入-獲取-刪除”正規化中,在把一個訊息從佇列中刪除之前,需要你的處理系統明確的指出該訊息已經被處理完畢,從而確保你的資料被安全的儲存直到你使用完畢。 - 擴充套件性
因為訊息佇列解耦了你的處理過程,所以增大訊息入隊和處理的頻率是很容易的,只要另外增加處理過程即可。不需要改變程式碼、不需要調節引數。擴充套件就像調大電力按鈕一樣簡單。 - 靈活性 & 峰值處理能力
在訪問量劇增的情況下,應用仍然需要繼續發揮作用,但是這樣的突發流量並不常見;如果為以能處理這類峰值訪問為標準來投入資源隨時待命無疑是巨大的浪費。使用訊息佇列能夠使關鍵元件頂住突發的訪問壓力,而不會因為突發的超負荷的請求而完全崩潰。 - 可恢復性
系統的一部分元件失效時,不會影響到整個系統。訊息佇列降低了程序間的耦合度,所以即使一個處理訊息的程序掛掉,加入佇列中的訊息仍然可以在系統恢復後被處理。 - 順序保證
在大多使用場景下,資料處理的順序都很重要。大部分訊息佇列本來就是排序的,並且能保證資料會按照特定的順序來處理。Kafka保證一個Partition內的訊息的有序性。 - 緩衝
在任何重要的系統中,都會有需要不同的處理時間的元素。例如,載入一張圖片比應用過濾器花費更少的時間。訊息佇列通過一個緩衝層來幫助任務最高效率的執行———寫入佇列的處理會盡可能的快速。該緩衝有助於控制和優化資料流經過系統的速度。 - 非同步通訊
很多時候,使用者不想也不需要立即處理訊息。訊息佇列提供了非同步處理機制,允許使用者把一個訊息放入佇列,但並不立即處理它。想向佇列中放入多少訊息就放多少,然後在需要的時候再去處理它們。
4. 常用MQ對比
Redis
Redis是一個基於Key-Value對的NoSQL資料庫,開發維護很活躍。雖然它是一個Key-Value資料庫儲存系統,但它本身支援MQ功能,所以完全可以當做一個輕量級的佇列服務來使用。
對於RabbitMQ和Redis的入隊和出隊操作,各執行100萬次,每10萬次記錄一次執行時間。實驗表明:
OP/MQ | Redis | RabbitMQ |
---|---|---|
入隊(<10K) | 快 | 慢 |
出隊 | 快 | 慢 |
ActiveMQ
-
點對點:
生產者傳送一條訊息到queue,只有一個消費者能收到。
當沒有消費者可用時,這個訊息會被儲存直到有 一個可用的消費者。
一個queue可以有很多消費者,他們之間實現了負載均衡,
所以Queue實現了一個可靠的負載均衡。

-
釋出/訂閱:
釋出者傳送到topic的訊息,只有訂閱了topic的訂閱者才會收到訊息。
和點對點方式不同,釋出到topic的訊息會被所有訂閱者消費

- 疑問
釋出訂閱模式下,能否實現訂閱者負載均衡消費呢?當釋出者訊息量很大時,顯然單個訂閱者的處理能力是不足的。
實際上現實場景中是多個訂閱者節點組成一個訂閱組負載均衡消費topic訊息即分組訂閱,這樣訂閱者很容易實現消費能力線性擴充套件。

傳統企業型訊息佇列ActiveMQ遵循了JMS(Java Message Service)規範,實現了點對點和釋出訂閱模型,但其他流行的訊息佇列RabbitMQ、Kafka並沒有遵循老態龍鍾的JMS規範,是通過什麼方式實現消費負載均衡、多訂閱呢?
RabbitMQ
RabbitMQ實現了AQMP協議,AQMP協議定義了訊息路由規則和方式。生產端通過路由規則傳送訊息到不同queue,消費端根據queue名稱消費訊息。此外RabbitMQ是向消費端 推送 訊息,訂閱關係和消費狀態儲存在服務端。
- 點對點 :生產端傳送一條訊息通過路由投遞到Queue,只有一個消費者能消費到。

-
釋出/訂閱:
當RabbitMQ需要支援多訂閱時,釋出者傳送的訊息通過路由同時寫到多個Queue,不同訂閱組消費此訊息。
RabbitMQ既支援記憶體佇列也支援持久化佇列,消費端為 推模型 ,消費狀態和訂閱關係由服務端負責維護,訊息消費完後立即刪除,不保留歷史訊息。所以支援多訂閱時,訊息會 多個拷貝 。

Kafka
- push/pull 拉模型
Kafka只支援訊息持久化,消費端為 拉模型 ,消費狀態和訂閱關係由客戶端端負責維護,訊息消費完後不會立即刪除,會保留歷史訊息。因此支援多訂閱時,訊息只會儲存一份就可以了。
同一個訂閱組會消費topic所有訊息,每條訊息只會被同一個訂閱組的一個消費節點消費,同一個訂閱組內不同消費節點會消費不同訊息。

-
特性:
快速持久化:可以在O(1)的系統開銷下進行訊息持久化;
高吞吐:在一臺普通的伺服器上既可以達到10W/s的吞吐速率;
完全的分散式系統:Broker、Producer、Consumer都原生自動支援分散式,自動實現負載均衡;
支援Hadoop資料並行載入:對於像Hadoop的一樣的日誌資料和離線分析系統,但又要求實時處理的限制,這是一個可行的解決方案。Kafka通過Hadoop的並行載入機制統一了線上和離線的訊息處理。
ofollow,noindex">擴充套件閱讀 --- 訊息中介軟體選型分析:從Kafka與RabbitMQ的對比看全域性