Kafka簡明教程

Kafka是啥虽缕?用Kafka官方的話來說就是:

Kafka is used for building real-time data pipelines and streaming apps. It is horizontally scalable, fault-tolerant, wicked fast, and runs in production in thousands of companies.

大致的意思就是馋没,這是一個實時數(shù)據(jù)處理系統(tǒng),可以橫向擴(kuò)展惯殊、高可靠锌半,而且還變態(tài)快搂抒,已經(jīng)被很多公司使用扮惦。

那么什么是實時數(shù)據(jù)處理系統(tǒng)呢臀蛛?顧名思義,實時數(shù)據(jù)處理系統(tǒng)就是數(shù)據(jù)一旦產(chǎn)生崖蜜,就要能快速進(jìn)行處理的系統(tǒng)浊仆。

對于實時數(shù)據(jù)處理,我們最常見的豫领,就是消息中間件了抡柿,也叫MQ(Message Queue,消息隊列)氏堤,也有叫Message Broker的沙绝。

這篇文章,我將從消息中間件的角度鼠锈,帶大家看看Kafka的內(nèi)部結(jié)構(gòu),看看它是如何做到橫向擴(kuò)展星著、高可靠的同時购笆,還能變態(tài)快的。

為什么需要消息中間件

消息中間件的作用主要有兩點:

  • 解耦消息的生產(chǎn)和消費(fèi)虚循。
  • 緩沖同欠。

想象一個場景,你的一個創(chuàng)建訂單的操作横缔,在訂單創(chuàng)建完成之后铺遂,需要觸發(fā)一系列其他的操作,比如進(jìn)行用戶訂單數(shù)據(jù)的統(tǒng)計茎刚、給用戶發(fā)送短信襟锐、給用戶發(fā)送郵件等等,就像這樣:

createOrder(...){
  ...
  statOrderData(...);
  sendSMS();
  sendEmail();
}

代碼這樣寫似乎沒什么問題膛锭,可是過了一段時間粮坞,你給系統(tǒng)引進(jìn)了一個用戶行為分析服務(wù),它也需要在訂單創(chuàng)建完成之后初狰,進(jìn)行一個分析用戶行為的操作莫杈,而且隨著系統(tǒng)的逐漸壯大,創(chuàng)建訂單之后要觸發(fā)的操作也就越來越多奢入,代碼也漸漸膨脹成這樣:

createOrder(...){
  ...
  statOrderData(...);
  sendSMS();
  sendEmail();
  // new operation
  statUserBehavior(...);
  doXXX(...);
  doYYY(...);
  // more and more operations
  ...
}

導(dǎo)致代碼越來越膨脹的癥結(jié)在于筝闹,消息的生產(chǎn)和消費(fèi)耦合在一起了。createOrder方法不僅僅要負(fù)責(zé)生產(chǎn)“訂單已創(chuàng)建”這條消息,還要負(fù)責(zé)處理這條消息关顷。

這就好比BBC的記者糊秆,在知道皇馬拿到歐冠冠軍之后,拿起手機(jī)解寝,翻開皇馬球迷通訊錄扩然,給球迷一個一個打電話,告訴他們聋伦,皇馬奪冠了夫偶。

事實上,BBC的記者只需要在他們官網(wǎng)發(fā)布這條消息觉增,然后球迷自行訪問BBC兵拢,去上面獲取這條新聞;又或者球迷訂閱了BBC逾礁,那么訂閱系統(tǒng)會主動把發(fā)布在官網(wǎng)的消息推送給球迷说铃。

同樣,createOrder也需要一個像BBC官網(wǎng)那樣的載體嘹履,也就是消息中間件腻扇,在訂單創(chuàng)建完成之后,把一條主題為“orderCreated”的消息砾嫉,放到消息中間件去就ok了幼苛,不必關(guān)心需要把這條消息發(fā)給誰。這就完成了消息的生產(chǎn)焕刮。

至于需要在訂單創(chuàng)建完成之后觸發(fā)操作的服務(wù)舶沿,則只需要訂閱主題為“orderCreated”的消息,在消息中間件出現(xiàn)新的“orderCreated”消息時配并,就會收到這條消息括荡,然后進(jìn)行相應(yīng)的處理。

因此溉旋,通過使用消息中間件畸冲,上面的代碼也就簡化成了:

createOrder(...){
  ...
  sendOrderCreatedMessage(...);
}

以后如果在訂單創(chuàng)建之后有新的操作需要執(zhí)行,這串代碼也不需要修改低滩,只需要給對消息進(jìn)行訂閱即可召夹。

另外,通過這樣的解耦恕沫,消費(fèi)者在消費(fèi)數(shù)據(jù)時更加的靈活监憎,不必每次消息一產(chǎn)生就要馬上去處理(雖然通常消費(fèi)者側(cè)也會有線程池等緩沖機(jī)制),可以等自己有空了的時候婶溯,再過來消息中間件這里取數(shù)據(jù)進(jìn)行處理鲸阔。這就是消息中間件帶來的緩沖作用偷霉。

Kafka一代 - 消息隊列

從上面的描述,我們可以看出褐筛,消息中間件之所以可以解耦消息的生產(chǎn)和消費(fèi)类少,主要是它提供了一個存放消息的地方——生產(chǎn)者把消息放進(jìn)來,消費(fèi)者在從中取出消息進(jìn)行處理渔扎。

那么這個存放消息的地方硫狞,應(yīng)該采用什么數(shù)據(jù)結(jié)構(gòu)呢?

在絕大多數(shù)情況下晃痴,我們都希望先發(fā)送進(jìn)來的消息残吩,可以先被處理(FIFO),這符合大多數(shù)的業(yè)務(wù)邏輯倘核,少數(shù)情況下我們會給消息設(shè)置優(yōu)先級泣侮。不管怎樣,對于消息中間件來說紧唱,一個先進(jìn)先出的隊列活尊,是非常合適的數(shù)據(jù)結(jié)構(gòu):


圖片來源:LinkedIn.com

那么要怎樣保證消息可以被順序消費(fèi)呢?

消費(fèi)者過來獲取消息時漏益,每次都把index=0的數(shù)據(jù)返回過去蛹锰,然后再刪除index=0的那條數(shù)據(jù)?

很明顯不行绰疤,因為訂閱了這條消息的消費(fèi)者數(shù)量宁仔,可能是0,也可能是1峦睡,還可能大于1。如果每次消費(fèi)完就刪除了权埠,那么其他訂閱了這條消息的消費(fèi)者就獲取不到這條消息了榨了。

事實上,Kafka會對數(shù)據(jù)進(jìn)行持久化存儲(至于存放多長時間攘蔽,這是可以配置的)龙屉,消費(fèi)者端會記錄一個offset,表明該消費(fèi)者當(dāng)前消費(fèi)到哪條數(shù)據(jù)满俗,所以下次消費(fèi)者想繼續(xù)消費(fèi)转捕,只需從offset+1的位置繼續(xù)消費(fèi)就好了。

消費(fèi)者甚至可以通過調(diào)整offset的值唆垃,重新消費(fèi)以前的數(shù)據(jù)五芝。

那么這就是Kafka了嗎?不辕万,這只是一條非常普通的消息隊列枢步,我們姑且叫它為Kafka一代吧沉删。

這個Kafka一代用一條消息隊列實現(xiàn)了消息中間件,這樣的簡單實現(xiàn)存在不少問題:

  • Topic魚龍混雜醉途。想象一下矾瑰,一個只訂閱了topic為“A”的消費(fèi)者,卻要在一條有ABCDEFG...等各種各樣topic的隊列里頭去尋找topic為A的消息隘擎,這樣性能豈不是很慢殴穴?
  • 吞吐量低。我們把全部消息都放在一條隊列了货葬,請求一多采幌,它肯定應(yīng)付不過來。

由此就引申出了Kafka二代宝惰。

Kafka二代 - Partition

要解決Kafka一代的那兩個問題植榕,很簡單——分布存儲

二代Kafka引入了Partition的概念尼夺,也就是采用多條隊列尊残, 每條隊列里面的消息都是相同的topic:

圖片來源:LinkedIn.com

Partition的設(shè)計解決了上面提到的兩個問題:

  • 純Topic隊列。一個隊列只有一種topic淤堵,消費(fèi)者再也不用擔(dān)心會碰到不是自己想要的topic的消息了寝衫。
  • 提高吞吐量。不同topic的消息交給不同隊列去存儲拐邪,再也不用以一敵十了慰毅。

一個隊列只有一種topic,但是一種topic的消息卻可以根據(jù)自定義的key值扎阶,分散到多條隊列中汹胃。也就是說,上圖的p1和p2东臀,可以都是同一種topic的隊列着饥。不過這是屬于比較高級的應(yīng)用了,以后有機(jī)會再和大家討論惰赋。

Kafka二代足夠完美了嗎宰掉?當(dāng)然不是,我們雖然通過Partition提升了性能赁濒,但是我們忽略了一個很重要的問題——高可用轨奄。

萬一機(jī)器掛掉了怎么辦?單點系統(tǒng)總是不可靠的拒炎。我們必須考慮備用節(jié)點和數(shù)據(jù)備份的問題挪拟。

Kafka三代 - Broker集群

很明顯,為了解決高可用問題枝冀,我們需要集群舞丛。

Kafka對集群的支持也是非常友好的耘子。在Kafka中,集群里的每個實例叫做Broker球切,就像這樣:

圖片來源:sookocheff.com

每個partition不再只有一個谷誓,而是有一個leader(紅色)和多個replica(藍(lán)色),生產(chǎn)者根據(jù)消息的topic和key值吨凑,確定了消息要發(fā)往哪個partition之后(假設(shè)是p1)捍歪,會找到partition對應(yīng)的leader(也就是broker2里的p1),然后將消息發(fā)給leader鸵钝,leader負(fù)責(zé)消息的寫入糙臼,并與其余的replica進(jìn)行同步。

一旦某一個partition的leader掛掉了恩商,那么只需提拔一個replica出來变逃,讓它成為leader就ok了,系統(tǒng)依舊可以正常運(yùn)行怠堪。

通過Broker集群的設(shè)計揽乱,我們不僅解決了系統(tǒng)高可用的問題,還進(jìn)一步提升了系統(tǒng)的吞吐量粟矿,因為replica同樣可以為消費(fèi)者提供數(shù)據(jù)查找的功能凰棉。

Kafka沒那么簡單

這篇文章只是帶大家初步認(rèn)識一下Kafka,很多細(xì)節(jié)并沒有深入討論陌粹,比如:

1撒犀、Kafka的消息結(jié)構(gòu)?
我們只知道Kafka內(nèi)部是一個消息隊列掏秩,但是隊列里的元素長什么樣或舞,包含了哪些消息呢?

參考:Kafka - messageformat

2蒙幻、Zookeeper和Kafka的關(guān)系嚷那?
如果玩過Kafka的Quick Start教程,就會發(fā)現(xiàn)杆煞,我們在使用Kafka時,需要先啟動一個ZK腐泻,那么這個ZK的作用到底是什么呢决乎?

參考:What-is-the-actual-role-of-Zookeeper-in-Kafka

3、數(shù)據(jù)可靠性和重復(fù)消費(fèi)
生產(chǎn)者把消息發(fā)給Kafka派桩,發(fā)送過程中掛掉构诚、或者Kafka保存消息時發(fā)送異常怎么辦?

同理铆惑,消費(fèi)者獲取消費(fèi)時發(fā)生異常怎么辦范嘱?

甚至送膳,如果消費(fèi)者已經(jīng)消費(fèi)了數(shù)據(jù),但是修改offset時失敗了丑蛤,導(dǎo)致重復(fù)消費(fèi)怎么辦叠聋?

等等這些異常場景,都是Kafka需要考慮的受裹。

參考:Kafka - Message Delivery Semantics

4碌补、 pull or push
消費(fèi)者側(cè)在獲取消息時,是通過主動去pull消息呢棉饶?還是由Kafka給消費(fèi)者push消息厦章?

這兩種方式各自有什么優(yōu)劣?

參考:Kafka - push vs pull

5照藻、 如何提高消費(fèi)者處理性能
還是之前的訂單創(chuàng)建的例子袜啃,訂單創(chuàng)建后,你要給用戶發(fā)送短信幸缕,現(xiàn)在你發(fā)現(xiàn)由于你只有一個消費(fèi)者在發(fā)送短信群发,忙不過來,怎么辦冀值?這就有了Kafka里頭的消費(fèi)者組(Consumer Group)的設(shè)計也物。

參考:Understanding-kafka-consumer-groups-and-consumer

......

終極問題:一條消息從生產(chǎn),到被消費(fèi)列疗,完整流程是怎樣的滑蚯?

如果能詳盡透徹地回答這個問題,那你對Kafka的理解也就非常深入了抵栈。

總結(jié)

本文從一個演化的視角告材,帶大家在Kafka的后花園里走馬觀花,逛了一圈古劲。

很多細(xì)節(jié)并沒有深入討論斥赋,只是一個引子,希望能起到拋磚引玉的作用产艾。

參考文獻(xiàn)&學(xué)習(xí)資源

官網(wǎng):

一些不錯的博客:

書籍(沒看過疤剑,但是感覺不錯的書):

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闷堡,一起剝皮案震驚了整個濱河市隘膘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杠览,老刑警劉巖弯菊,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異踱阿,居然都是意外死亡管钳,警方通過查閱死者的電腦和手機(jī)钦铁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來才漆,“玉大人牛曹,你說我怎么就攤上這事≡岳茫” “怎么了躏仇?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腺办。 經(jīng)常有香客問我焰手,道長,這世上最難降的妖魔是什么怀喉? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任书妻,我火速辦了婚禮,結(jié)果婚禮上躬拢,老公的妹妹穿的比我還像新娘躲履。我一直安慰自己,他們只是感情好聊闯,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布工猜。 她就那樣靜靜地躺著,像睡著了一般菱蔬。 火紅的嫁衣襯著肌膚如雪篷帅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天拴泌,我揣著相機(jī)與錄音魏身,去河邊找鬼。 笑死蚪腐,一個胖子當(dāng)著我的面吹牛箭昵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播回季,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼家制,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泡一?” 一聲冷哼從身側(cè)響起慰丛,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瘾杭,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哪亿,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粥烁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年贤笆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片讨阻。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡芥永,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钝吮,到底是詐尸還是另有隱情埋涧,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布奇瘦,位于F島的核電站棘催,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏耳标。R本人自食惡果不足惜醇坝,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望次坡。 院中可真熱鬧呼猪,春花似錦、人聲如沸砸琅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽症脂。三九已至谚赎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間摊腋,已是汗流浹背沸版。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留兴蒸,地道東北人视粮。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像橙凳,于是被迫代替她去往敵國和親蕾殴。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 姓名:周小蓬 16019110037 轉(zhuǎn)載自:http://blog.csdn.net/YChenFeng/art...
    aeytifiw閱讀 34,712評論 13 425
  • 本文轉(zhuǎn)載自http://dataunion.org/?p=9307 背景介紹Kafka簡介Kafka是一種分布式的...
    Bottle丶Fish閱讀 5,461評論 0 34
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理岛啸,服務(wù)發(fā)現(xiàn)钓觉,斷路器,智...
    卡卡羅2017閱讀 134,629評論 18 139
  • 文章簡介 系統(tǒng)原生加載展示——UIActivityIndicatorView&UIProgressView 開源項...
    linatan閱讀 762評論 0 1