Kafka 里面的信息是如何被消費(fèi)的?
作為一個爬蟲工程師,Kafka 對你而言就是一個消息隊(duì)列,你只需要掌握如何向里面寫入數(shù)據(jù),以及如何讀取數(shù)據(jù)就可以了。
請謹(jǐn)記:使用 Kafka 很容易,但對 Kafka 集群進(jìn)行搭建、維護(hù)與調(diào)優(yōu)很麻煩。Kafka 集群需要有專人來維護(hù),不要以為你能輕易勝任這個工作。”本文,以及接下來的幾篇針對 Kafka 的文章,我們面向的對象都是爬蟲工程師或者僅僅需要使用 Kafka 的讀者。關(guān)于 Kafka 更深入的底層細(xì)節(jié)與核心原理,不在我們的討論范圍中。為了解釋方便,文章中對 Kafka 的一些術(shù)語會使用一些不太準(zhǔn)確但能表明意思的類比。如果你需要在面試中解釋這些術(shù)語,還請閱讀Kafka 的官方文檔。
今天我們要討論的一個話題是,Kafka 是如何做到,對單個程序的多個進(jìn)程而言,能持續(xù)消費(fèi),斷點(diǎn)續(xù)傳和并行消費(fèi);對多個程序而言又互不影響,各自獨(dú)立。
一個 Kafka 可以有多個不同的隊(duì)列,我們把這個隊(duì)列叫做Topic,假設(shè)其中一個隊(duì)列如下圖所示:
信息從右邊進(jìn)去,從左邊出來。如果這是Redis 的列表,那么它彈出一條信息以后,隊(duì)列會變成下面這樣:
最左邊的信息1不見了。所以即使程序在消費(fèi)了信息1后立刻關(guān)閉,再重新打開,程序也會接著從信息2開始消費(fèi),不會把信息1重復(fù)消費(fèi)兩次。
但我如果有兩個程序呢?程序1讀取每一條數(shù)據(jù),再轉(zhuǎn)存到數(shù)據(jù)庫。程序2讀取每一條數(shù)據(jù),再檢查是否有關(guān)鍵詞。這種情況下,信息1應(yīng)該能被程序1消費(fèi),也能被程序2消費(fèi)。但上面這種方案顯然是不行的。當(dāng)程序1消費(fèi)了信息1,程序2就再也拿不到它了。
所以,在 Kafka 里面,信息會停留在隊(duì)列里面,但對每一個程序來說,有一個單獨(dú)的記號,來記錄當(dāng)前消費(fèi)到了哪一條數(shù)據(jù),如下圖所示。
當(dāng)程序1要讀取 Kafka 里面下一條數(shù)據(jù)時,Kafka 先把當(dāng)前位置的標(biāo)記向右移動一位,把新的這個值返回出來。標(biāo)記移動與返回這兩個操作合在一起算是一個原子操作,不會出現(xiàn)重復(fù)讀取的問題。
程序1與程序2使用的是不同的標(biāo)記,所以各自的標(biāo)記指向哪個值,是互不影響的。
當(dāng)增加一個程序3的時候,只需要再加一個標(biāo)記即可。新的這個標(biāo)記也不受前兩個標(biāo)記的影響。
這就實(shí)現(xiàn)了在多個不同的程序讀取 Kafka 時,各自互不影響。
現(xiàn)在如果你覺得程序1消費(fèi)太慢了,把程序1同時運(yùn)行了3次,那么由于標(biāo)記和移位是原子操作,即使你看起來程序是同時去讀取 Kafka,但在內(nèi)部 Kafka 也會對他們進(jìn)行“排隊(duì)”,從而使得他們返回的結(jié)果不重復(fù),不遺漏。
如果你在網(wǎng)上看 Kafka 的教程,你會發(fā)現(xiàn)他們提到了一個叫做 Offset 的東西,實(shí)際上就是本文所說的各個程序里面指向當(dāng)前數(shù)據(jù)的標(biāo)記。
你還會看到一個關(guān)鍵詞叫做Group,實(shí)際上對應(yīng)到本文的程序1,程序2和程序3。
對同一個隊(duì)列,如果多個程序使用不同的Group消費(fèi),那么他們讀取的數(shù)據(jù)就互不干擾。
對同一個隊(duì)列,相同 Group 的多個進(jìn)程在消費(fèi)數(shù)據(jù)時,看起來就像是在對 Redis 進(jìn)行 lpop 操作一樣。
最后,你在網(wǎng)上關(guān)于 Kafka 的文章里面,一定會看到一個詞叫做Paritition或者中文分片。而且你會發(fā)現(xiàn)你無法理解這個東西。
沒關(guān)系,忘記它吧。你只需要知道,一個 Topic 有多少個 Partition,那么你最多能啟動多少個進(jìn)程讀取同一個 Group。——如果一個Topic有3個Partition,那么你只能最多開3個進(jìn)程同時讀相同的 Group。Topic如果有5個Partition,那么你只能最多開5個進(jìn)程讀同一個 Group。

































