一 kafka是什么
kafka是一個(gè)分布式的消息隊(duì)列瞄桨,有高性能遣疯,擴(kuò)展性高等優(yōu)點(diǎn)。所謂的消息隊(duì)列就是發(fā)送者通過網(wǎng)絡(luò)套接字發(fā)送消息扶镀,接收者接收消息蕴侣,在這一切發(fā)生的同時(shí),還需要有工具去管理消費(fèi)者消費(fèi)到哪里臭觉,以及高可用等問題睛蛛,這一切就組成了消息隊(duì)列鹦马。
-
kafka架構(gòu)圖
kafka從基本構(gòu)成上來說有三大要素,producer,broker,consumer忆肾,producer負(fù)責(zé)發(fā)送消息荸频,broker負(fù)責(zé)管理消息,consumer負(fù)責(zé)消費(fèi)消息客冈。消息需要按照不同的topic進(jìn)行分類旭从,topic是一個(gè)邏輯上的概念,在物理上场仲,每個(gè)topic還要分成不同的partition和悦,對(duì)應(yīng)到真實(shí)的存儲(chǔ):每個(gè)topic會(huì)有一個(gè)文件夾,文件夾下面存放著不同的日志文件渠缕,這些文件就是partition鸽素。producer發(fā)送到哪個(gè)partition也是可以指定的。kafka的整體結(jié)構(gòu)如圖:
- producer,broker,consumer
二 消息發(fā)送過程
1 api介紹
kafka有high level api和low level api亦鳞,high level幫助我們管理了offset等功能馍忽,low level需要自己去管理消費(fèi)的offset,一般來說都是采用high level燕差。
2 消息發(fā)送
2.1 基礎(chǔ)內(nèi)容
生產(chǎn)者在發(fā)送消息時(shí)遭笋,api中有若干可選項(xiàng):topic,value必填,標(biāo)記著你需要往哪個(gè)隊(duì)列中發(fā)送什么內(nèi)容徒探,key和partition是可選項(xiàng)瓦呼,可以將message發(fā)入指定的分區(qū)中,有partition就發(fā)往指定partition中测暗,如果沒有partition就根據(jù)key去發(fā)送央串,有key就將key值hash后除余,如果連key都沒有碗啄,則根據(jù)round-robin輪訓(xùn)寫入蹋辅。
我們都知道,kafka是一個(gè)分布式的挫掏,高可用的消息隊(duì)列,所謂的分布式秩命,就是消息的存儲(chǔ)具有水平擴(kuò)展的能力尉共,一個(gè)topic的消息可以存儲(chǔ)在不同的物理機(jī)上;所謂的高可用指的是弃锐,同一條消息袄友,會(huì)在備份的機(jī)器上存在。凡是分布式的系統(tǒng)霹菊,就一定存在CAP的問題剧蚣。下面說明一下支竹,kafka在發(fā)送消息時(shí)都做了什么:
- 1.正常情況下,在發(fā)送消息時(shí)鸠按,producer就往指定的partition發(fā)送消息礼搁,由partition擁有的所有broker中的leader進(jìn)行處理。
- 2.當(dāng)partition的leader broker掛掉時(shí)目尖,會(huì)重新選舉出新的leader處理producer的寫入請(qǐng)求馒吴。
2.2 producer怎么才算成功寫入消息?
producer寫消息的內(nèi)容分為如下幾步:
- producer向partition的leader broker進(jìn)行寫請(qǐng)求瑟曲。
- leader把消息寫入日志中饮戳。
- 幾臺(tái)備份broker從leader中pull消息出來。
對(duì)應(yīng)的消息寫入成功標(biāo)志也分為3種洞拨,request.required.acks有三個(gè)可以設(shè)置的值:0扯罐,1,-1 - 0 代表不管broker是否返回都算寫入成功烦衣。
- 1 代表leader返回成功就算成功歹河。
- -1代表所有主備broker都寫成功才算成功。
3 offset的保存
offset是partition中一條消息的唯一標(biāo)識(shí)序號(hào)琉挖,可以通過offet在日志文件中找到指定的消息启泣。
三 消息消費(fèi)過程
1 基本概念
消費(fèi)的基本要求是:同一個(gè)group內(nèi)的consumer只會(huì)消費(fèi)同一個(gè)topic內(nèi)的消息一次,不同的group可以消費(fèi)同一個(gè)topic示辈,kafka的做法是:同一個(gè)group內(nèi)的consumer被劃分為只能消費(fèi)指定的partition寥茫,如果consumer掛掉,那么由broker進(jìn)行重新分配矾麻。這種關(guān)系通過心跳連接維持纱耻。
這里需要注意的一點(diǎn)是:partition和consumer的關(guān)系是多對(duì)一的關(guān)系,如果consumer的數(shù)量多于partition的數(shù)量险耀,那么必定有consumer沒有消息可以消費(fèi)弄喘。
2 消費(fèi)者offset
在kafka 0.1版本之前,消費(fèi)者的offset保存在zookeeper中甩牺,但是由于zookeeper的性能問題蘑志,這種方式不太適合kafka,所以后來kafka進(jìn)行了變更:將其存放在了 __consumeroffsets這個(gè)topic中贬派。
在進(jìn)行消息寫入時(shí)急但,具體寫入哪個(gè)partition由消費(fèi)組ID的hash值決定。
__consumers_offsets partition =
Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount)
//groupMetadataTopicPartitionCount由offsets.topic.num.partitions指定搞乏,默認(rèn)是50個(gè)分區(qū)波桩。
__consumeroffsets中存入的是KV型數(shù)據(jù),key的值由groupid,partition,topic三者共同決定(groupid-topic-partition)请敦,這就意味著:在同一個(gè)group內(nèi)镐躲,只能有一個(gè)consumer消費(fèi)指定topic的指定partition消息储玫。
consumer讀取消費(fèi)位置用到了緩存,每次consumer消費(fèi)完消息后萤皂,會(huì)追加寫一條記錄到topic中撒穷,同時(shí),系統(tǒng)維護(hù)了一個(gè)緩存敌蚜,在提交后桥滨,會(huì)將consumer的消費(fèi)offset緩存值進(jìn)行更新,每次consumer拉取消費(fèi)位置弛车,從緩存中取出數(shù)據(jù)即可齐媒,不必每次都去遍歷這個(gè)log記錄。