消息隊(duì)列之Kafka-引言

1、Kafka是什么

Kafka 最早是由 LinkedIn 公司采用Scala語(yǔ)言開(kāi)發(fā)的一個(gè)多分區(qū)、多副本且基于ZooKeeper協(xié)調(diào)的分布式消息系統(tǒng),現(xiàn)已成為 Apache 的頂級(jí)項(xiàng)目。

Apache Kafka與傳統(tǒng)消息系統(tǒng)相比,有以下特點(diǎn):

  • 同時(shí)為發(fā)布和訂閱提供高吞吐量
    Kafka 的設(shè)計(jì)目標(biāo)是以時(shí)間復(fù)雜度為 O(1) 的方式提供消息持久化能力,即使對(duì)TB 級(jí)以上數(shù)據(jù)也能保證常數(shù)時(shí)間的訪問(wèn)性能。即使在非常廉價(jià)的商用機(jī)器上也能做到單機(jī)支持每秒 100K 條消息的傳輸。
  • 消息持久化
    將消息持久化到磁盤,因此可用于批量消費(fèi),例如 ETL 以及實(shí)時(shí)應(yīng)用程序。通過(guò)將數(shù)據(jù)持久化到硬盤以及 replication 防止數(shù)據(jù)丟失。
  • 分布式
    支持 Server 間的消息分區(qū)及分布式消費(fèi),同時(shí)保證每個(gè) partition 內(nèi)的消息順序傳輸。這樣易于向外擴(kuò)展,所有的producer、broker 和 consumer 都會(huì)有多個(gè),均為分布式的。無(wú)需停機(jī)即可擴(kuò)展機(jī)器。
  • 消費(fèi)消息采用 pull 模式
    消息被處理的狀態(tài)是在 consumer 端維護(hù),而不是由 server 端維護(hù),broker 無(wú)狀態(tài),consumer 自己保存 offset。

2、體系架構(gòu)

1.jpeg
  • Producer
    通過(guò)push模式向Kafka Broker發(fā)送消息。發(fā)送的消息可以是網(wǎng)站的頁(yè)面訪問(wèn)、服務(wù)器日志,也可以是CPU和內(nèi)存相關(guān)的系統(tǒng)資源信息。
  • Broker
    用于存儲(chǔ)消息的服務(wù)器,可以簡(jiǎn)單地看做一個(gè)獨(dú)立的Kafka實(shí)例。Kafka Broker支持水平擴(kuò)展。Kafka Broker節(jié)點(diǎn)的數(shù)量越多,Kafka集群的吞吐率越高。
  • Consumer
    通過(guò)pull模式從Broker訂閱并消費(fèi)消息。每個(gè) Consumer 屬于一個(gè)特定的 Consumer Group(可為每個(gè) Consumer 指定Group Name,若不指定 Group Name 則屬于默認(rèn)的 Group)。
  • Zookeeper
    管理集群的配置、選舉leader分區(qū),并且在Consumer Group發(fā)生變化時(shí),進(jìn)行負(fù)載均衡。

3、Topic與Partition

一個(gè)消息中間件,隊(duì)列不單單只有一個(gè),我們往往會(huì)有多個(gè)隊(duì)列,而我們生產(chǎn)者和消費(fèi)者就得知道:把數(shù)據(jù)丟給哪個(gè)隊(duì)列,從哪個(gè)隊(duì)列消息。我們需要給隊(duì)列取名字,叫做topic

2.png

為了提高一個(gè)topic的吞吐量,Kafka會(huì)把topic進(jìn)行分區(qū)(partition)。所以,生產(chǎn)者實(shí)際上是往topic的一個(gè)partition發(fā)送數(shù)據(jù),而消費(fèi)者實(shí)際上頁(yè)是從一個(gè)topic的partition拉取數(shù)據(jù):

3.png

Kafka可以保證單個(gè)partition的寫入是有順序的。如果要保證全局有序,那只能寫入一個(gè)partition中。如果要消費(fèi)也有序,消費(fèi)者也只能有一個(gè)。

凡是分布式就無(wú)法避免網(wǎng)絡(luò)抖動(dòng)/機(jī)器宕機(jī)等問(wèn)題的發(fā)生,很有可能消費(fèi)者A讀取了數(shù)據(jù),還沒(méi)來(lái)得及消費(fèi),就掛掉了。Zookeeper發(fā)現(xiàn)消費(fèi)者A掛了,讓消費(fèi)者B去消費(fèi)原本消費(fèi)者A的分區(qū),等消費(fèi)者A重連的時(shí)候,發(fā)現(xiàn)已經(jīng)重復(fù)消費(fèi)同一條數(shù)據(jù)了。如果業(yè)務(wù)上不允許重復(fù)消費(fèi)的問(wèn)題,最好消費(fèi)者那端做業(yè)務(wù)上的校驗(yàn)。

一個(gè)broker就是一個(gè)kafka服務(wù)器,多個(gè)broker構(gòu)成一個(gè)kafka集群。一個(gè)topic會(huì)分為多個(gè)partition,partition會(huì)分布在不同的broker中。

也就是說(shuō),Kafka是天然分布式的

4、多副本機(jī)制

既然是分布式,肯定會(huì)有單點(diǎn)問(wèn)題:如果其中一臺(tái)broker掛了,怎么辦?

Kafka 為分區(qū)引入了多副本 (Replica) 機(jī)制, 通過(guò)增加副本數(shù)量可以提升容災(zāi)能力。比如,現(xiàn)在我們有三個(gè)partition,分別存在三臺(tái)broker上。每個(gè)partition都會(huì)備份,這些備份散落在不同的broker上:

4.png

紅色塊的partition代表的是主分區(qū),紫色的partition塊代表的是備份分區(qū)。生產(chǎn)者往topic丟數(shù)據(jù),是與主分區(qū)交互,消費(fèi)者消費(fèi)topic的數(shù)據(jù),也是與主分區(qū)交互。

備份分區(qū)僅僅用作于備份,不做讀寫。如果某個(gè)Broker掛了,那就會(huì)選舉出其他Broker的partition來(lái)作為主分區(qū),這就實(shí)現(xiàn)了高可用。

分區(qū)中的所有副本統(tǒng)稱為 AR ( Assigned Replicas) 。 所有與 leader 副本保持 一定程度同步的副本(包括 leader 副本在內(nèi)〕組成 ISR (In-Sync Replicas ) , ISR 集合是 AR 集合中 的一個(gè)子 集 。 消息會(huì)先發(fā)送到 leader 副本,然后 follower 副本才能從 leader 副本中拉取消息進(jìn)行同步, 同步期間內(nèi) follower 副本相對(duì)于 leader 副本而言會(huì)有一定范圍的滯后,這個(gè)范圍可以通過(guò)參數(shù)進(jìn)行配置 。 與 leader 副本同步滯后過(guò)多的副本(不包 括 leader 副本)組成 OSR ( Out-of-Sync Replicas),由 此可見(jiàn): AR=ISR+OSR。 在正常情況下, 所有的 follower副本都應(yīng)該與 leader副本保持一定程度的同步,即 AR=ISR, OSR 集合為空。

由此可見(jiàn), Kafka 的復(fù)制機(jī)制既不是完全的同步復(fù)制,也不是單純的異步復(fù)制。事實(shí)上, 同步復(fù)制要求所有能工作的 folower 副本都復(fù)制完,這條消息才會(huì)被確認(rèn)為已成功提交,這種復(fù)制方式極大地影響了性能。而在異步復(fù)制方式下, follower 副本異步地從 leader 副本中 復(fù)制數(shù) 據(jù),數(shù)據(jù)只要被 leader 副本寫入就被認(rèn)為已經(jīng)成功提交。在這種情況下,如果 follower 副本都 還沒(méi)有復(fù)制完而落后于 leader 副本,突然 leader 副本著機(jī),則會(huì)造成數(shù)據(jù)丟失。 Kafka 使用的這 種 ISR 的方式則有效地權(quán)衡了數(shù)據(jù)可靠性和性能之間的關(guān)系。

ISR 與 HWLEO 也有緊密的關(guān)系 。 HW 是 High Watermark 的縮寫,俗稱高水位,它標(biāo)識(shí)了一個(gè)特定的消息偏移量(offset),消費(fèi)者只能拉取到這個(gè) offset之前的消息。

如下圖 所示,它代表一個(gè)日志文件,這個(gè)日志文件中有 9 條消息,第一條消息的 offset 為 0,最后一條消息的 offset為 8, offset為 9 的消息用虛線框表示,代表下 一條待寫入 的消息 。日志文件的 HW 為 6,表示消費(fèi)者只能拉取到 offset 在 0 至 5 之間的消息, 而 offset 為 6 的消息對(duì)消 費(fèi)者而言是不可見(jiàn) 的 。

5.png

LEO 是 Log End Offset 的縮寫,它標(biāo)識(shí)當(dāng)前日志文件中下一條待寫入消息 的 offset,上圖 中offset為9的位置即為當(dāng)前日志文件的LEO, LEO的大小相當(dāng)于當(dāng)前日志分區(qū)中最后一條消 息的 offset值加 l。分區(qū) ISR集合中的每個(gè)副本都會(huì)維護(hù)自身的 LEO,而ISR集合中最小的 LEO 即為分區(qū)的 HW ,對(duì)消費(fèi)者而言只能消費(fèi) HW 之前的消息。

為了保證消息的持久化,Kafka會(huì)將partition的數(shù)據(jù)寫在磁盤(消息日志),不過(guò)Kafka只允許追加寫入(順序訪問(wèn)),避免緩慢的隨機(jī) I/O 操作。當(dāng)然,Kafka也不是partition一有數(shù)據(jù)就立馬將數(shù)據(jù)寫到磁盤上,它會(huì)先緩存一部分,等到足夠多數(shù)據(jù)量或等待一定的時(shí)間再批量寫入。

5、消費(fèi)者組

6.png

生產(chǎn)者可以有多個(gè),消費(fèi)者也可以有多個(gè)。像上面圖的情況,是一個(gè)消費(fèi)者消費(fèi)三個(gè)分區(qū)的數(shù)據(jù)。多個(gè)消費(fèi)者可以組成一個(gè)消費(fèi)者組。

  • 如果消費(fèi)者組中的某個(gè)消費(fèi)者掛了,那么其中一個(gè)消費(fèi)者可能就要消費(fèi)兩個(gè)partition了

  • 如果只有三個(gè)partition,而消費(fèi)者組有4個(gè)消費(fèi)者,那么一個(gè)消費(fèi)者會(huì)空閑

  • 消費(fèi)者組之間從邏輯上它們是獨(dú)立的,如果多加入一個(gè)消費(fèi)者組,無(wú)論是新增的消費(fèi)者組還是原本的消費(fèi)者組,都能消費(fèi)topic的全部數(shù)據(jù)。

那么問(wèn)題來(lái)了,如果一個(gè)消費(fèi)者組中的某個(gè)消費(fèi)者掛了,存活的消費(fèi)者是需要知道掛掉的消費(fèi)者消費(fèi)到哪了?

這里要引出offset了,offset是消息在分區(qū)中的唯一標(biāo)識(shí),說(shuō)白了就是表示消費(fèi)者的消費(fèi)進(jìn)度。 Kafka通過(guò)offset來(lái)保證消息在分區(qū)內(nèi)的順序性,不過(guò) offset并不跨越分區(qū),也就是說(shuō), Kafka保證的是分區(qū)有序而不是主題有序

7.png

在以前版本的Kafka,這個(gè)offset是由Zookeeper來(lái)管理的,后來(lái)Kafka開(kāi)發(fā)者認(rèn)為Zookeeper不合適大量的刪改操作,于是把offset在broker以內(nèi)部topic(_consumer_offsets)的方式來(lái)保存起來(lái)。

每次消費(fèi)者消費(fèi)的時(shí)候,都會(huì)提交這個(gè)offset,Kafka可以讓你選擇是自動(dòng)提交還是手動(dòng)提交。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容