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訊息即分組訂閱,這樣訂閱者很容易實現消費能力線性擴充套件。
RabbitMQ
RabbitMQ實現了AQMP協議,AQMP協議定義了訊息路由規則和方式。生產端通過路由規則傳送訊息到不同queue,消費端根據queue名稱消費訊息。此外RabbitMQ是向消費端推送訊息,訂閱關係和消費狀態儲存在服務端。
- 點對點:生產端傳送一條訊息通過路由投遞到Queue,只有一個消費者能消費到。
- 釋出/訂閱:
當RabbitMQ需要支援多訂閱時,釋出者傳送的訊息通過路由同時寫到多個Queue,不同訂閱組消費此訊息。
RabbitMQ既支援記憶體佇列也支援持久化佇列,消費端為推模型,消費狀態和訂閱關係由服務端負責維護,訊息消費完後立即刪除,不保留歷史訊息。所以支援多訂閱時,訊息會多個拷貝。
Kafka
- push/pull
Kafka只支援訊息持久化,消費端為拉模型,消費狀態和訂閱關係由客戶端端負責維護,訊息消費完後不會立即刪除,會保留歷史訊息。因此支援多訂閱時,訊息只會儲存一份就可以了。
同一個訂閱組會消費topic所有訊息,每條訊息只會被同一個訂閱組的一個消費節點消費,同一個訂閱組內不同消費節點會消費不同訊息。
-
特性:
快速持久化:可以在O(1)的系統開銷下進行訊息持久化,這種結構對於即使數以TB的訊息儲存也能夠保持長時間的穩定效能。
高吞吐:在一臺普通的伺服器上既可以達到10W/s的吞吐速率。
完全的分散式系統:Broker、Producer、Consumer都原生自動支援分散式,自動實現負載均衡。
支援Hadoop資料並行載入:對於像Hadoop的一樣的日誌資料和離線分析系統,但又要求實時處理的限制,這是一個可行的解決方案。Kafka通過Hadoop的並行載入機制統一了線上和離線的訊息處理。
5. Kafka的使用場景
-
訊息
kafka更好的替換傳統的訊息系統,訊息系統被用於各種場景(解耦資料生產者,快取未處理的訊息等),與大多數訊息系統比較,kafka有更好的吞吐量,內建分割槽,副本和故障轉移,這有利於處理大規模的訊息。
根據我們的經驗,訊息往往用於較低的吞吐量,但需要低的端到端延遲,並需要提供強大的耐用性的保證。
在這一領域的kafka比得上傳統的訊息系統,如ActiveMQ或RabbitMQ。 -
網站活動追蹤
kafka原本的使用場景:使用者的活動追蹤,網站的活動(網頁遊覽,搜尋或其他使用者的操作資訊)釋出到不同的話題中心,這些訊息可實時處理,實時監測,也可載入到Hadoop或離線處理資料倉儲。
每個使用者頁面檢視都會產生非常高的量。 -
指標
kafka也常常用於監測資料。分散式應用程式生成的統計資料集中聚合。 -
日誌聚合
使用kafka代替一個日誌聚合的解決方案。 -
流處理
kafka訊息處理包含多個階段。其中原始輸入資料是從kafka主題消費的,然後彙總,豐富,或者以其他的方式處理轉化為新主題,例如,一個推薦新聞文章,文章內容可能從“articles”主題獲取;然後進一步處理內容,得到一個處理後的新內容,最後推薦給使用者。這種處理是基於單個主題的實時資料流。從0.10.0.0開始,輕量,但功能強大的流處理,就進行這樣的資料處理了。
除了Kafka Streams,還有Apache Storm和Apache Samza可選擇。 -
事件採集
事件採集是一種應用程式的設計風格,其中狀態的變化根據時間的順序記錄下來,kafka支援這種非常大的儲存日誌資料的場景。 -
提交日誌
kafka可以作為一種分散式的外部提交日誌,日誌幫助節點之間複製資料,並作為失敗的節點來恢復資料重新同步,kafka的日誌壓縮功能很好的支援這種用法,這種用法類似於Apacha BookKeeper專案。