本文翻譯自:https://kafka.apache.org/intro,Kafka目前版本是1.0.0。轉(zhuǎn)載請(qǐng)注明出處,謝謝。
歡迎拍磚指正。
前言
Kafka是一個(gè)分布式流處理平臺(tái),具備3個(gè)核心能力:
- 可以發(fā)布和訂閱數(shù)據(jù)流,類似消息隊(duì)列和企業(yè)消息系統(tǒng)。
- 可以容錯(cuò)的持久化數(shù)據(jù)流。
- 對(duì)數(shù)據(jù)流進(jìn)行處理。
適合構(gòu)建以下2種應(yīng)用:
- 作為流數(shù)據(jù)管道在系統(tǒng)或應(yīng)用之間實(shí)時(shí)可靠的獲取數(shù)據(jù)。
- 作為流處理應(yīng)用程序?qū)?shù)據(jù)流進(jìn)行實(shí)時(shí)轉(zhuǎn)換或響應(yīng)。
明確一些概念
- Kafka以集群的方式在一臺(tái)或多臺(tái)服務(wù)器上面運(yùn)行。
- Kafka集群以分類的方式存儲(chǔ)數(shù)據(jù)流,一個(gè)分類就是一個(gè)topic
- 數(shù)據(jù)流里面的每條記錄都包含一個(gè)key,一個(gè)value,一個(gè)timestamp(時(shí)間戳)。
Kafka的API主要分為4大類:
- Producer API:使應(yīng)用可以發(fā)布數(shù)據(jù)流給Kafka topic(一個(gè)或多個(gè))。
- Consumer API:使應(yīng)用可以訂閱topic(一個(gè)或多個(gè)),然后處理發(fā)送給這些topic的數(shù)據(jù)流。
- Streams API:使應(yīng)用成為一個(gè)流處理器,消費(fèi)從topic(一個(gè)或多個(gè))接收到的輸入流,然后產(chǎn)生輸出流發(fā)送給其它topic(一個(gè)或多個(gè))。
-
Connector API:用來(lái)構(gòu)建可重用的生產(chǎn)者或消費(fèi)者,連接已存在的應(yīng)用或數(shù)據(jù)系統(tǒng)。例如:關(guān)系型數(shù)據(jù)庫(kù)連接器可以捕獲表的每一個(gè)變更。
Kafka內(nèi)部客戶端和服務(wù)端通訊使用簡(jiǎn)潔高效、語(yǔ)言無(wú)關(guān)的tcp協(xié)議。tcp協(xié)議版本化且向后兼容。Kafka提供了java和其它許多語(yǔ)言的客戶端包。
角色關(guān)系圖
Topics and Logs
一個(gè)topic是發(fā)布的數(shù)據(jù)的一種類型(名稱),可以有多個(gè)(0,1,n個(gè))訂閱者。Kafka集群為每個(gè)topic維護(hù)著一個(gè)分區(qū)了的log(日志),如圖:

partition是一個(gè)有序、不可變且不斷提交到一個(gè)結(jié)構(gòu)化日志的數(shù)據(jù)序列。每個(gè)數(shù)據(jù)都分配有唯一的叫做offset的有序ID,用于在partition中標(biāo)識(shí)數(shù)據(jù)。 Kafka集群保留所有已發(fā)布的數(shù)據(jù)--無(wú)論它們是否已被消費(fèi)(只要數(shù)據(jù)在配置的保存期內(nèi))。例如:假如設(shè)置2天的數(shù)據(jù)保存期,那么在數(shù)據(jù)發(fā)布后的2天內(nèi)它都可以被消費(fèi),2天后數(shù)據(jù)會(huì)被丟棄以釋放空間。Kafka性能隨數(shù)據(jù)遞增是常量級(jí)的,長(zhǎng)時(shí)間保存數(shù)據(jù)沒有問(wèn)題。

實(shí)際上,每個(gè)消費(fèi)者端持有的唯一元數(shù)據(jù):其在日志中的 offset or position(偏移量或位置)。offset由消費(fèi)者控制:一般情況下,消費(fèi)者會(huì)往前移動(dòng)offset來(lái)讀取數(shù)據(jù),實(shí)際上也可以移動(dòng)到任意位置讀取。例如,消費(fèi)者可以把offset重置到之前某個(gè)位置來(lái)重新處理舊數(shù)據(jù)或跳過(guò)最近的記錄直接消費(fèi)最新的數(shù)據(jù)。
這些特性組合起來(lái)意味著Kafka的消費(fèi)者可以非常便捷——他們可以在不影響集群或其他消費(fèi)者的情況下加入或退出。例如,你可以使用我們的命令行工具來(lái)獲取任意topic的最新數(shù)據(jù),且不會(huì)影響現(xiàn)有消費(fèi)者的消費(fèi)。
topic的日志分割成partitions有幾個(gè)目的。首先,它允許topic日志大小超出單臺(tái)服務(wù)器的限制。雖然每個(gè)單獨(dú)的partition大小不能超出承載它的服務(wù)器【真的超出了Kafka/我們?nèi)绾翁幚???/strong>,但是一個(gè)topic可能有多個(gè)partition,因此topic可以保存任意數(shù)量的數(shù)據(jù)。其次,partition作為并行的單元—more on that in a bit。
Distribution
log的partition分布在集群中的服務(wù)器上,每臺(tái)服務(wù)器處理分布在其上的partition的數(shù)據(jù)和請(qǐng)求。為了容錯(cuò),partition會(huì)在多臺(tái)(具體數(shù)目可配置)服務(wù)器上進(jìn)行復(fù)制備份。
partition會(huì)有一臺(tái)服務(wù)器作為“l(fā)eader”,其余的是“follower”(即主從)。leader處理所有的讀寫請(qǐng)求,follower被動(dòng)的備份leader數(shù)據(jù)。 【被動(dòng),那誰(shuí)通知它?leader?】 如果leader不可用,其中一個(gè)follower會(huì)自動(dòng)成為新的leader。每臺(tái)服務(wù)器對(duì)于分布其上的多個(gè)partition可能是leader也可能是follower,由此實(shí)現(xiàn)負(fù)載均衡。
Producers
Producers發(fā)布數(shù)據(jù)到他們選擇的topics里面。producer負(fù)責(zé)選擇將數(shù)據(jù)發(fā)送給topic中的哪個(gè)partition??梢圆捎醚h(huán)的方式簡(jiǎn)單實(shí)現(xiàn)負(fù)載均衡,或者根據(jù)數(shù)據(jù)中的一些關(guān)鍵字來(lái)決定應(yīng)該發(fā)送給哪個(gè)partition。
Consumers
消費(fèi)者會(huì)給自己標(biāo)記一個(gè)consumer group(消費(fèi)者組)名稱。【一個(gè)應(yīng)用可以同時(shí)屬于多個(gè)消費(fèi)者組嗎?--一個(gè)topic下不能?多個(gè)topic下可以吧?】發(fā)布到topic的數(shù)據(jù)會(huì)投遞給訂閱該topic的消費(fèi)者組中的一個(gè)消費(fèi)者實(shí)例。消費(fèi)者實(shí)例可能在不同的進(jìn)程中,也可能在不同的服務(wù)器上。
如果所有的消費(fèi)者實(shí)例的組名稱相同,數(shù)據(jù)將會(huì)有效地在消費(fèi)者實(shí)例中負(fù)載均衡。
如果所有的消費(fèi)者實(shí)例的組名稱都不同,數(shù)據(jù)會(huì)廣播給每個(gè)實(shí)例。

兩臺(tái)服務(wù)器組成的Kafka集群,托管著4個(gè)partition(p0-p3),有2個(gè)consumer group(消費(fèi)者組)。A組有2個(gè)消費(fèi)者實(shí)例,B組有4個(gè)。
通常,topic會(huì)有少量的消費(fèi)者組(即邏輯訂閱者)。每個(gè)消費(fèi)者組則有許多消費(fèi)者組成以伸縮和容錯(cuò)。這同樣還是發(fā)布-訂閱模式,只不過(guò)消費(fèi)者是一個(gè)集群,而非單個(gè)進(jìn)程。
Kafka中消費(fèi)的實(shí)現(xiàn)方式是將log的partition劃分給消費(fèi)者實(shí)例,【如何劃分?推薦這篇文章】(總的說(shuō)來(lái)就是一個(gè)partition只會(huì)被同個(gè)消費(fèi)者組中的其中一個(gè)實(shí)例消費(fèi),但一個(gè)消費(fèi)者實(shí)例可以消費(fèi)topic的多個(gè)partition)。Kafka協(xié)議可以動(dòng)態(tài)的維護(hù)組內(nèi)成員。如果有新的實(shí)例加入了消費(fèi)者組,它會(huì)接管其它實(shí)例的部分partition。如果一個(gè)實(shí)例失效,它的partition會(huì)分配給其它實(shí)例。【算法是怎樣的?可以自定義嗎?】
Kafka只保證一個(gè)partition內(nèi)的數(shù)據(jù)順序,不保證不同partition間所有數(shù)據(jù)的順序。【結(jié)合可以根據(jù)數(shù)據(jù)的key來(lái)分區(qū)的特性?】,可以滿足大部分應(yīng)用的需求。如果確實(shí)需要保證topic里面所有數(shù)據(jù)的順序,可以設(shè)置topic只有1個(gè)partition,但這也意味著每個(gè)消費(fèi)者組只能有1個(gè)實(shí)例同時(shí)去消費(fèi)。
Guarantees
Kafka提供以下保證:
- 同一個(gè)producer發(fā)送給topic partition的消息會(huì)以發(fā)送的先后順序?qū)懭氲絣og中。也就是說(shuō),一個(gè)producer發(fā)送了消息M1、M2。M1先與M2發(fā)送,那么,M1會(huì)有一個(gè)較小的offset值,并且早于M2寫入到log中。
- 一個(gè)消費(fèi)者實(shí)例會(huì)按消息寫入的順序收到消息。
- 對(duì)于一個(gè)復(fù)制了n份的topic(應(yīng)該是topic里面的partition復(fù)制n份)。即使其中n-1份失效,也可保證不丟失數(shù)據(jù),前提是數(shù)據(jù)已提交到日志。【因?yàn)閜artition有多個(gè)備份,如何算提交成功?leader提交成功就算成功?還是所有follower也提交成功了才算?】
更多細(xì)節(jié)請(qǐng)參考設(shè)計(jì)部分的文檔。
Kafka as a Messaging System
Kafka的流概念與傳統(tǒng)的企業(yè)消息系統(tǒng)相比有何異同呢?
消息傳遞通常有兩種模式:隊(duì)列和發(fā)布訂閱。隊(duì)列模式時(shí),服務(wù)器只會(huì)將數(shù)據(jù)發(fā)送給眾多消費(fèi)者中的一個(gè);發(fā)布訂閱模式時(shí),數(shù)據(jù)會(huì)廣播給所有消費(fèi)者。這兩種模式各有優(yōu)缺點(diǎn)。隊(duì)列的好處在于,它允許您將數(shù)據(jù)分配給多個(gè)消費(fèi)者實(shí)例處理,這樣可以讓您對(duì)消息處理進(jìn)行擴(kuò)展。不過(guò)隊(duì)列不支持多個(gè)訂閱者——一旦消費(fèi)者讀取了某個(gè)數(shù)據(jù),數(shù)據(jù)就消失了。發(fā)布訂閱支持將數(shù)據(jù)廣播給多個(gè)消費(fèi)者,但消費(fèi)者不能擴(kuò)展,因?yàn)橄⒂肋h(yuǎn)會(huì)發(fā)送給所有消費(fèi)者。
Kafka中的consumer group抽象、統(tǒng)一了這個(gè)2個(gè)概念。與隊(duì)列一樣,consumer group允許您將消息的處理分配給多個(gè)進(jìn)程(consumer group的成員)。同時(shí)也和發(fā)布訂閱模式一樣,Kafka允許您將消息廣播給多個(gè)consumer group。
Kafka模型的優(yōu)勢(shì)在于:每個(gè)topic都允許橫向擴(kuò)展且支持多個(gè)訂閱者——不用去選擇隊(duì)列模式還是消費(fèi)訂閱模式。
同時(shí),與傳統(tǒng)消息系統(tǒng)相比,Kafka提供更強(qiáng)的數(shù)據(jù)順序保證。
傳統(tǒng)隊(duì)列在服務(wù)端記錄消息順序,如果多個(gè)用戶從隊(duì)列中消費(fèi),則服務(wù)器將按記錄的順序發(fā)送消息給消費(fèi)者處理。但是,因?yàn)橄l(fā)送是異步的,消息到達(dá)不同消費(fèi)者時(shí)的順序未必還和服務(wù)端記錄的順序一致。這意味著在并行消費(fèi)的情況下。記錄的順序丟失(無(wú)效了)。通常使用exclusive consumer(專有使用者)的概念來(lái)解決這個(gè)問(wèn)題,它只允許一個(gè)進(jìn)程消費(fèi)隊(duì)列,但也意味著無(wú)法并行消費(fèi)消息。
Kafka作了改進(jìn),通過(guò)在topic中引入partition,Kafka可以同時(shí)滿足消費(fèi)者數(shù)據(jù)順序保證和負(fù)載均衡的要求。這是通過(guò)將topic的partition分配給consumer group的消費(fèi)者實(shí)例來(lái)實(shí)現(xiàn)的,這樣每個(gè)partition就只會(huì)被組中的一個(gè)消費(fèi)者實(shí)例消費(fèi)(某個(gè)時(shí)間點(diǎn)上)。通過(guò)這種方法,我們確保該實(shí)例是該partition的唯一讀取者,并按順序消費(fèi)數(shù)據(jù)。由于topic可以有許多partition,因此對(duì)眾多消費(fèi)者實(shí)例上來(lái)說(shuō)仍然是負(fù)載均衡的。但是請(qǐng)注意,consumer group的消費(fèi)者實(shí)例數(shù)目不能大于topic的partition數(shù)量(多出的消費(fèi)者實(shí)例并不會(huì)消費(fèi)數(shù)據(jù))。
Kafka as a Storage System
任何允許發(fā)布消息、異步消費(fèi)消息的消息隊(duì)列對(duì)消息來(lái)說(shuō)也是一個(gè)存儲(chǔ)系統(tǒng)。Kafka是一個(gè)很好的存儲(chǔ)系統(tǒng)。
Kafka會(huì)把接收到的數(shù)據(jù)寫入硬盤,并且復(fù)制多份用于容錯(cuò)。Kafka允許producer等待,直到所有備份寫入完成后才認(rèn)為這次提交成功。
Kafka采用的磁盤數(shù)據(jù)結(jié)構(gòu)具有很好的伸縮性:無(wú)論你需要存儲(chǔ)的數(shù)據(jù)是50KB還是50TB,對(duì)Kafka來(lái)說(shuō)都是一樣的(高性能)。
由于認(rèn)真對(duì)待存儲(chǔ)并允許客戶端控制它們的讀取位置,您可以將Kafka視為一種專用于日志存儲(chǔ)的高性能、低延遲、支持復(fù)制和分發(fā)的分布式文件系統(tǒng)。
更多細(xì)節(jié)請(qǐng)參考這個(gè)頁(yè)面。
Kafka for Stream Processing
只是讀、寫和存儲(chǔ)流數(shù)據(jù)還不夠,其目的是實(shí)現(xiàn)實(shí)時(shí)流處理。
Kafka中的流處理器是指那些從input topic中讀取輸入流,處理后寫出數(shù)據(jù)流到output topic的應(yīng)用。
例如,一個(gè)零售應(yīng)用會(huì)從銷售和發(fā)貨那里讀取一個(gè)輸入流,輸出排序和價(jià)格計(jì)算后的數(shù)據(jù)流。
可以使用producer 和consumer api直接進(jìn)行簡(jiǎn)單的處理。然而,為了處理更復(fù)雜的轉(zhuǎn)換,Kafka提供了一個(gè)高度集成的Streams API,允許應(yīng)用高效的從流中計(jì)算聚合或合并流。
這個(gè)特性有助于解決這類應(yīng)用面臨的問(wèn)題:處理無(wú)序數(shù)據(jù),代碼修改后重新處理輸入,執(zhí)行狀態(tài)計(jì)算等。
Streams API建立在Kafka提供的核心原語(yǔ)之上:使用producer和consumer處理輸入,使用有狀態(tài)存儲(chǔ),在流處理器上同樣采用分組機(jī)制以便容錯(cuò)。
Putting the Pieces Together
把消息、存儲(chǔ)和流處理結(jié)合在一起似乎不太常見,但對(duì)作為流處理平臺(tái)的Kafka來(lái)說(shuō)至關(guān)重要。
像HDFS 之類的分布式文件系統(tǒng)可以把靜態(tài)文件存儲(chǔ)起來(lái)用于批處理。這樣可以有效處理歷史數(shù)據(jù)。
傳統(tǒng)的消息隊(duì)列允許你訂閱后處理將來(lái)收到的數(shù)據(jù)。以這種方式構(gòu)建的應(yīng)用處理未來(lái)到達(dá)的數(shù)據(jù)。
Kafka同時(shí)具備這2種能力,這對(duì)于使用Kafka的應(yīng)用來(lái)說(shuō),無(wú)論是作為流處理應(yīng)用還是流的管道都意義重大。
同時(shí)結(jié)合存儲(chǔ)和低延遲訂閱二者,流處理系統(tǒng)可以用同樣的方式處理過(guò)去和將來(lái)的數(shù)據(jù)。當(dāng)一個(gè)應(yīng)用處理完歷史數(shù)據(jù)后不必下線,可以繼續(xù)處理接收到的將來(lái)時(shí)數(shù)據(jù)。 這是一個(gè)更廣義的流處理,把批處理功能包含進(jìn)了消息驅(qū)動(dòng)的應(yīng)用。
二者結(jié)合同樣使Kafka用作為一個(gè)低延遲的實(shí)時(shí)流數(shù)據(jù)管道成為可能。可靠存儲(chǔ)特性使Kafka可以用于關(guān)鍵數(shù)據(jù)傳輸或與那些需要定期停機(jī)維護(hù)的離線系統(tǒng)集成。流處理能力使得可以在數(shù)據(jù)抵達(dá)時(shí)進(jìn)行轉(zhuǎn)換。
更多特性的細(xì)節(jié)請(qǐng)參考文檔.
