Kafka 簡介
Kafka是分布式流平台。
一個流平台有3個主要特征:
- 發布和訂閱消息流,這一點與傳統的消息隊列相似。
- 以容災持久化方式的消息流存儲。
- 在消息流發生時處理消息流。
Kafka通常使用在兩大類應用中:
- 在系統或應用之間,構建實時、可靠的消息流管道。
- 構建實時流應用程序,用於轉換或響應數據流
Kafka的幾個基本概念:
- Kafka可以作為一個集群運行在跨越多個數據中心的多個服務上。
- Kafka集群按照分類存儲的消息流叫做topic。
- 每一個消息由一個主鍵、一個值、和一個時間戳組成。
Kafka有4個核心的API:
- Producer API允許應用向一個或多個topic發送信息流。
- Consumer API允許應用訂閱一個或多個topic並處理產生的信息流。
- Streams API允許應用扮演一個流處理器,從一個或多個topic消費輸入流,並向一個或多個topic生產輸出流。 實際上是轉換輸入流到輸出流。
- Connector API構建和運行連接Kafka的可復用的生產者或消費者,到已存在的應用或數據系統。例如:連接一個關系型數據庫捕獲表中的每一次變化。
在Kafka中,客戶端和服務器之間的通信是通過一種簡單的,高性能的,語言不可知的TCP協議完成的。
Topics 和 Logs
我們了解一下Kafka為消息流提供的核心抽象——topic。 一個topic是一個消息發布時的分類。Kafka中的topic總是有0個、1個、或多個消費者訂閱寫入其中的數據。
對於每一個topic,Kafka集群保存着分區日志:
每一個partition是一個有序的不可改變的消息隊列, 它可以持續的追加——結構化的提交日志。partitions中的每一個記錄都會分配 一個有序的id,這個id叫做偏移量——每一個partition中的一個消息的唯一標識符。
Kafka集群通過配置保留時間持久化所有發布的消息,不管它是否被消費。例如:設置保留時間為2天,一個消息發布后的2天內,它可以被消費,超過2天,它將被丟棄以釋放空間。
實際上,保存在每一個消費者基礎上的唯一元數據是偏移量(offset)或者說是日志中消費者的位置。偏移量(offset)時候被消費者控制的: 正常情況下,一個消費者在讀取數據時,線性增加它的偏移量,但實際上,消費者控制位置,它可以按照任何順序處理和消費消息。例如:消費者可以重置一個老的偏移量,重新 處理過去的數據,也可以跳到最新的數據,從“現在時刻”起,消費數據。
這些特性意味着消費者是十分廉價的,他們可以來去自如,不會和集群中的其他消費者沖突。例如:你可以到任何topic的消息末尾,而不影響正在消費這個topic的其他消費者。
日志中的partitions服務着幾個目的:首先,它們允許日志的大小超出適合單個服務器的大小。每一個單獨的partition必須適合於自己的服務器。但是一個topic可以有許多個partition ,所以它可以處理任意數量規模的數據。其次它扮演着平行的單位。
分布式
日志的partitions分布在Kafka集群中的服務上,每一個服務處理partitions中的一份。每一個partition可以通過配置服務的數量進行復制,以達到容災的目的。
每一個partition都有一個服務扮演着”leader”的角色,0個或多個服務扮演着”followers”的角色。”leader”處理partition所有的讀寫請求,”followers”通過”leader”進行數據備份。 如果”leader”失敗了,”followers”中的一個會自動變成”leader”。
異地同步
Kafka的MirrorMaker為集群提供異地同步支持,使用MirrorMaker,消息可以跨越多個數據中心或雲區域進行復制。你可以用主-被模式進行數復制和恢復,也可以用主-主模式 把數據置於離用戶更新的地方。
生產者
生產者發布數據到他們選擇的topic,生產者負責選擇哪一個消息分配到topic中的哪一個partition。它可以通過輪詢的方式簡單的實現負載均衡,或者通過消息主鍵進行語義分區。
消費者
消費者用消費組名稱標志着他們自己。發布到topic的每一個消息都會傳送到每一個訂閱的消費組中的一個消費實例上。消費實例可以按照進程分割,也可以按照機器分割。
如果所有的消費實例在一個消費組下,消息實際上是在消費實例上進行負載均衡。
如果所有的實例在不同的消費組下,每一個消息都會廣播到每一個消費實例。
兩個服務器Kafka集群托管四個分區(P0-P3)和兩個消費者組。消費者組A有兩個消費者實例,而組B有四個消費者實例。
通常情況下,我們發現topic都有一個小量的消費組,每一個“邏輯訂閱者”都有一個。每一個消費組都由許多消費實例組成,為了擴展和容災。 這僅僅在生產-訂閱語義上,訂閱者由一個消費集群代替了單一的進程。
Kafka消費的實現方式是通過消費實例分割日志中的partition,所以,在任何時間點,每一個實例都是partition合理份額中的專一消費者。 組內保持關系的進程被Kafka協議動態的處理。如果一個新的實例加入了組,它會從組內的其他成員分配一些partition。如果一個實例死掉了, partitions會分配到剩余的實例中。
Kafka僅提供partition內的消息排序,不是topic內不同partition之間的。按分區排序與按鍵分區數據的能力相結合,足以滿足大多數應用程序的需求。可是, 如果你需要消息的整體排序,它可以用一個topic只有一個partition來完成,這意味着一個消費組中,只有一個消費實例處理數據。
多租戶
你可以用多租戶方案部署Kafka集群。多租戶可以通過配置啟用哪些topic可以生產或消費數據。還有配額操作的支持。管理員可以根據請求定義和執行配額以控制客戶端使用的代理資源。
擔保
作為高級別的Kafka,給出了一下的擔保:
- 被發送到topic partition的消息會按照他們發送的順序追加。如果M1被相同的生產者作為M2發送,M1先發送,M1有一個較低的offset,並且在日志中先與M2出現。
- 消費者按照日志中的順序發現消息。
- 對於具有復制因子N的主題,我們將容忍多達N-1個服務器故障,而不會丟失任何提交給日志的記錄。
Kafka作為消息系統
Kafka的流概念與傳統企業消息系統如何比較?
傳統的消息有連個模型:隊列和發布-訂閱。在隊列中,每一個消息會分配到消費者中的一個,在發布-訂閱模式下,每一個消息會廣播到所有的消費者。 這兩者中的每一個都有優點和缺點。隊列的優點是可以通過多個消費者實例分割數據的處理,這可以擴展你的處理進程。不幸的是,隊列不能有多個訂閱者,一旦一個進程 讀取了數據,它就消失了。發布-訂閱允許你廣播數據到多個進程,消息去了每一個消費者,你沒有方式去擴展它。
Kafka消費組的概念整合了這兩個概念。作為隊列,消費組可以通過進程集合(消費組中的成員)分割處理。作為發布-訂閱,Kafka允許你發布消息到所有的消費組。
Kafka模型的優點是每一個topic都有這兩個屬性,它可以擴展處理和有多個訂閱者,不需要選擇其中的一種。
Kafka比傳統的消息系統有更強的排序保障。
傳統的隊列在服務端保存消息的順序,如果多個消費者從隊列中消費數據,服務按照存儲的順序分發消息。可是,雖然服務按照順序分發數據,數據時異步的傳遞給消費者, 所以他們到達不同的消費者時是不能保證順序的。這實際上意味着消息的順序在平行消費面前是丟失的。消息系統為了解決這樣的問題,通常有一個“專用消費者”的概念, 它只允許一個消費者從隊列消費數據,這意味着沒有平行處理。
Kafka可以更好的解決這個問題。通過有一個在topic內的平行partition的概念,Kafka既可以提供消息順序的保障,又可以通過消費處理池進行負載均衡。 這是通過將topic中的partition分配給消費組中的消費者來實現的,以便每一個分區被組中的一個確定的消費者消費。通過這樣做,我們確保了一個消費者 是partition的唯一讀取者,並按照順序消費數據。由於有多個partition,仍然可以通過多個消費者均衡負載。記住,組中消費者的數量不能大於partition的數量。
Kafka作為存儲系統
任何允許發布消息並解耦消費的消息隊列實際上都扮演着一個消息的存儲系統。卡夫卡的不同之處在於它是一個非常好的存儲系統。 寫入Kafka的數據寫入磁盤並進行復制以實現容錯。Kafka允許生產者等待確認,以便寫入在完全復制之前不會被認為是完成的,並且即使寫入的服務器失敗也能保證持續。 Kafka磁盤結構使用的規模很大 - 無論您在服務器上有50 KB還是50 TB的持久性數據,Kafka都會執行相同的操作。作為認真考慮存儲並允許客戶端控制其讀取位置的結果,您可以將Kafka視為一種專用於高性能,低延遲提交日志存儲,復制和傳播的專用分布式文件系統。
Kafka作為流處理
僅讀取,寫入和存儲數據流是不夠的,目標是啟用流的實時處理。
在Kafka中,流處理器是指從輸入主題獲取連續數據流,對該輸入執行一些處理並生成連續數據流以輸出主題的任何內容。
例如,零售應用程序可能會接受銷售和裝運的輸入流,並輸出一系列重新排序和對這些數據計算出的價格調整。
可以直接使用生產者API和消費者API進行簡單的處理。然而,對於更復雜的轉換,Kafka提供完全集成的Streams API。這允許構建應用程序進行非平凡的處理,從而計算聚合關閉流或將流連接在一起。
這個工具有助於解決這類應用程序面臨的難題:處理無序數據,重新處理代碼更改的輸入,執行有狀態的計算等。
流API基於Kafka提供的核心原語構建:它使用生產者API和消費者API輸入,使用Kafka進行有狀態存儲,並在流處理器實例之間使用相同的組機制來實現容錯。