本文包括kafka的定義、安裝尺借、啟動(dòng)绊起、架構(gòu)、工作流程燎斩、原理虱歪、生產(chǎn)者、消費(fèi)者栅表、分區(qū)笋鄙、ISR節(jié)點(diǎn)、HW怪瓶、分區(qū)分配策略萧落、offset、高效讀寫機(jī)制洗贰。
1. Kafka 概述
1.1 定義
Kakfa 是一個(gè)分布式的基于發(fā)布/訂閱模式的消息隊(duì)列(message queue)铐尚,主要應(yīng)用于大數(shù)據(jù)的實(shí)時(shí)處理領(lǐng)域。
1.2 消息隊(duì)列
1.2.1 傳統(tǒng)消息隊(duì)列與新式消息隊(duì)列模式
上面是傳統(tǒng)的消息隊(duì)列哆姻,比如一個(gè)用戶要注冊信息宣增,當(dāng)用戶信息寫入數(shù)據(jù)庫后,后面還有一些其他流程矛缨,比如發(fā)送短信爹脾,則需要等這些流程處理完成后,再返回給用戶箕昭。而新式隊(duì)列灵妨,比如一個(gè)用戶注冊信息,數(shù)據(jù)直接丟進(jìn)數(shù)據(jù)庫落竹,就直接返回給用戶成功泌霍。
1.2.2 使用消息隊(duì)列的好處
- 解耦
- 可恢復(fù)性
- 緩沖
- 靈活性與峰值處理能力
- 異步通信
1.2.3 消息隊(duì)列的模式
1) 點(diǎn)對點(diǎn)模式
消息生產(chǎn)者發(fā)送消息到消息隊(duì)列中,然后消息消費(fèi)者從隊(duì)列中取出并且消費(fèi)消息述召,消息被消費(fèi)后朱转,隊(duì)列中不在存儲(chǔ)蟹地。所以消息消費(fèi)者不可能消費(fèi)到已經(jīng)被消費(fèi)的消息;隊(duì)列支持存在多個(gè)消費(fèi)者藤为,但是對于一個(gè)消息而言怪与,只會(huì) 有一個(gè)消費(fèi)者可以消費(fèi);如果想發(fā)給多個(gè)消費(fèi)者缅疟,則需要多次發(fā)送該條消息分别。
2) 發(fā)布/訂閱模式(一對多,消費(fèi)者消費(fèi)數(shù)據(jù)之后不會(huì)清除消息)
消息生產(chǎn)者將消息發(fā)布到 topic 中存淫,同時(shí)有多個(gè)消息消費(fèi)者(訂閱)消費(fèi)該消息耘斩。和點(diǎn)對點(diǎn)的方式不同,發(fā)布到 topic 的消息會(huì)被所有的訂閱者消費(fèi)桅咆;但是數(shù)據(jù)保留是期限的括授,默認(rèn)是 7 天,因?yàn)樗皇谴鎯?chǔ)系統(tǒng)轧邪。Kafka 就是這種模式的。有兩種方式羞海,一種是是消費(fèi)者去主動(dòng)去消費(fèi)(拉燃捎蕖)消息,而不是生產(chǎn)者推送消息給消費(fèi)者却邓;另外一種就是生產(chǎn)者主動(dòng)推送消息給消費(fèi)者硕糊,類似公眾號。
1.3 Kafka 基礎(chǔ)架構(gòu)
Kafka 的基礎(chǔ)架構(gòu)主要有 broker腊徙、生產(chǎn)者简十、消費(fèi)者組構(gòu)成,當(dāng)前還包括 ZooKeeper撬腾。
生產(chǎn)者負(fù)責(zé)發(fā)送消息螟蝙,broker 負(fù)責(zé)緩沖消息,broker 中可以創(chuàng)建 topic民傻,每個(gè) topic 又有 partition 和 replication 的概念胰默。
消費(fèi)者組負(fù)責(zé)處理消息,同一個(gè)消費(fèi)者組的中消費(fèi)者不能消費(fèi)同一個(gè) partition 中的數(shù)據(jù)漓踢。消費(fèi)者組主要是提高消費(fèi)能力牵署,比如之前是一個(gè)消費(fèi)者消費(fèi) 100 條數(shù)據(jù),現(xiàn)在是 2 個(gè)消費(fèi)者消費(fèi) 100 條數(shù)據(jù)喧半,可以提高消費(fèi)能力奴迅。所以消費(fèi)者組的消費(fèi)者的個(gè)數(shù)要小于 partition 的個(gè)數(shù),不然就會(huì)有消費(fèi)者沒有 partition 可以消費(fèi)挺据,造成資源的浪費(fèi)取具。
注意:不同消費(fèi)者組的消費(fèi)者是可以消費(fèi)相同的 partition 數(shù)據(jù)脖隶。
Kakfa 如果要組件集群,則只需要注冊到一個(gè) ZooKeeper 中就可以了者填,ZooKeeper 中還保留消息消費(fèi)的進(jìn)度或者說偏移量或者消費(fèi)位置浩村。
0.9 之前的版本偏移量存儲(chǔ)在 ZooKeeper;
0.9 之后的版本偏移量存儲(chǔ)在 Kafka中占哟。Kafka 定義了一個(gè)系統(tǒng) topic心墅,專用用來存儲(chǔ)偏移量的數(shù)據(jù)。
為什么要改榨乎?
主要是考慮到頻繁更改偏移量怎燥,對 ZooKeeper 的壓力較大,而且 Kafka 本身自己的處理也較復(fù)雜蜜暑。
1.4 安裝 Kafka
- Kafka 的安裝只需要解壓安裝包就可以完成安裝铐姚。
tar -zxvf kafka_2.11-2.1.1.tgz -C /usr/local/
- 查看配置文件。
[root@es1 config]# pwd/usr/local/kafka/config[root@es1 config]# lltotal 84-rw-r--r--. 1 root root 906 Feb 8 2019 connect-console-sink.properties-rw-r--r--. 1 root root 909 Feb 8 2019 connect-console-source.properties-rw-r--r--. 1 root root 5321 Feb 8 2019 connect-distributed.properties-rw-r--r--. 1 root root 883 Feb 8 2019 connect-file-sink.properties-rw-r--r--. 1 root root 881 Feb 8 2019 connect-file-source.properties-rw-r--r--. 1 root root 1111 Feb 8 2019 connect-log4j.properties-rw-r--r--. 1 root root 2262 Feb 8 2019 connect-standalone.properties-rw-r--r--. 1 root root 1221 Feb 8 2019 consumer.properties-rw-r--r--. 1 root root 4727 Feb 8 2019 log4j.properties-rw-r--r--. 1 root root 1925 Feb 8 2019 producer.properties-rw-r--r--. 1 root root 6865 Jan 16 22:00 server-1.properties-rw-r--r--. 1 root root 6865 Jan 16 22:00 server-2.properties-rw-r--r--. 1 root root 6873 Jan 16 03:57 server.properties-rw-r--r--. 1 root root 1032 Feb 8 2019 tools-log4j.properties-rw-r--r--. 1 root root 1169 Feb 8 2019 trogdor.conf-rw-r--r--. 1 root root 1023 Feb 8 2019 zookeeper.properties
- 修改配置文件 server.properties肛捍。
設(shè)置 broker.id 這個(gè)是 Kafka 集群區(qū)分每個(gè)節(jié)點(diǎn)的唯一標(biāo)志符隐绵。
- 設(shè)置 Kafka 的數(shù)據(jù)存儲(chǔ)路徑。
注意:這個(gè)目錄下不能有其他非 Kafka 目錄拙毫,不然會(huì)導(dǎo)致 Kafka 集群無法啟動(dòng)依许。
- 設(shè)置是否可以刪除 topic,默認(rèn) Kafka 的 topic 是不允許刪除的缀蹄。
- Kafka 的數(shù)據(jù)保留的時(shí)間峭跳,默認(rèn)是 7 天。
- Log 文件最大的大小缺前,如果 log 文件超過 1 G 會(huì)創(chuàng)建一個(gè)新的文件蛀醉。
- Kafka 連接的 ZooKeeper 的地址和連接 Kafka 的超時(shí)時(shí)間。
- 默認(rèn)的 partition 的個(gè)數(shù)衅码。
1.5 啟動(dòng) Kafka
- 啟動(dòng)方式一拯刁,Kafka 只能單節(jié)點(diǎn)啟動(dòng),所以每個(gè) Kakfa 節(jié)點(diǎn)都需要手動(dòng)啟動(dòng)逝段,下面的方式阻塞的方式啟動(dòng)筛璧。
- 啟動(dòng)方式二,守護(hù)的方式啟動(dòng)惹恃,推薦使用夭谤。
1.6 Kafka 操作
- 查看當(dāng)前 Kafka 集群已有的 topic。
注意:這里連接的 ZooKeeper巫糙,而不是連接的 Kafka朗儒。
- 創(chuàng)建 topic,指定分片和副本個(gè)數(shù)。
說明:replication-factor 副本數(shù)醉锄,replication-factor 分區(qū)數(shù)乏悄,topic 主題名。
如果當(dāng)前 Kafka 集群只有 3 個(gè) broker 節(jié)點(diǎn)恳不,則 replication-factor 最大就是 3 了檩小,下面的例子創(chuàng)建副本為 4,則會(huì)報(bào)錯(cuò)烟勋。
- 刪除 topic规求。
4) 查看 topic 信息。
1.7 啟動(dòng)生產(chǎn)者生產(chǎn)消息卵惦,Kafka 自帶一個(gè)生產(chǎn)者和消費(fèi)者的客戶端
- 啟動(dòng)一個(gè)生產(chǎn)者阻肿,注意此時(shí)連的 9092 端口,連接的 Kafka 集群沮尿。
- 啟動(dòng)一個(gè)消費(fèi)者丛塌,注意此時(shí)連接的還是 9092 端口,在 0.9 版本之前連接的還是 2181 端口畜疾。
這里我們啟動(dòng) 2 個(gè)消費(fèi)者來測試一下赴邻。
說明:如果不指定的消費(fèi)者組的配置文件的話,默認(rèn)每個(gè)消費(fèi)者都屬于不同的消費(fèi)者組啡捶。
- 發(fā)送消息姥敛,可以看到每個(gè)消費(fèi)者都能收到消息。
4)Kakfa 中的實(shí)際數(shù)據(jù)届慈。
2. Kafka 架構(gòu)深入
Kafka 不能保證消息的全局有序徒溪,只能保證消息在 partition 內(nèi)有序忿偷,因?yàn)橄M(fèi)者消費(fèi)消息是在不同的 partition 中隨機(jī)的金顿。
2.1 Kafka 的工作流程
Kafka 中的消息是以 topic 進(jìn)行分類的,生產(chǎn)者生成消息鲤桥、消費(fèi)者消費(fèi)消息都面向 topic揍拆。
Topic 是一個(gè)邏輯上的概念,而 partition 是物理上的概念茶凳。每個(gè) partition 又有副本的概念嫂拴。每個(gè) partition 對應(yīng)于一個(gè) log 文件,該 log 文件中存儲(chǔ)的就是生產(chǎn)者生成的數(shù)據(jù)贮喧,生產(chǎn)者生成的數(shù)據(jù)會(huì)不斷的追加到該 log 的文件末端筒狠,且每條數(shù)據(jù)都有自己的 offset,消費(fèi)者都會(huì)實(shí)時(shí)記錄自己消費(fèi)到了那個(gè) offset箱沦,以便出錯(cuò)的時(shí)候從上次的位置繼續(xù)消費(fèi)辩恼,這個(gè) offset 就保存在 index 文件中。Kafka 的 offset 是分區(qū)內(nèi)有序的,但是在不同分區(qū)中是無順序的灶伊,Kafka 不保證數(shù)據(jù)的全局有序疆前。
2.2 Kafka 原理
由于生產(chǎn)者生產(chǎn)的消息會(huì)不斷追加到 log 文件的末尾,為防止 log 文件過大導(dǎo)致數(shù)據(jù)定位效率低下聘萨,Kafka 采用分片和索引的機(jī)制竹椒,將每個(gè) partition 分為多個(gè) segment,每個(gè) segment 對應(yīng)2個(gè)文件 — index 文件和 log 文件米辐,這 2 個(gè)文件位于一個(gè)相同的文件夾下胸完,文件夾的命名規(guī)則為:topic 名稱 + 分區(qū)序號。
Index 和 log 的文件的文件名是當(dāng)前這個(gè)索引是最小的數(shù)據(jù)的 offset儡循。Kafka 如何快速的消費(fèi)數(shù)據(jù)呢舶吗?
Index 文件中存儲(chǔ)的數(shù)據(jù)的索引信息,第一列是 offset择膝,第二列這這個(gè)數(shù)據(jù)所對應(yīng)的 log 文件中的偏移量誓琼,就像我們?nèi)プx文件,使用 seek() 設(shè)置當(dāng)前鼠標(biāo)的位置一樣肴捉,可以更快的找到數(shù)據(jù)腹侣。
如果要去消費(fèi) offset 為 3 的數(shù)據(jù),首先通過二分法找到數(shù)據(jù)在哪個(gè) index 文件中齿穗,然后在通過 index 中 offset 找到數(shù)據(jù)在 log 文件中的 offset傲隶;這樣就可以快速的定位到數(shù)據(jù),并消費(fèi)窃页。
所以跺株,Kakfa 雖然把數(shù)據(jù)存儲(chǔ)在磁盤中,但是他的讀取速度還是非巢甭簦快的乒省。
3. Kafka 生產(chǎn)者和消費(fèi)者
3.1 Kafka 生產(chǎn)者
Kafka 的 partition 分區(qū)的作用
Kafka 分區(qū)的原因主要就是提供并發(fā)提高性能,因?yàn)樽x寫是 partition 為單位讀寫的畦木;那生產(chǎn)者發(fā)送消息是發(fā)送到哪個(gè) partition 中呢袖扛?
在客戶端中指定 partition;
輪詢(推薦)消息1去 p1十籍,消息2去 p2蛆封,消息3去 p3,消息4去 p1勾栗,消息5去 p2惨篱,消息6去 p3……
3.2 Kafka 如何保證數(shù)據(jù)可靠性呢?****通過 ack 來保證
為保證生產(chǎn)者發(fā)送的數(shù)據(jù)围俘,能可靠的發(fā)送到指定的 topic砸讳,topic 的每個(gè) partition 收到生產(chǎn)者發(fā)送的數(shù)據(jù)后机断,都需要向生產(chǎn)者發(fā)送 ack(確認(rèn)收到),如果生產(chǎn)者收到 ack绣夺,就會(huì)進(jìn)行下一輪的發(fā)送吏奸,否則重新發(fā)送數(shù)據(jù)。
那么 Kafka 什么時(shí)候向生產(chǎn)者發(fā)送 ack陶耍?
確保 follower 和 leader 同步完成奋蔚,leader 在發(fā)送 ack 給生產(chǎn)者,這樣才能確保 leader 掛掉之后烈钞,能在 follower 中選舉出新的 leader 后泊碑,數(shù)據(jù)不會(huì)丟失。
那多少個(gè) follower 同步完成后發(fā)送 ack毯欣?
方案1:半數(shù)已經(jīng)完成同步馒过,就發(fā)送 ack;
方案2:全部完成同步酗钞,才發(fā)送 ack(Kafka采用這種方式)
采用第二種方案后腹忽,設(shè)想以下場景:leader 收到數(shù)據(jù),所有的 follower 都開始同步數(shù)據(jù)砚作,但是有一個(gè) follower 因?yàn)槟撤N故障窘奏,一直無法完成同步,那 leader 就要一直等下葫录,直到他同步完成着裹,才能發(fā)送 ack。這樣就非常影響效率米同,這個(gè)問題怎么解決骇扇?
Leader 維護(hù)了一個(gè)動(dòng)態(tài)的 ISR 列表(同步副本的作用),只需要這個(gè)列表的中的 follower 和 leader 同步面粮;當(dāng) ISR 中的 follower 完成數(shù)據(jù)的同步之后少孝,leader 就會(huì)給生產(chǎn)者發(fā)送 ack,如果 follower 長時(shí)間未向 leader 同步數(shù)據(jù)但金,則該 follower 將被剔除ISR韭山,這個(gè)時(shí)間閾值也是自定義的郁季;同樣 leader 故障后冷溃,就會(huì)從 ISR 中選舉新的 leader。
怎么選擇 ISR 的節(jié)點(diǎn)呢梦裂?
首先通信的時(shí)間要快似枕,要和 leader 要可以很快的完成通信,這個(gè)時(shí)間默認(rèn)是 10s
然后就看 leader 數(shù)據(jù)差距年柠,消息條數(shù)默認(rèn)是 10000 條(后面版本被移除)
為什么移除:因?yàn)?Kafka 發(fā)送消息是批量發(fā)送的凿歼,所以會(huì)一瞬間 leader 接受完成,但是 follower 還沒有拉取,所以會(huì)頻繁踢出和加入ISR答憔,這個(gè)數(shù)據(jù)會(huì)保存到 ZooKeeper 和內(nèi)存中味赃,所以會(huì)頻繁更新 ZooKeeper 和內(nèi)存。
但是對于某些不太重要的數(shù)據(jù)虐拓,對數(shù)據(jù)的可靠性要求不是很高,能夠容忍數(shù)據(jù)的少量丟失,所以沒必要等 ISR 中的 follower 全部接受成功甘畅。所以 Kafka 為用戶提供了三種可靠性級別搂橙,用戶可以根據(jù)可靠性和延遲進(jìn)行權(quán)衡,這個(gè)設(shè)置在kafka的生成中設(shè)置:ack 參數(shù)設(shè)置态兴。
1) acks 為 0
生產(chǎn)者不等 ack狠持,只管往 topic 丟數(shù)據(jù)就可以了,這個(gè)丟數(shù)據(jù)的概率非常高瞻润。
2) ack為 1
leader 落盤后就會(huì)返回 ack喘垂,會(huì)有數(shù)據(jù)丟失的現(xiàn)象,如果 leader 在同步完成后出現(xiàn)故障绍撞,則會(huì)出現(xiàn)數(shù)據(jù)丟失王污。
3) ack為-1(all)
leader 和 follower(ISR)落盤才會(huì)返回 ack,會(huì)有數(shù)據(jù)重復(fù)現(xiàn)象楚午,如果在 leader 已經(jīng)寫完成昭齐,且 follower 同步完成,但是在返回ack的出現(xiàn)故障矾柜,則會(huì)出現(xiàn)數(shù)據(jù)重復(fù)現(xiàn)象阱驾;極限情況下,這個(gè)也會(huì)有數(shù)據(jù)丟失的情況怪蔑,比如 follower 和 leader 通信都很慢里覆,所以 ISR 中只有一個(gè) leader 節(jié)點(diǎn),這個(gè)時(shí)候缆瓣,leader 完成落盤喧枷,就會(huì)返回 ack,如果此時(shí) leader 故障后弓坞,就會(huì)導(dǎo)致丟失數(shù)據(jù)隧甚。
3.3 Kafka 如何保證消費(fèi)數(shù)據(jù)的一致性?****通過HW來保證
LEO:指每個(gè) follower 的最大的 offset渡冻;
HW(高水位):指消費(fèi)者能見到的最大的 offset戚扳,LSR 隊(duì)列中最小的 LEO,也就是說消費(fèi)者只能看到1~6的數(shù)據(jù)族吻,后面的數(shù)據(jù)看不到帽借,也消費(fèi)不了珠增。
避免 leader 掛掉后,比如當(dāng)前消費(fèi)者消費(fèi)8這條數(shù)據(jù)后砍艾,leader 掛了蒂教,此時(shí)比如 f2 成為 leader,f2 根本就沒有9這條數(shù)據(jù)脆荷,那么消費(fèi)者就會(huì)報(bào)錯(cuò)悴品,所以設(shè)計(jì)了 HW 這個(gè)參數(shù),只暴露最少的數(shù)據(jù)給消費(fèi)者简烘,避免上面的問題苔严。
3.3.1 HW 保證數(shù)據(jù)存儲(chǔ)的一致性
1) follower 故障
follower 發(fā)生故障后會(huì)被臨時(shí)提出 LSR,待該 follower 恢復(fù)后孤澎,follower 會(huì)讀取本地的磁盤記錄的上次的 HW届氢,并將該 log 文件高于 HW 的部分截取掉,從 HW 開始向 leader 進(jìn)行同步覆旭,等該 follower 的 LEO 大于等于該 partition 的 hw退子,即 follower 追上leader后,就可以重新加入 LSR型将。
2) leader 故障
leader 發(fā)生故障后寂祥,會(huì)從 ISR 中選出一個(gè)新的 leader,之后七兜,為了保證多個(gè)副本之間的數(shù)據(jù)一致性丸凭,其余的 follower 會(huì)先將各自的 log 文件高于 hw 的部分截掉(新 leader 自己不會(huì)截掉),然后從新的 leader 同步數(shù)據(jù)腕铸。
注意:這個(gè)是為了保證多個(gè)副本間的數(shù)據(jù)存儲(chǔ)的一致性惜犀,并不能保證數(shù)據(jù)不丟失或者不重復(fù)。
3.3.2 精準(zhǔn)一次(冪等性)狠裹,保證數(shù)據(jù)不重復(fù)
ack 設(shè)置為 -1虽界,則可以保證數(shù)據(jù)不丟失,但是會(huì)出現(xiàn)數(shù)據(jù)重復(fù)(at least once)
ack 設(shè)置為 0涛菠,則可以保證數(shù)據(jù)不重復(fù)莉御,但是不能保證數(shù)據(jù)不丟失(at most once)
但是如果魚和熊掌兼得,該怎么辦俗冻?這個(gè)時(shí)候就就引入了 Exact once(精準(zhǔn)一次)礁叔。
在 0.11 版本后,引入冪等性解決 Kakfa 集群內(nèi)部的數(shù)據(jù)重復(fù)言疗,在 0.11 版本之前晴圾,在消費(fèi)者處自己做處理颂砸。如果啟用了冪等性噪奄,則 ack 默認(rèn)就是-1死姚,Kafka 就會(huì)為每個(gè)生產(chǎn)者分配一個(gè) pid,并未每條消息分配 seqnumber勤篮,如果 pid都毒、partition、seqnumber 三者一樣碰缔,則 Kafka 認(rèn)為是重復(fù)數(shù)據(jù)账劲,就不會(huì)落盤保存;但是如果生產(chǎn)者掛掉后金抡,也會(huì)出現(xiàn)有數(shù)據(jù)重復(fù)的現(xiàn)象瀑焦;所以冪等性解決在單次會(huì)話的單個(gè)分區(qū)的數(shù)據(jù)重復(fù),但是在分區(qū)間或者跨會(huì)話的是數(shù)據(jù)重復(fù)的是無法解決的梗肝。
3.4 Kafka 消費(fèi)者
3.4.1 消費(fèi)方式
消息隊(duì)列有兩種消費(fèi)消息的方式榛瓮,push(微信公眾號)、pull(kafka)巫击。push 模式很難適應(yīng)消費(fèi)速率不同的消費(fèi)者禀晓,因?yàn)橄M(fèi)發(fā)送速率是由 broker 決定的,他的目標(biāo)是盡可能以最快的的速度傳遞消息坝锰,但是這樣很容易造成消費(fèi)者來不及處理消息粹懒,典型的表現(xiàn)就是拒絕服務(wù)以及網(wǎng)絡(luò)擁塞。而 pull 的方式可以消費(fèi)者的消費(fèi)能力以適當(dāng)?shù)乃俾氏M(fèi)消息顷级。
pull 模式的不足之處是如果 Kafka 沒有數(shù)據(jù)凫乖,消費(fèi)者可能會(huì)陷入死循環(huán),一直返回空數(shù)據(jù)弓颈,針對這一點(diǎn)拣凹,Kafka 消費(fèi)者在消費(fèi)數(shù)據(jù)時(shí)候回傳遞一個(gè) timeout 參數(shù),如果當(dāng)時(shí)沒有數(shù)據(jù)可供消費(fèi)恨豁,消費(fèi)者會(huì)等待一段時(shí)間在返回嚣镜。
3.4.2 分區(qū)分配策略
一個(gè)消費(fèi)者組有多個(gè)消費(fèi)者,一個(gè) topic 有多個(gè) partition橘蜜。所以必然會(huì)涉及到 partition 的分配問題菊匿,即確定哪個(gè) partition 由哪個(gè)消費(fèi)者來消費(fèi)。Kafka 提供兩種方式计福,一種是輪詢(RountRobin)對于 topic 組生效跌捆,一種是(Range)對于單個(gè)topic生效
輪詢:前置條件是需要一個(gè)消費(fèi)者里的消費(fèi)者訂閱的是相同的 topic。不然就會(huì)出現(xiàn)問題象颖;非默認(rèn)的的方式佩厚。
同一個(gè)消費(fèi)者組里的消費(fèi)者不能同時(shí)消費(fèi)同一個(gè)分區(qū),比如三個(gè)消費(fèi)者消費(fèi)一個(gè) topic 的 9 個(gè)分區(qū)说订。
如果一個(gè)消費(fèi)者組里有2個(gè)消費(fèi)者抄瓦,這個(gè)消費(fèi)者組里同時(shí)消費(fèi) 2 個(gè) topic潮瓶,每個(gè) topic 又有三個(gè) partition。首先會(huì)把 2 個(gè) topic 當(dāng)做一個(gè)主題钙姊,然后根據(jù) topic 和 partition 做 hash毯辅,然后在按照 hash 排序。然后輪詢分配給一個(gè)消費(fèi)者組中的 2 個(gè)消費(fèi)者煞额。
如果是下面這樣的方式訂閱的呢思恐?
比如有 3 個(gè) topic,每個(gè) topic 有 3 個(gè) partition膊毁,一個(gè)消費(fèi)者組中有 2 個(gè)消費(fèi)者胀莹。消費(fèi)者1訂閱 topic1 和 topic2,消費(fèi)者2訂閱 topic2 和 topic3婚温。那么這樣的場景嗜逻,使用輪訓(xùn)的方式訂閱 topic 就會(huì)有問題。
如果是下面這種方式訂閱呢缭召?
比如有2個(gè) topic栈顷,每個(gè) topic 有3個(gè) partition,一個(gè)消費(fèi)者組 有2個(gè)消費(fèi)者嵌巷,消費(fèi)者1訂閱 topic1萄凤,消費(fèi)者2訂閱 topic2,這樣使用輪訓(xùn)的方式訂閱 topic 也會(huì)有問題搪哪。
所以我們一直強(qiáng)調(diào)靡努,使用輪訓(xùn)的方式訂閱 topic 的前提是一個(gè)消費(fèi)者組中的所有消費(fèi)者訂閱的主題是一樣的;所以輪詢的方式不是 Kafka 默認(rèn)的方式晓折;Range 是按照單個(gè) topic 來劃分的惑朦,默認(rèn)的分配方式。
Range 的問題會(huì)出現(xiàn)消費(fèi)者數(shù)據(jù)不均衡的問題漓概。比如下面的例子漾月,一個(gè)消費(fèi)者組訂閱了 2 個(gè) topic,就會(huì)出現(xiàn)消費(fèi)者1消費(fèi) 4 個(gè) partition胃珍,而另外一個(gè)消費(fèi)者只消費(fèi) 2 個(gè) partition梁肿。
分區(qū)策略什么時(shí)候會(huì)觸發(fā)呢?當(dāng)消費(fèi)者組里的消費(fèi)者個(gè)數(shù)變化的時(shí)候觅彰,會(huì)觸發(fā)分區(qū)策略調(diào)整吩蔑,比如消費(fèi)者里增加消費(fèi)者,或者減少消費(fèi)者填抬。
3.4.3 維護(hù) offset
由于消費(fèi)者在消費(fèi)過程中可能會(huì)出現(xiàn)斷電宕機(jī)等故障烛芬,消費(fèi)者恢復(fù)后,需要從故障前的位置繼續(xù)消費(fèi),所以消費(fèi)者需要實(shí)施記錄自己消費(fèi)哪個(gè) offset赘娄,以便故障恢復(fù)后繼續(xù)消費(fèi)仆潮。
Offset保存的位置有2個(gè),一個(gè) ZooKeeper擅憔,一個(gè)是 Kafka鸵闪。首先看下 offset 保存到 ZooKeeper檐晕,由消費(fèi)者組暑诸、topic、partition 三個(gè)元素確定唯一的 offset辟灰。
所以消費(fèi)者組中的某個(gè)消費(fèi)者掛掉之后个榕,或者的消費(fèi)者還是可以拿到這個(gè) offset。
Controller 這個(gè)節(jié)點(diǎn)和 ZooKeeper 通信芥喇,同步數(shù)據(jù)西采,這個(gè)節(jié)點(diǎn)就是誰先起來,誰就先注冊 controller继控,誰就是 controller械馆。其他節(jié)點(diǎn)和 controller 信息保持同步。
3.4.5 消費(fèi)者組的案例
修改消費(fèi)者組 id
啟動(dòng)一個(gè)消費(fèi)者發(fā)送 3 條數(shù)據(jù)武通。
指定消費(fèi)者組啟動(dòng)消費(fèi)者霹崎,啟動(dòng)三個(gè)消費(fèi)者,可以看到每個(gè)消費(fèi)者消費(fèi)了一條數(shù)據(jù)冶忱。
在演示下不同組可以消費(fèi)同一個(gè) topic 的尾菇,我們看到 2 個(gè)消費(fèi)者的消費(fèi)者都消費(fèi)到同一條數(shù)據(jù)。再次啟動(dòng)一個(gè)消費(fèi)者囚枪,這個(gè)消費(fèi)者屬于另外一個(gè)消費(fèi)者組派诬。
4 Kafka 的高效讀寫機(jī)制
4.1 分布式部署
多節(jié)點(diǎn)并行操作。
4.2链沼、順序?qū)懘疟P
Kafka 的 producer 生產(chǎn)數(shù)據(jù)默赂,要寫入到 log 文件中,寫的過程中一直追加到文件末尾括勺,為順序?qū)懛趴桑倬W(wǎng)有數(shù)據(jù)表明。同樣的磁盤朝刊,順序?qū)懩艿?600M/S耀里,而隨機(jī)寫只有 100K/S。這與磁盤的機(jī)械結(jié)構(gòu)有關(guān)拾氓,順序?qū)懼钥旆肟妫且驗(yàn)槠涫∪チ舜罅看蓬^尋址的時(shí)間。
4.3、零復(fù)制技術(shù)
正常情況下房官,先把數(shù)據(jù)讀到內(nèi)核空間趾徽,在從內(nèi)核空間把數(shù)據(jù)讀到用戶空間,然后在調(diào)操作系統(tǒng)的 IO 接口寫到內(nèi)核空間翰守,最終在寫到硬盤中孵奶。
Kafka 是這樣做的,直接在內(nèi)核空間流轉(zhuǎn) IO 流蜡峰,所以 Kafka 的性能非常高了袁。
5. ZooKeeper 在 Kafka 中的作用
Kafka 集群中有一個(gè) broker 會(huì)被選舉為 controller,負(fù)責(zé)管理集群 broker 的上下線湿颅,所有的 topic 的分區(qū)副本分配和 leader 選舉等工作载绿。