kafka原理總結(jié)
1 架構(gòu)圖
如上圖所示歉眷,kafka架構(gòu)組成為 一個kafka broker集群(多個broker組成)颤枪,一個zookeeper集群,若干個 生成者和消費者直連broker進(jìn)行生產(chǎn)和消費畏纲。
生產(chǎn)者向kafka集群push消息,消費者從kafka集群pull消息進(jìn)行消息艘蹋。broker集群和消費者向zookeeper注冊,由zookeeper進(jìn)行管理女阀,zookeeper進(jìn)行l(wèi)eader選舉和consumer group 變化時進(jìn)行relanlance
概念
-
Broker
消息中間件處理節(jié)點(服務(wù)器)屑迂,一個節(jié)點就是一個broker浸策,一個Kafka集群由一個或多個broker組成屈糊。消息內(nèi)容存儲在broker中
-
Producer
生產(chǎn)者琼了,負(fù)責(zé)向kafka broker發(fā)送消息(push方式)
-
Consumer
消費者夫晌,負(fù)責(zé)從kafka broker拉去消息(pull方式), 多個消費者組成一個consumer group
-
Topic
消息的分類昧诱,同一類消息一個topic
-
Partition
同一個topic上面的消息晓淀,進(jìn)行分區(qū)來存儲盏档,一個topic被有序分分成若干個分區(qū),相當(dāng)于topic的細(xì)分蜈亩。
2 Topic、Broker稚配、Parttion 的關(guān)系
在理解Tpoic、Broker午衰、Partition之前,我們先看一下他們之前的關(guān)系圖
如上圖所有臊岸,一個topic創(chuàng)建4個分區(qū)的情況下尊流,在每個broker有4個分區(qū)。zookeeper會在這些分區(qū)中選擇一個分區(qū)作為主分區(qū)奠旺,即分區(qū)leader。Producer在生產(chǎn)消息時候响疚,直連broker。broker從zookeeper獲取當(dāng)前哪些節(jié)點存活忿晕,主分區(qū)在哪個服務(wù),producer就把消息發(fā)送給對應(yīng)的主分區(qū)践盼。主分區(qū)同步到各個follower分區(qū)。
從上圖可以發(fā)現(xiàn)渔伯。由于partition leader會分布在不同分區(qū)(zookeeper根據(jù)節(jié)點情況,做負(fù)載均衡锣吼,選舉leader),broker節(jié)點越多玄叠,kafka的吞吐也就越高。
3 Consumer & Consumer Group 的關(guān)系
kafka官網(wǎng)給出一個關(guān)于kafka消費者和消費者group的關(guān)系读恃,如下:
這個圖可以清晰的說明Consumer 、Consumer Group 疹吃、Partition的關(guān)系。
同一個分區(qū)的消息互墓,可以被不同組的消費者消費。但同一個組內(nèi)的消費篡撵,對于同一個分區(qū)豆挽,只能有一個消費來消費育谬。
不同分區(qū)可以被同一個消費者消費
同一個Consumer Group中帮哈,消費者和分區(qū)的關(guān)系是 1對多。
4 Kafka數(shù)據(jù)的存儲
- kafka數(shù)據(jù)的存儲
kafka的消息是直接存放在硬盤上娘侍,并沒有向其他的一些消息同寫在內(nèi)存,至于設(shè)計的原因嚎杨,kafka官方文檔有解析(kafka為何直接寫硬盤-持久化)。
kafka采用分區(qū)的概念枫浙,把topic分為多個分區(qū),生產(chǎn)者push的數(shù)據(jù)箩帚,會被分配(使用輪詢或者h(yuǎn)ash的方式)到不同的分區(qū)進(jìn)行寫入黄痪。kafka寫數(shù)據(jù)是以追加的方式寫入到Partition中紧帕。
例如桅打,如果使用用戶ID作為key轻纪,則用戶相關(guān)的所有數(shù)據(jù)都會被分發(fā)到同一個分區(qū)上叠纷。 這允許消費者在消費數(shù)據(jù)時做一些特定的本地化處理。這樣的分區(qū)風(fēng)格經(jīng)常被設(shè)計用于一些本地處理比較敏感的消費者涩嚣。
消息文件存在broker配置文件配置的消息目錄中 log.dirs=/tmp/kafka.log
- zookeeper在kafka中管理哪些東西
從kafka的結(jié)構(gòu)圖掂僵,我們可以發(fā)現(xiàn)和zookeeper產(chǎn)生關(guān)聯(lián)的之后 broker和Consumer航厚。所以锰蓬,很明顯zookeeper在kafka架構(gòu)中主要管理broker和consumer的相關(guān)信息。
事實上芹扭,zookeeper的確實是做的這樣的工作。
-
broker信息
broker啟動后舱卡,向zookeeper進(jìn)行注冊。Broker在zookeeper中保存為一個臨時節(jié)點矫钓,節(jié)點的路徑是/brokers/ids/[brokerid],每個節(jié)點會保存對應(yīng)broker的IP以及端口等信息.
-
topic信息
kafka的topic會分成不同分區(qū)。這些信息同樣會存儲在zookeeper上面新娜。這也會為什么創(chuàng)建topic的時候需要傳入zookeeper的地址原因既绩。
-
生產(chǎn)負(fù)載均衡
這些 broker信息和topic概龄、Partition信息存儲在zookeeper上之后熬词,zookeeper就可以Topic上的watcher(zookeeper watches)動態(tài)感知節(jié)點變化,根據(jù)節(jié)點的當(dāng)前狀態(tài)進(jìn)行生產(chǎn)者負(fù)載(選擇適合的節(jié)點作為 Partition Leader)互拾。
-
消費者信息
消費者監(jiān)聽topic的時候,會向zookeeper進(jìn)行注冊颜矿,消費的信息、消費者組的信息都會存儲在zookeeper中田篇。
-
消費負(fù)載均衡
同樣的替废,有消費者信息泊柬、消費者組的信息、broker信息 這些都在zookeeper中兽赁,zookeeper在消費者節(jié)點發(fā)生變化,broker發(fā)生變化的時候刀崖,進(jìn)行負(fù)載。(zookeeper的監(jiān)聽機(jī)制馆截,真的是個好東西)
-
消費OffSet
kafka的消息是不斷在Partition后面進(jìn)行追加的,消費者通過一個offset定位每次消費的起點蜡娶,拉取partition中從offset之后的所有信息映穗。這個offset直接決定消費者可以看到的信息的范圍翎蹈,這個數(shù)據(jù)也被存儲在zookeeper中男公。每個消費者消費時候根據(jù)zookeeper中的offset確認(rèn)當(dāng)前應(yīng)該消費的數(shù)據(jù)。需要注意的是枢赔,將來的更新的kafka版本中,可能會棄用zookeeper存儲offset的機(jī)制踏拜。以下是kafka關(guān)于此的說法
topic的consumer也在zookeeper中注冊自己,以便相互協(xié)調(diào)和平衡數(shù)據(jù)的消耗肮塞。consumer也可以通過設(shè)置offsets.storage = zookeeper將他們的偏移量存儲在zookeeper中。但是枕赵,這個偏移存儲機(jī)制將在未來的版本中被棄用。因此拷窜,建議將數(shù)據(jù)遷移到kafka中。
5 消息的發(fā)送和消費
- push 和 pull 機(jī)制的原理
關(guān)于push-based 篮昧,pull-based 即 基于推送,或者基于拉取懊昨。不管是push-based還是 pull-based都有其優(yōu)點和缺點。kafka的設(shè)計的時候酵颁,producer 把數(shù)據(jù) push 到 broker,然后 consumer 從 broker 中 pull 數(shù)據(jù)材义。
了解push-based pull-based嫁赏,我們從幾個問題出發(fā),或許會更加清晰一些潦蝇。
-
消息生產(chǎn)為什么選擇使用push方式,而不使用pull呢 贤牛?
如果生產(chǎn)使用拉取方式,即 producer生產(chǎn)消息之后殉簸,存儲在生產(chǎn)者本地,broker在從producer拉取般卑。這種方式有明顯的缺點就是爽雄,broker控制者消息的傳輸速率蝠检,加重了broker負(fù)擔(dān)挚瘟,broker要不斷獲取信息。即使在沒有消息產(chǎn)生的時候乘盖,broker也需要不斷的去拉取。并且其消息時效性會有缺失(生產(chǎn)者先緩存)订框。而生產(chǎn)環(huán)節(jié),使用push可以上消息快速到達(dá)中間,不需要時效確實少浪腐。
-
生產(chǎn)和消費為什么不全push顿乒?
生產(chǎn)環(huán)節(jié)议街,使用push和消息推給中間件,消費時候為什么不也直接把消息推送給消費者欲侮?這樣消息不是更加實時嗎环揽?確實芍殖,如果使用全 push-based 的方式,確實是這樣蛤售,但是這樣的設(shè)計會有一個明顯的缺點妒潭,如果生產(chǎn)者消息生產(chǎn)的速率比較快。消費者會處理不過來雳灾,加重了消費者的負(fù)荷,相反谎亩,如果生產(chǎn)消息使用push, push過來的消息存儲中間件(相當(dāng)于做了一個緩沖)因此可以放心大膽的生產(chǎn)消息,消費根據(jù)自己的情況主動pull進(jìn)行消費就會好很多摸吠。但是此做法,在部分情況下寸痢,會喪失實時性。
-
消費pull缺點
消費環(huán)節(jié)使用pull的方式紊选,利用中間件緩存數(shù)據(jù),消費根據(jù)自己的負(fù)載來進(jìn)行消費兵罢,上面提到的,1 可能導(dǎo)致時效性的喪失卖词,2. Consumer可能會在一個緊密的循環(huán)中結(jié)束輪詢吏夯,實際上 busy-waiting 直到數(shù)據(jù)到來即横。
- 消息的發(fā)送
kafka在發(fā)送消息時候噪生,Producer直連broker东囚,從broker獲取當(dāng)前存活的broker節(jié)點,找到topic對用的partition leader页藻,通過文件追加的方式,把數(shù)據(jù)寫到對應(yīng)topic的broker的 partition leader中璃吧。partition leader同步數(shù)據(jù)到各個follower。
此過程中畜挨,zookeeper 負(fù)責(zé)選舉 partition leader來做到負(fù)載均衡,同時生產(chǎn)者生產(chǎn)消息的時候,利用partition(輪詢或是通過key進(jìn)hash的方式確定分區(qū))設(shè)計膝晾,做到生產(chǎn)負(fù)載均衡。
同時血当,kafka也提供了在生產(chǎn)者本省做內(nèi)存緩存消息之后在做批量發(fā)送的方式,來減少網(wǎng)絡(luò)消耗落恼。
- 消息的消費
Consumer消費消息的時候,通過zookeeper獲取到消費topic的partition的位置offset佳谦,然后一次拉取直連的broker中從offset開始的之后所有的數(shù)據(jù)進(jìn)行消費
6 關(guān)于消息交付
- At most once——消息可能會丟失但絕不重傳滋戳。
- At least once——消息可以重傳但絕不丟失钻蔑。
- Exactly once——這正是人們想要的, 每一條消息只被傳遞一次.
以下下為kafka的實現(xiàn)奸鸯, 更加詳細(xì)的,參考 kafka中文社區(qū)-文檔-設(shè)計思想-4.6 消息交付語義
那么 exactly once 語義(即你真正想要的東西)呢娄涩?當(dāng)從一個 kafka topic 中消費并輸出到另一個 topic 時 (正如在一個Kafka Streams 應(yīng)用中所做的那樣),我們可以使用我們上文提到的 0.11.0.0 版本中的新事務(wù)型 producer,并將 consumer 的位置存儲為一個 topic 中的消息努隙,所以我們可以在輸出 topic 接收已經(jīng)被處理的數(shù)據(jù)的時候孔轴,在同一個事務(wù)中向 Kafka 寫入 offset剃法。如果事務(wù)被中斷路鹰,則消費者的位置將恢復(fù)到原來的值,而輸出 topic 上產(chǎn)生的數(shù)據(jù)對其他消費者是否可見晋柱,取決于事務(wù)的“隔離級別”。 在默認(rèn)的“read_uncommitted”隔離級別中雁竞,所有消息對 consumer 都是可見的,即使它們是中止的事務(wù)的一部分彪腔,但是在“read_committed”的隔離級別中,消費者只能訪問已提交的事務(wù)中的消息(以及任何不屬于事務(wù)的消息)德挣。
參考資料: