點(diǎn)對點(diǎn)消息系統(tǒng)
簡單來說就是生產(chǎn)者(Producer)發(fā)送消息到隊(duì)列,消費(fèi)者(Consumer)從隊(duì)列中取出消息耕拷。這種模型的特點(diǎn)就是一條消息只會被一個消費(fèi)者接收纺棺,一但有消費(fèi)者消費(fèi)了這條消息壳坪,其他消費(fèi)者就沒辦法重復(fù)消費(fèi)了午磁。
發(fā)布-訂閱消息系統(tǒng)
發(fā)布訂閱的模型也比較好理解笋妥,首先消費(fèi)者需要訂閱這個隊(duì)列懊昨,生產(chǎn)者只要發(fā)送一條消息到隊(duì)列中,所有已訂閱該隊(duì)列的的消費(fèi)者都能接收到該消息春宣,未訂閱的用戶則無法接收疚颊。就像我們的微信關(guān)注微信公眾號一樣,只有關(guān)注了的用戶才會收到公眾號推送的消息信认。
Kafka
Kafka異軍突起材义,是非常火熱的一款消息中間件嫁赏。消息中間件的作用非常多其掂,常用作系統(tǒng)業(yè)務(wù)的解耦。例如最常聽到的秒殺業(yè)務(wù)潦蝇,我們也能使用消息中間件對業(yè)務(wù)進(jìn)行解耦款熬,用戶發(fā)起秒殺請求后,系統(tǒng)首先會將該請求轉(zhuǎn)發(fā)到中間件中攘乒,然后返回一個等待的結(jié)果(用戶界面顯示正在搶購贤牛,請耐心等待),而我們系統(tǒng)會有監(jiān)聽器去接收這些秒殺請求進(jìn)行對應(yīng)的業(yè)務(wù)處理则酝,最重要的是殉簸,整個系統(tǒng)的擴(kuò)展顯得非常簡單,我們只需要部署Kafka的集群沽讹,以及后臺的負(fù)載均衡就能快速提高系統(tǒng)的訪問并發(fā)量般卑。
Kafka的最大的特點(diǎn)就是高吞吐量以及可水平擴(kuò)展,正因這兩點(diǎn)Kafka非常適合處理數(shù)據(jù)量龐大的業(yè)務(wù)爽雄,例如使用Kafka做日志分析蝠检、數(shù)據(jù)計(jì)算。新版本Kafka也推出了Stream API挚瘟,可以更好的支持?jǐn)?shù)據(jù)流處理叹谁。基于這些特性我們可以實(shí)現(xiàn)非常多的系統(tǒng)功能乘盖。
Broker
Broker為節(jié)點(diǎn)的意思焰檩,我們啟動的單個Kafka實(shí)例則為一個Broker,多個Broker可以組成Kafka集群侧漓。broker接收來著生產(chǎn)者的消息锅尘,為消息設(shè)置偏移量监氢,并提交消息到磁盤保存布蔗,broker為消費(fèi)者提供消息藤违,對讀取分區(qū)的請求作出響應(yīng),返回已經(jīng)提交到磁盤上的消息纵揍,根據(jù)特定的硬件及其特性顿乒,單個broker可以輕松處理數(shù)千個分區(qū)以及每秒百萬級的消息量。
集群
broker是集群的組成部分泽谨。每個集群都有一個broker同時充當(dāng)了集群控制器的角色(自動從活躍成員中選舉)璧榄,控制器負(fù)責(zé)管理工作,包括將分區(qū)分配給broker和監(jiān)控broker吧雹,在集群中骨杂,如果一個分區(qū)從屬于一個broker,該broker被稱為分區(qū)的首領(lǐng)雄卷。一個分區(qū)可以分配給多個broker搓蚪,這時候會發(fā)生分區(qū)復(fù)制,這種復(fù)制機(jī)制為分區(qū)提供了消息冗余丁鹉,如果有一個broker失效妒潭,其他broker可以接管領(lǐng)導(dǎo)權(quán),不過相關(guān)的消費(fèi)者和生產(chǎn)者都要重新連接到新的首領(lǐng)揣钦。
保留消息(在一定期限內(nèi))是kafka的一個重要特性雳灾,默認(rèn)保留策略:要么保留一段時間,要么保留到消息達(dá)到一定大小的字節(jié)數(shù)冯凹,當(dāng)消息達(dá)到上限時谎亩,舊消息就會過期并刪除,所以在任何時間宇姚,消息總量都不會超過配置指定的大小团驱。另外主題可以配置自己的保留策略,可以將消息保留到不再使用為止空凸。還可以通過配置把主題當(dāng)做緊湊型日志嚎花,只有最后一個帶有特定建的消息會被保留下來,這種情況對于變更日志類型的數(shù)據(jù)來說比較適用呀洲,因?yàn)橹恍枰P(guān)系最后時刻發(fā)生的變更紊选。
多集群
如果越來越多的系統(tǒng)都發(fā)消息給kafka,那么最好適用多集群模式道逗,原因包括:
數(shù)據(jù)類型分離
安全需求隔離
多數(shù)據(jù)中心(災(zāi)難恢復(fù))
如果使用多個數(shù)據(jù)中心兵罢,就需要在它們之間復(fù)制消息,這樣在線應(yīng)用程序才可以訪問到多個站點(diǎn)的用戶活動信息滓窍,例如一個用戶修改了他的資料卖词,不管從哪個數(shù)據(jù)中心,都應(yīng)該能看到這些改動,也可以多個站點(diǎn)的監(jiān)控?cái)?shù)據(jù)都聚集到一個部署了分析和告警系統(tǒng)的中心位置此蜈。不過即横,kafka本身的消息復(fù)制只能在單集群內(nèi)進(jìn)行,不能再多個集群間進(jìn)行裆赵。
kafka的MirrorMaker工具可以實(shí)現(xiàn)集群間的消息復(fù)制东囚,MirrorMaker的核心組件包含了一個生產(chǎn)者和一個消費(fèi)者,兩者之間通過一個隊(duì)列相連战授。消費(fèi)者從一個集群讀取消息页藻,生產(chǎn)者把消息發(fā)送到另一個集群上,不過這種方式在創(chuàng)建復(fù)雜的數(shù)據(jù)管道方面顯得有點(diǎn)力不從心植兰。
Topic
Topic為主題的意思份帐,也就是相當(dāng)于消息系統(tǒng)中的隊(duì)列(queue)。kafka的消息通過主題進(jìn)行分類楣导,主題就好比數(shù)據(jù)庫的表弥鹦,或者文件系統(tǒng)里的文件夾,一個Topic中存在多個Partition爷辙,一個分區(qū)就是一個提交日志彬坏,消息以追加的方式寫入分區(qū),因?yàn)闊o法在整個主題范圍內(nèi)保證消息的順序膝晾,但可以保證消息在單個分區(qū)內(nèi)的順序栓始。很多時候,人們把一個主題的數(shù)據(jù)看成一個流血当,不管它有多少個分區(qū)幻赚,流是一組從生產(chǎn)者移動到消費(fèi)者的數(shù)據(jù),Kafka Streams等這些框架以實(shí)時的方式處理消息臊旭,也即是所謂的流式處理落恼。可以用流式處理和離線處理進(jìn)行比較(例如Hadoop)离熏。
Partition
Partition為分區(qū)的意思佳谦,是構(gòu)成Kafka存儲結(jié)構(gòu)的最小單位,kafka通過分區(qū)來實(shí)現(xiàn)數(shù)據(jù)冗余和伸縮性滋戳,分區(qū)可以分布在不同的服務(wù)器上钻蔑,也就是說一個主題可以橫跨多個服務(wù)器,以此來提供比單個服務(wù)器更強(qiáng)大的性能奸鸯。
Partition offset
offset為消息偏移量咪笑,以Partition為單位,即使在同一個Topic中娄涩,不同Partition的offset也是重新開始計(jì)算(也就是會重復(fù))
生產(chǎn)者
生產(chǎn)者創(chuàng)建消息窗怒,也被稱為發(fā)布者或者寫入者,一般一個消息會被發(fā)布到一個特定的主題上,一般情況會均衡的分布到主題的所有分區(qū)上扬虚,而并不關(guān)心特定消息會被寫到哪個分區(qū)努隙,不過,某些情況也可以寫到指定分區(qū)孔轴,這通常是通過消息鍵和分區(qū)器來實(shí)現(xiàn)剃法。分區(qū)器為鍵生成一個散列值碎捺,并將其映射到指定分區(qū)上路鹰,這樣可以保證同一個鍵的消息會寫到同一個分區(qū)上,在某些情況下可以實(shí)現(xiàn)順序性收厨。分區(qū)器也可以自定義晋柱。
消費(fèi)者
消費(fèi)者讀取消息,也可以叫做訂閱者或者讀者诵叁。消費(fèi)者訂閱一個或者多個主題雁竞,并按照消息生成的順序讀取它們。消費(fèi)者通過檢查消息的偏移量來區(qū)分已經(jīng)讀取過的消息拧额,偏移量是另一種元數(shù)據(jù)碑诉,它是一個不斷遞增的整數(shù)值,在創(chuàng)建消息時侥锦,kafka會把它添加到消息里进栽,在給定的分區(qū)里,每個消息的偏移量都是唯一的恭垦,消費(fèi)者把每個分區(qū)最后讀取的消息偏移量保存在zookeeper或者kafka上快毛,如果消費(fèi)者關(guān)閉或重啟,它的讀取狀態(tài)不會丟失番挺。
Group
Group為消費(fèi)者組的意思唠帝,一個Group里面包含多個消費(fèi)者,也就是說玄柏,會有一個或者多個消費(fèi)者共同讀取一個主題襟衰,群組保證每個分區(qū)只能被一個消費(fèi)者使用。消費(fèi)者與分區(qū)之間的映射通常被稱為消費(fèi)者對分區(qū)的所有權(quán)關(guān)系粪摘。通過這種方式右蒲,消費(fèi)者可以消費(fèi)包含大量消息的主題,而且如果一個消費(fèi)者失敗赶熟,群組中其他成員可以接管失效消費(fèi)者的工作瑰妄。
Message
Message為消息的意思,Kafka的數(shù)據(jù)單元被稱為消息映砖,可以把消息看成是數(shù)據(jù)庫里的一行或者一條記錄间坐。消息由字節(jié)數(shù)組組成,所以對于kafka來說,消息里的數(shù)據(jù)沒有特別的格式或者含義竹宋,消息可以有一個可選的元數(shù)據(jù)劳澄,也就是鍵(key),鍵也是一個字節(jié)數(shù)組蜈七,同樣沒有特殊的含義秒拔。當(dāng)消息以一種可控的方式寫入不同的分區(qū)時,會用到鍵飒硅。最簡單的例子就是為鍵生成一個一致性散列值砂缩,然后使用散列值對主題分區(qū)數(shù)進(jìn)行取模,為消息選取分區(qū)三娩,這樣可以保證具有相同鍵的消息總是被寫到相同的分區(qū)上庵芭。
這里就需要說說為什么這樣設(shè)計(jì)了:
首先Topic中有分區(qū)的概念,每個分區(qū)保存各自的數(shù)據(jù)雀监,而我們的Group這對應(yīng)著Topic双吆,也就是這個Topic中的數(shù)據(jù)都是由該Group去消費(fèi),也就是允許多個消費(fèi)者同時消費(fèi)会前,這樣能大大提高Kafka的吞吐量好乐。不過這樣的設(shè)計(jì)也會帶來不少的不便,比如特定場景下你需要去維護(hù)多個Partition之間的關(guān)系瓦宜。這里就不多講了蔚万。
批次
為了提高效率,消息被分批次寫入kafka歉提,批次就是一組消息笛坦,這些消息屬于同一個主題和分區(qū)。如果每一個消息都單獨(dú)穿行于網(wǎng)絡(luò)苔巨,會導(dǎo)致大量的網(wǎng)絡(luò)開銷版扩,把消息分成批次傳輸可以減少網(wǎng)絡(luò)開銷,不過侄泽,這要在延遲和吞吐量上作出權(quán)衡礁芦,批次越大,單位時間處理的消息也越多悼尾,單個消息的傳輸時間就越長柿扣。批次數(shù)據(jù)會被壓縮,這樣可以提升數(shù)據(jù)的傳輸和存儲能力闺魏,但是要做更多的計(jì)算處理未状。
模式
對于kafka來說,消息就是晦澀難懂的字節(jié)數(shù)組析桥。所以有人建議使用一些額外的結(jié)構(gòu)來定義消息內(nèi)容司草,這樣更加容易理解艰垂。根據(jù)需求,消息模式有許多可用的選項(xiàng)埋虹。想JSON和XML這些簡單的系統(tǒng)猜憎,易用而且可讀性好。不過它們?nèi)狈?qiáng)類型處理能力搔课,而且不同版本的兼容性也不是很好胰柑。許多kafka使用者喜歡用Apache Avro,它最初是為Hadoop開發(fā)的一款序列化框架爬泥,Avro提供了一種緊湊的序列化格式柬讨,模式和消息體是分開的,當(dāng)模式發(fā)生變化時急灭,不需要重新生成代碼姐浮,它還支持強(qiáng)類型和模式進(jìn)化谷遂,其版本既向前兼容也向后兼容葬馋。
數(shù)據(jù)格式的一致性對kafka很重要,它消除了消息讀寫之間的耦合性肾扰,如果讀寫操作緊密的耦合在一起畴嘶,消息訂閱者則需要升級系統(tǒng)才能同時處理新舊兩種數(shù)據(jù)格式。在消息訂閱者升級了之后集晚,消息發(fā)布者才跟著升級窗悯,以便使用新的數(shù)據(jù)格式,新的應(yīng)用程序如果需要使用數(shù)據(jù)偷拔,就要與消息發(fā)布者發(fā)生耦合蒋院,導(dǎo)致開發(fā)者需要做很多繁雜的工作。定義良好的模式莲绰,并把它們放在公共倉庫欺旧,可以方便我們理解kafka的消息結(jié)構(gòu)。