Kafka工作流程
Kafka中消息是以topic進(jìn)行分類的,Producer生產(chǎn)消息,Consumer消費(fèi)消息,都是面向topic的。
Topic是邏輯上的概念,Partition是物理上的概念,每個Partition對應(yīng)著一個log文件,該log文件中存儲的就是producer生產(chǎn)的數(shù)據(jù)。
寫入方式
producer采用推(push)模式將消息發(fā)布到broker,每條消息都被追加(append)到分區(qū)(patition)中,屬于順序?qū)懘疟P(順序?qū)懘疟P效率比隨機(jī)寫內(nèi)存要高,保障kafka吞率)。
分區(qū)(Partition)
Kafka集群有多個消息代理服務(wù)器(broker-server)組成,發(fā)布到Kafka集群的每條消息都有一個類別,用主題(topic)來表示。通常,不同應(yīng)用產(chǎn)生不同類型的數(shù)據(jù),可以設(shè)置不同的主題。一個主題一般會有多個消息的訂閱者,當(dāng)生產(chǎn)者發(fā)布消息到某個主題時,訂閱了這個主題的消費(fèi)者都可以接收到生成者寫入的新消息。
Kafka文件存儲
kafka集群為每個主題維護(hù)了分布式的分區(qū)(partition)日志文件,物理意義上可以把主題(topic)看作進(jìn)行了分區(qū)的日志文件(partition log)。主題的每個分區(qū)都是一個有序的、不可變的記錄序列,新的消息會不斷追加到日志中。分區(qū)中的每條消息都會按照時間順序分配到一個單調(diào)遞增的順序編號,叫做偏移量(offset),這個偏移量能夠唯一地定位當(dāng)前分區(qū)中的每一條消息。
消息發(fā)送時都被發(fā)送到一個topic,其本質(zhì)就是一個目錄,而topic是由一些Partition Logs(分區(qū)日志)組成,其組織結(jié)構(gòu)如下圖所示:
下圖中的topic有3個分區(qū),每個分區(qū)的偏移量都從0開始,不同分區(qū)之間的偏移量都是獨(dú)立的,不會相互影響。
我們可以看到,每個Partition中的消息都是有序的,生產(chǎn)的消息被不斷追加到Partition log上,其中的每一個消息都被賦予了一個唯一的offset值。
發(fā)布到Kafka主題的每條消息包括鍵值和時間戳。消息到達(dá)服務(wù)器端的指定分區(qū)后,都會分配到一個自增的偏移量。原始的消息內(nèi)容和分配的偏移量以及其他一些元數(shù)據(jù)信息最后都會存儲到分區(qū)日志文件中。消息的鍵也可以不用設(shè)置,這種情況下消息會均衡地分布到不同的分區(qū)。
Kafka文件存儲也是通過本地落盤的方式存儲的,主要是通過相應(yīng)的log與index等文件保存具體的消息文件。
生產(chǎn)者不斷的向log文件追加消息文件,為了防止log文件過大導(dǎo)致定位效率低下,Kafka的log文件以1G為一個分界點,當(dāng).log文件大小超過1G的時候,此時會創(chuàng)建一個新的.log文件,同時為了快速定位大文件中消息位置,Kafka采取了分片和索引的機(jī)制來加速定位。
在kafka的存儲log的地方,即文件的地方,會存在消費(fèi)的偏移量以及具體的分區(qū)信息,分區(qū)信息的話主要包括.index和.log文件組成,分區(qū)目的是為了備份,所以同一個分區(qū)存儲在不同的broker上,即當(dāng)third-2
存在當(dāng)前機(jī)器kafka01
上,實際上再kafka03
中也有這個分區(qū)的文件(副本),分區(qū)中包含副本,即一個分區(qū)可以設(shè)置多個副本,副本中有一個是leader,其余為follower。
生產(chǎn)者分區(qū)策略
分區(qū)的原因
- 方便在集群中擴(kuò)展:每個partition通過調(diào)整以適應(yīng)它所在的機(jī)器,而一個Topic又可以有多個partition組成,因此整個集群可以適應(yīng)適合的數(shù)據(jù)
- 可以提高并發(fā):以Partition為單位進(jìn)行讀寫。類似于多路。
分區(qū)的原則
-
指明partition(這里的指明是指第幾個分區(qū))的情況下,直接將指明的值作為partition的值。
-
沒有指明partition的情況下,但是存在值key,此時將key的hash值與topic的partition總數(shù)進(jìn)行取余得到partition值。
-
值與partition均無的情況下,第一次調(diào)用時隨機(jī)生成一個整數(shù),后面每次調(diào)用在這個整數(shù)上自增,將這個值與topic可用的partition總數(shù)取余得到partition值,即round-robin算法。
生產(chǎn)者ISR
為保證producer發(fā)送的數(shù)據(jù)能夠可靠的發(fā)送到指定的topic中,topic的每個partition收到producer發(fā)送的數(shù)據(jù)后,都需要向producer發(fā)送ackacknowledgement,如果producer收到ack就會進(jìn)行下一輪的發(fā)送,否則重新發(fā)送數(shù)據(jù)。
發(fā)送ack的時機(jī)
確保有follower與leader同步完成,leader在發(fā)送ack,這樣可以保證在leader掛掉之后,follower中可以選出新的leader(主要是確保follower中數(shù)據(jù)不丟失)
follower同步完成多少才發(fā)送ack
半數(shù)以上的follower同步完成,即可發(fā)送ack
全部的follower同步完成,才可以發(fā)送ack
副本數(shù)據(jù)同步策略
半數(shù)follower同步完成即發(fā)送ack
優(yōu)點是延遲低
缺點是選舉新的leader的時候,容忍n臺節(jié)點的故障,需要2n+1個副本(因為需要半數(shù)同意,所以故障的時候,能夠選舉的前提是剩下的副本超過半數(shù)),容錯率為1/2
全部follower同步完成完成發(fā)送ack
優(yōu)點是容錯率搞,選舉新的leader的時候,容忍n臺節(jié)點的故障只需要n+1個副本即可,因為只需要剩下的一個人同意即可發(fā)送ack了
缺點是延遲高,因為需要全部副本同步完成才可
kafka選擇的是第二種,因為在容錯率上面更加有優(yōu)勢,同時對于分區(qū)的數(shù)據(jù)而言,每個分區(qū)都有大量的數(shù)據(jù),第一種方案會造成大量數(shù)據(jù)的冗余。雖然第二種網(wǎng)絡(luò)延遲較高,但是網(wǎng)絡(luò)延遲對于Kafka的影響較小。
ISR(同步副本集)
猜想
采用了第二種方案進(jìn)行同步ack之后,如果leader收到數(shù)據(jù),所有的follower開始同步數(shù)據(jù),但有一個follower因為某種故障,遲遲不能夠與leader進(jìn)行同步,那么leader就要一直等待下去,直到它同步完成,才可以發(fā)送ack,此時需要如何解決這個問題呢?
解決
leader中維護(hù)了一個動態(tài)的ISR(in-sync replica set),即與leader保持同步的follower集合,當(dāng)ISR中的follower完成數(shù)據(jù)的同步之后,給leader發(fā)送ack,如果follower長時間沒有向leader同步數(shù)據(jù),則該follower將從ISR中被踢出,該之間閾值由replica.lag.time.max.ms參數(shù)設(shè)定。當(dāng)leader發(fā)生故障之后,會從ISR中選舉出新的leader
生產(chǎn)者ack機(jī)制
對于某些不太重要的數(shù)據(jù),對數(shù)據(jù)的可靠性要求不是很高,能夠容忍數(shù)據(jù)的少量丟失,所以沒有必要等到ISR中所有的follower全部接受成功。
Kafka為用戶提供了三種可靠性級別,用戶根據(jù)可靠性和延遲的要求進(jìn)行權(quán)衡選擇不同的配置。
ack參數(shù)配置
0:producer不等待broker的ack,這一操作提供了最低的延遲,broker接收到還沒有寫入磁盤就已經(jīng)返回,當(dāng)broker故障時有可能丟失數(shù)據(jù)
1:producer等待broker的ack,partition的leader落盤成功后返回ack,如果在follower同步成功之前l(fā)eader故障,那么將丟失數(shù)據(jù)。(只是leader落盤)
-1(all):producer等待broker的ack,partition的leader和ISR的follower全部落盤成功才返回ack,但是如果在follower同步完成后,broker發(fā)送ack之前,如果leader發(fā)生故障,會造成數(shù)據(jù)重復(fù)。(這里的數(shù)據(jù)重復(fù)是因為沒有收到,所以繼續(xù)重發(fā)導(dǎo)致的數(shù)據(jù)重復(fù))
producer返ack,0無落盤直接返,1只leader落盤然后返,-1全部落盤然后返
數(shù)據(jù)一致性問題
LEO(Log End Offset): 每個副本最后的一個offset
HW(High Watermark): 高水位,指代消費(fèi)者能見到的最大的offset,ISR隊列中最小的LEO。
follower故障和leader故障
follower故障: follower發(fā)生故障后會被臨時提出ISR,等待該follower恢復(fù)后,follower會讀取本地磁盤記錄的上次的HW,并將log文件高于HW的部分截取掉,從HW開始向leader進(jìn)行同步,等待該follower的LEO大于等于該partition的HW,即follower追上leader之后,就可以重新加入ISR了。
leader故障:leader發(fā)生故障之后,會從ISR中選出一個新的leader,為了保證多個副本之間的數(shù)據(jù)的一致性,其余的follower會先將各自的log文件高于HW的部分截掉,然后從新的leader中同步數(shù)據(jù)。
這只能保證副本之間的數(shù)據(jù)一致性,并不能保證數(shù)據(jù)不丟失或者不重復(fù)
ExactlyOnce
將服務(wù)器的ACK級別設(shè)置為-1(all),可以保證producer到Server之間不會丟失數(shù)據(jù),即At Least Once至少一次語義。將服務(wù)器ACK級別設(shè)置為0,可以保證生產(chǎn)者每條消息只會被發(fā)送一次,即At Most Once至多一次。
At Least Once可以保證數(shù)據(jù)不丟失,但是不能保證數(shù)據(jù)不重復(fù),而At Most Once可以保證數(shù)據(jù)不重復(fù),但是不能保證數(shù)據(jù)不丟失,對于重要的數(shù)據(jù),則要求數(shù)據(jù)不重復(fù)也不丟失,即Exactly Once即精確的一次。
在0.11版本的Kafka之前,只能保證數(shù)據(jù)不丟失,在下游對數(shù)據(jù)的重復(fù)進(jìn)行去重操作,多余多個下游應(yīng)用的情況,則分別進(jìn)行全局去重,對性能有很大影響。
0.11版本的kafka,引入了一項重大特性:冪等性,冪等性指代Producer不論向Server發(fā)送了多少次重復(fù)數(shù)據(jù),Server端都只會持久化一條數(shù)據(jù)。冪等性結(jié)合At Least Once語義就構(gòu)成了Kafka的Exactly Once語義。
啟用冪等性,即在Producer的參數(shù)中設(shè)置enable.idempotence=true即可,Kafka的冪等性實現(xiàn)實際是將之前的去重操作放在了數(shù)據(jù)上游來做,開啟冪等性的Producer在初始化的時候會被分配一個PID,發(fā)往同一個Partition的消息會附帶Sequence Number,而Broker端會對<PID,Partition,SeqNumber>做緩存,當(dāng)具有相同主鍵的消息的時候,Broker只會持久化一條。文章來源:http://www.zghlxwxcb.cn/news/detail-850093.html
但PID在重啟之后會發(fā)生變化,同時不同的Partition也具有不同的主鍵,所以冪等性無法保證跨分區(qū)跨會話的Exactly Once。文章來源地址http://www.zghlxwxcb.cn/news/detail-850093.html
到了這里,關(guān)于Kafka生產(chǎn)者相關(guān)概念的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!