kafka是什么?
Kafka 是一個廣受歡迎的流式處理平臺田柔。你可以認(rèn)為它是一個專門用于將信息從一個地方放置到另一個地方的服務(wù)全景。它能幫助你在眾多服務(wù)間構(gòu)建異步事件處理模型耀石,創(chuàng)建生產(chǎn)-消費(fèi)機(jī)制或者均衡地分布式作業(yè) - 這方面的案例多不勝數(shù)。
無論出于何種目的而使用kafka爸黄,你都有必要了解一些kafka的基礎(chǔ)理論娶牌。
生產(chǎn)者和消費(fèi)者
kafka包含生產(chǎn)者和消費(fèi)者的概念,前者推送消息到kafka馆纳,而后者從kafka獲取這些消息诗良。
由于有各種各樣的消息數(shù)據(jù)通過kafka被處理,因此為了將它們分類理順鲁驶,kafka允許你為不同類型的消息創(chuàng)建獨(dú)立的處理上下文鉴裹,即以主題(topics)的形式將消息進(jìn)行分組。
每一個試圖推送消息的生產(chǎn)者都必須為消息提供一個topic名稱钥弯。
此外径荔,消費(fèi)者也會訂閱一系列的topics()繼而可以從這些topics中消費(fèi)消息
消費(fèi)者組
在現(xiàn)實(shí)場景中,你想要每個感興趣的服務(wù)從某個特定的topic接收每一條消息脆霎,同時你希望你的消息精確地遞送至每個服務(wù)的某個實(shí)例总处;這是消費(fèi)者組就可以登場了。
最根本的睛蛛,如果你想將一類消息分發(fā)給一群消費(fèi)者處理或者將這些消費(fèi)和其他組的消費(fèi)者區(qū)分開來鹦马, 你會將這些消費(fèi)者添加到一個消費(fèi)者組。
每個topic中的每條消息會被遞送到每個消費(fèi)者組忆肾,但在消費(fèi)者組內(nèi)晦炊,單條消息只會被某一個消費(fèi)者處理(組內(nèi)其他的消費(fèi)對這條消息是無感的)蹂风。
從下圖中也可以看到扒最,每條消息會終結(jié)于每個消費(fèi)者組中的某個特定消費(fèi)者赏殃。
分區(qū)
現(xiàn)在讓我們聚焦到單個的消費(fèi)者組中。假設(shè)你有一個叫作EmailGroup的組,該組包含3個消費(fèi)者和悦;那么kafka會將消息投遞至哪個消費(fèi)者呢退疫?
事實(shí)上,每個topic被劃分為了多個分區(qū)鸽素,分區(qū)是整個topic的一個數(shù)據(jù)分塊蹄咖,一條消息只會出現(xiàn)在其中一個分區(qū)上。
生產(chǎn)者生產(chǎn)的消息包含鍵和值兩部分付鹿;值就是你想投遞的數(shù)據(jù)澜汤,鍵也可以用來傳遞信息,但它更適合用來作分區(qū)鍵舵匾,生產(chǎn)者會將該鍵進(jìn)行hash俊抵,以確定將對應(yīng)的消息發(fā)往哪個分區(qū)。這就意味著坐梯,如果你想發(fā)送兩條不同的消息到相同的分區(qū)徽诲,那么你得為它們設(shè)置同樣的鍵。
很好吵血,目前為止谎替,我們知道了生產(chǎn)者如何與分區(qū)協(xié)同,但是消費(fèi)者方面呢蹋辅?
消費(fèi)者將會訂閱一個topic(加入消費(fèi)者組是必然的)并且拉取它所對應(yīng)的分區(qū)中的消息钱贯。這兒最重要的概念是每個分區(qū)必然被確定的單個消費(fèi)者消費(fèi),而每個消費(fèi)者則能夠訂閱多個分區(qū)(也可能0個分區(qū)侦另,比如消費(fèi)者數(shù)量大于分區(qū)數(shù)量)秩命。
聚焦至分區(qū),你會看到kafka是可以保證單個分區(qū)消息有序的褒傅。假設(shè)有條消息A(鍵為阿勇)被發(fā)送到一個topic弃锐,之后有一條消息B(鍵也為阿勇)也發(fā)送到該topic;然后消費(fèi)者將會依次先接收到A然后是B殿托,當(dāng)然這種順序僅對單個分區(qū)有效霹菊,不同分區(qū)的消息將以不確定的順序被消費(fèi)。
實(shí)際上支竹,分區(qū)只是一個僅允許往后追加的日志旋廷,這也是保證順序的原因。另一方面唾戚,不同的分區(qū)是不同的數(shù)據(jù)分片(日志)柳洋,因此無法保證順序待诅。
作為圖形化的解釋叹坦,這里生產(chǎn)者發(fā)布了3條消息——A、B和C——都具有相同的鍵卑雁。分區(qū)看起來是這樣的:
如果消費(fèi)者現(xiàn)在訂閱了這個主題募书,并且被分配到這個分區(qū)绪囱,那么它將首先接收UserCreatedA,然后是UserCreatedB莹捡,最后是UserCreatedC鬼吵。
Offset
現(xiàn)在你可能會問:“我的應(yīng)用如何追蹤哪條消息已經(jīng)被消費(fèi),接著是哪條消息將被拉壤河齿椅?”,由于在kafka中消息日志是線性結(jié)構(gòu)启泣,分區(qū)中每條消息都被分配了確定的offset(位移偏量),比如分區(qū)中第一條消息offset記作0寥茫,嚇一條記作1遣蚀,以此類推。
基于以上原理纱耻,kafka中每條消息能夠通過topic名稱芭梯,分區(qū)號和offset作唯一標(biāo)定。
消費(fèi)者使用offsets來指定它在一個log中的消費(fèi)位置玖喘。事實(shí)上,offsets存在兩種蘑志,一種是在kafka中可持久化的用于在消費(fèi)者崩潰時作為消費(fèi)存根芒涡,另一種是在消費(fèi)者端本地存儲用于協(xié)調(diào)持續(xù)的消息輪詢。
已提交的offset
第一種偏移量是提交偏移量卖漫,它用于在消費(fèi)者崩潰時標(biāo)記該消費(fèi)者最后的消費(fèi)點(diǎn)费尽。
比如,有個新啟動的消費(fèi)者要消費(fèi)一個新的topic羊始,它從offset-0拉取了10條消息旱幼;消息被處理后,消費(fèi)者想標(biāo)記消息為“已消費(fèi)”并通知kafka突委,這個過程叫作“提交”柏卤,簡而言之,消費(fèi)者想要告訴集群記住它已經(jīng)消費(fèi)到位置offset-10了匀油。
現(xiàn)在缘缚,即使服務(wù)端/消費(fèi)者宕機(jī),在恢復(fù)后敌蚜,新的消費(fèi)者接入進(jìn)分區(qū)同樣可以從offset-10之后繼續(xù)消費(fèi)桥滨。
提交的offset被持久化到Kafka中,只有通過提交才能更改。使用者在連接到集群時獲取此offset齐媒,以了解前一個消費(fèi)者已消費(fèi)到何處蒲每。
消費(fèi)端offset
你或許會問,當(dāng)你拉取消息的時候使用哪個offset喻括?是已提交的那個邀杏?看下面的代碼,對poll方法連續(xù)調(diào)用了兩次唬血,但是中間卻沒有commit操作望蜡。你會期待第二次調(diào)用poll得到什么?
val anyTimeout = 100
consumer.poll()
consumer.poll()
您當(dāng)然希望代碼會繼續(xù)執(zhí)行拷恨,所以第二次poll應(yīng)該會返回下一批消息泣特,對嗎?事實(shí)卻是如此挑随。代碼背后状您,消費(fèi)者記住了一個叫作position的東西;每次您調(diào)用poll并確定下一條要獲取的消息時兜挨,它都會增加膏孟,而與此同時,如果您調(diào)用某個提交方法拌汇,offset則會被提交柒桑。
通過調(diào)用以下方法中的一個,你能改變消費(fèi)者的position:
consumer.seek(somePartition, newOffset)
consumer.seekToBeginning(somePartitions)
consumer.seekToEnd(somePartitions)
最后噪舀,初始o(jì)ffset是多少呢魁淳?如果你新建了一個消費(fèi)者組,剛開始不會有提交的offset与倡。
kafka允許你選擇一個策略界逛,記住這個策略設(shè)置只會在沒有產(chǎn)生已提交offset時才會生效,否則如何已提交offset已經(jīng)存在纺座,kafka將會使用該offset息拜;
可選的策略如下:
- Earliest - 偏移量將設(shè)置為可用的最低/最早偏移量
- Lastest - 偏移量將設(shè)置為可用的最大/最新偏移量
- None - 將拋出異常,因此可以手動處理
balabala