學(xué)習(xí)來源:
1.簡(jiǎn)介
Apache Kafka由著名職業(yè)社交公司LinkedIn開發(fā),最初是被設(shè)計(jì)用來解決LinkedIn公司內(nèi)部海量日志傳輸?shù)葐栴}。Kafka使用Scala語言編寫,于2011年開源并進(jìn)入Apache孵化器,2012年10月正式畢業(yè),現(xiàn)在為Apache頂級(jí)項(xiàng)目。
Kafka是一個(gè)分布式數(shù)據(jù)流平臺(tái),可以運(yùn)行在單臺(tái)或者多臺(tái)服務(wù)器上部署形成集群。它提供了發(fā)布和訂閱功能,使用者可以發(fā)送數(shù)據(jù)到Kafka中,也可以從Kafka中讀取數(shù)據(jù)(以便進(jìn)行后續(xù)的處理)。Kafka具有高吞吐、低延遲、高容錯(cuò)等特點(diǎn)。設(shè)計(jì)內(nèi)在就是分布式的,分區(qū)的和可復(fù)制的提交日志服務(wù)。
2.架構(gòu)組件
Broker 節(jié)點(diǎn)
Kafka集群包含一個(gè)或多個(gè)服務(wù)器,這種服務(wù)器被稱為brokerTopic 主題
每條發(fā)布到Kafka集群的消息都有一個(gè)類別,這個(gè)類別被稱為Topic。(物理上不同Topic的消息分開存儲(chǔ),邏輯上一個(gè)Topic的消息雖然保存于一個(gè)或多個(gè)broker上但用戶只需指定消息的Topic即可生產(chǎn)或消費(fèi)數(shù)據(jù)而不必關(guān)心數(shù)據(jù)存于何處)Partition 分區(qū)
Partition是物理上的概念,每個(gè)Topic包含一個(gè)或多個(gè)Partition.Producer 生產(chǎn)者
負(fù)責(zé)發(fā)布消息到Kafka brokerConsumer 消費(fèi)者
消息消費(fèi)者,向Kafka broker讀取消息的客戶端。Consumer Group 消費(fèi)組
每個(gè)Consumer屬于一個(gè)特定的Consumer Group(可為每個(gè)Consumer指定group name,若不指定group name則屬于默認(rèn)的group)。消息(Record):
實(shí)際寫入Kafka中并可以被讀取的消息記錄。每個(gè)record包含了key、value和timestamp。Segment:消息的聚合單位,包括一定的消息數(shù)量。



一個(gè)topic,可以有partion
每個(gè)partition都是一個(gè)有序并且不可變的消息記錄集合。當(dāng)新的數(shù)據(jù)寫入時(shí),就被追加到partition的末尾。在每個(gè)partition中,每條消息都會(huì)被分配一個(gè)順序的唯一標(biāo)識(shí),這個(gè)標(biāo)識(shí)被稱為offset,即偏移量。注意,Kafka只保證在同一個(gè)partition內(nèi)部消息是有序的,在不同partition之間,并不能保證消息有序。
不同的Partition是給到不同的消費(fèi)者的,所以我們也可以定制查詢讓特定的消息進(jìn)入特定的Partition。
produce發(fā)送的消息分發(fā)到不同的partition中,consumer接受數(shù)據(jù)的時(shí)候是按照group來接受,kafka確保每個(gè)partition只能同一個(gè)group中的同一個(gè)consumer消費(fèi),如果想要重復(fù)消費(fèi),那么需要其他的組來消費(fèi)。Zookeerper中保存這每個(gè)topic下的每個(gè)partition在每個(gè)group中消費(fèi)的offset
跨borker的replicate(將follower視為replication);
leader掛掉,會(huì)重新選舉leader。
同一個(gè)broker中的partion可以既有l(wèi)eader,也有follower
- 生產(chǎn)部分:
kafka以topic來進(jìn)行消息管理,每個(gè)topic包含多個(gè)partition,每個(gè)partition對(duì)應(yīng)一個(gè)邏輯log,有多個(gè)segment組成。 - 消費(fèi)部分:
每個(gè)消費(fèi)者實(shí)例可以消費(fèi)多個(gè)分區(qū),但是每個(gè)分區(qū)最多只能被消費(fèi)者組中的一個(gè)實(shí)例消費(fèi)。
復(fù)制(Replication)過程:
1)一個(gè)partition的復(fù)制個(gè)數(shù)(replication factor)包括這個(gè)partition的leader本身。
2)所有對(duì)partition的讀和寫都通過leader。
3)Followers通過pull獲取leader上log(message和offset)
4)如果一個(gè)follower掛掉、卡住或者同步太慢,leader會(huì)把這個(gè)follower從”in sync replicas“(ISR)列表中刪除。
5)當(dāng)所有的”in sync replicas“的follower把一個(gè)消息寫入到自己的log中時(shí),這個(gè)消息才被認(rèn)為是”committed“的。
6)如果針對(duì)某個(gè)partition的所有復(fù)制節(jié)點(diǎn)都掛了,Kafka選擇最先復(fù)活的那個(gè)節(jié)點(diǎn)作為leader(這個(gè)節(jié)點(diǎn)不一定在ISR里)。
Consumers and Consumer Groups
1)consumer注冊(cè)到zookeeper
2)屬于同一個(gè)group的consumer(group id一樣)平均分配partition,每個(gè)partition只會(huì)被一個(gè)consumer消費(fèi)。
3)當(dāng)broker或同一個(gè)group的其他consumer的狀態(tài)發(fā)生變化的時(shí)候,consumer rebalance就會(huì)發(fā)生。
3.基本原理
3.1 生產(chǎn)者
生產(chǎn)者可以將數(shù)據(jù)寫入到選定的主題。生產(chǎn)者負(fù)責(zé)決定要將哪條記錄寫入到那個(gè)分區(qū)當(dāng)中。可以使用輪詢方式,即每次取一小段時(shí)間的數(shù)據(jù)寫入某個(gè)partition,下一小段的時(shí)間寫入下一個(gè)partition;也可以使用一些分區(qū)函數(shù)(比如哈希),根據(jù)record的key值將記錄寫入不同的分區(qū)。
3.2 消費(fèi)者
多個(gè)消費(fèi)者實(shí)例可以組成一個(gè)消費(fèi)者組,并用一個(gè)標(biāo)簽來標(biāo)識(shí)這個(gè)消費(fèi)者組。一個(gè)消費(fèi)者組中的不同消費(fèi)者實(shí)例可以運(yùn)行在不同的進(jìn)程甚至不同的服務(wù)器上。
如果所有的消費(fèi)者實(shí)例都在同一個(gè)消費(fèi)者組中,那么消息記錄會(huì)被很好的均衡的發(fā)送到每個(gè)消費(fèi)者實(shí)例。

如上圖所示,一個(gè)兩個(gè)節(jié)點(diǎn)的Kafka集群上擁有一個(gè)四個(gè)partition(P0-P3)的topic。有兩個(gè)消費(fèi)者組都在消費(fèi)這個(gè)topic中的數(shù)據(jù),消費(fèi)者組A有兩個(gè)消費(fèi)者實(shí)例,消費(fèi)者組B有四個(gè)消費(fèi)者實(shí)例。
從圖中我們可以看到,在同一個(gè)消費(fèi)者組中,每個(gè)消費(fèi)者實(shí)例可以消費(fèi)多個(gè)分區(qū),但是每個(gè)分區(qū)最多只能被消費(fèi)者組中的一個(gè)實(shí)例消費(fèi)。也就是說,如果有一個(gè)4個(gè)分區(qū)的主題,那么消費(fèi)者組中最多只能有4個(gè)消費(fèi)者實(shí)例去消費(fèi),多出來的都不會(huì)被分配到分區(qū)。其實(shí)這也很好理解,如果允許兩個(gè)消費(fèi)者實(shí)例同時(shí)消費(fèi)同一個(gè)分區(qū),那么就無法記錄這個(gè)分區(qū)被這個(gè)消費(fèi)者組消費(fèi)的offset了。如果在消費(fèi)者組中動(dòng)態(tài)的上線或下線消費(fèi)者,那么Kafka集群會(huì)自動(dòng)調(diào)整分區(qū)與消費(fèi)者實(shí)例間的對(duì)應(yīng)關(guān)系。
3.3 kafka儲(chǔ)存策略
kafka以topic來進(jìn)行消息管理,每個(gè)topic包含多個(gè)partition,每個(gè)partition對(duì)應(yīng)一個(gè)邏輯log,有多個(gè)segment組成。
每個(gè)segment中存儲(chǔ)多條消息,消息id由其邏輯位置決定,即從消息id可直接定位到消息的存儲(chǔ)位置,避免id到位置的額外映射。(每個(gè)part在內(nèi)存中對(duì)應(yīng)一個(gè)index,記錄每個(gè)segment中的第一條消息偏移)
發(fā)布者發(fā)到某個(gè)topic的消息會(huì)被均勻的分布到多個(gè)partition上(或根據(jù)用戶指定的路由規(guī)則進(jìn)行分布),broker收到發(fā)布消息往對(duì)應(yīng)partition的最后一個(gè)segment上添加該消息,當(dāng)某個(gè)segment上的消息條數(shù)達(dá)到配置值或消息發(fā)布時(shí)間超過閾值時(shí),segment上的消息會(huì)被flush到磁盤,只有flush到磁盤上的消息訂閱者才能訂閱到,segment達(dá)到一定的大小后將不會(huì)再往該segment寫數(shù)據(jù),broker會(huì)創(chuàng)建新的segment。
3.4 kafka刪除策略
1.N天前的刪除。
2.保留最近的n GB數(shù)據(jù)。
3.5 broker
與其它消息系統(tǒng)不同,Kafka broker是無狀態(tài)的。這意味著消費(fèi)者必須維護(hù)已消費(fèi)的狀態(tài)信息。這些信息由消費(fèi)者自己維護(hù),broker完全不管(有offset managerbroker管理)。
從代理刪除消息變得很棘手,因?yàn)榇聿⒉恢老M(fèi)者是否已經(jīng)使用了該消息。Kafka創(chuàng)新性地解決了這個(gè)問題,它將一個(gè)簡(jiǎn)單的基于時(shí)間的SLA應(yīng)用于保留策略。當(dāng)消息在代理中超過一定時(shí)間后,將會(huì)被自動(dòng)刪除。這種創(chuàng)新設(shè)計(jì)有很大的好處,消費(fèi)者可以故意倒回到老的偏移量再次消費(fèi)數(shù)據(jù)。這違反了隊(duì)列的常見約定,但被證明是許多消費(fèi)者的基本特征。
3.6 容錯(cuò) (Multi-tenancy)
每個(gè)topic的分區(qū)都可以分布在Kafka集群的不同服務(wù)器上。比如topic A有partition 0,1,2,分別分布在Broker 1,2,3上面。每個(gè)服務(wù)器都可以處理分布在它上面的分區(qū)的寫入和讀取操作。另外,每個(gè)分區(qū)也可以配置多個(gè)副本用來提高容錯(cuò)性。
每個(gè)partition有一個(gè)服務(wù)器充當(dāng)“l(fā)eader”,零至多個(gè)服務(wù)器充當(dāng)“follower”。Leader會(huì)處理針對(duì)于這個(gè)分區(qū)的所有讀寫操作,而follower只是被動(dòng)的從leader中復(fù)制數(shù)據(jù)。當(dāng)leader掛掉了,那么原有的follower會(huì)自動(dòng)選舉出一個(gè)新的leader。每臺(tái)服務(wù)器都會(huì)作為一些分區(qū)的leader,也會(huì)作為其他分區(qū)的follower,所以Kafka集群內(nèi)的負(fù)載會(huì)比較均衡。
如果所有的消費(fèi)者實(shí)例都在不同的消費(fèi)者組,那么每一條消息記錄會(huì)被廣播到每一個(gè)消費(fèi)者實(shí)例。
3.7 持久化
依賴文件系統(tǒng)(持久化到本地),數(shù)據(jù)持久化到log
3.8 效率
解決”small IO problem“:
使用”message set“組合消息。
server使用"chunks of messages"寫到log。consumer一次獲取大的消息塊。解決”byte copying“:
在producer、broker和consumer之間使用統(tǒng)一的binary message format。
使用系統(tǒng)的pagecache。
使用sendfile傳輸log,避免拷貝。端到端的批量壓縮(End-to-end Batch Compression),Kafka支持GZIP和Snappy壓縮協(xié)議。
異步批量發(fā)送
批量發(fā)送:配置不多于固定消息數(shù)目一起發(fā)送并且等待時(shí)間小于一個(gè)固定延遲的數(shù)據(jù)。
3.9 目標(biāo) && 應(yīng)用場(chǎng)景
- 高吞吐量來支持高容量的事件流處理
- 2.支持從離線系統(tǒng)加載數(shù)據(jù)
- 低延遲的消息系統(tǒng)
3.10 Push vs Pull
1)producer push data to broker,consumer pull data from broker
2)consumer pull的優(yōu)點(diǎn):consumer自己控制消息的讀取速度和數(shù)量。
3)consumer pull的缺點(diǎn):如果broker沒有數(shù)據(jù),則可能要pull多次忙等待,Kafka可以配置consumer long pull一直等到有數(shù)據(jù)。
3.11 三種消息發(fā)送語義(Message Delivery Semantics)
- At most once—Messages may be lost but are never redelivered.
- At least once—Messages are never lost but may be redelivered.
- Exactly once—this is what people actually want, each message is delivered once and only once.
Producer:有個(gè)”acks“配置可以控制接收的leader的在什么情況下就回應(yīng)producer消息寫入成功。
Consumer:
讀取消息,寫log,處理消息。如果處理消息失敗,log已經(jīng)寫入,則無法再次處理失敗的消息,對(duì)應(yīng)”At most once“。
讀取消息,處理消息,寫log。如果消息處理成功,寫log失敗,則消息會(huì)被處理兩次,對(duì)應(yīng)”At least once“。
讀取消息,同時(shí)處理消息并把result和log同時(shí)寫入。這樣保證result和log同時(shí)更新或同時(shí)失敗,對(duì)應(yīng)”Exactly once“。
Kafka默認(rèn)保證at-least-once delivery,容許用戶實(shí)現(xiàn)at-most-once語義,exactly-once的實(shí)現(xiàn)取決于目的存儲(chǔ)系統(tǒng),kafka提供了讀取offset,實(shí)現(xiàn)也沒有問題。
3.12 Zookeeper協(xié)調(diào)控制
1)管理broker與consumer的動(dòng)態(tài)加入與離開。
2)觸發(fā)負(fù)載均衡,當(dāng)broker或consumer加入或離開時(shí)會(huì)觸發(fā)負(fù)載均衡算法,使得一個(gè)consumer group內(nèi)的多個(gè)consumer的訂閱負(fù)載平衡。
3)維護(hù)消費(fèi)關(guān)系及每個(gè)partition的消費(fèi)信息。
全系統(tǒng)分布式,即所有的Producer、Broker和Consumer都默認(rèn)有多個(gè),均為分布式的。Producer和Broker之間沒有負(fù)載均衡機(jī)制。Broker和Consumer 之間利用ZooKeeper進(jìn)行負(fù)載均衡。所有的Broker和Consumer都會(huì)在Zookeeper中進(jìn)行注冊(cè),且Zookeeper會(huì)保存他們的一些元數(shù)據(jù)信息。如果某個(gè)Broker和Consumer發(fā)生了變化,那么所有其他的Broker和Consumer都會(huì)得到通知。
kafka高并發(fā)原理
http://www.itdecent.cn/p/12d59d9951f3
- 寫高并發(fā):寫到緩存中,系統(tǒng)自動(dòng) 刷到磁盤。
2.讀高并發(fā):零拷貝技術(shù)