[TOC]
1 簡(jiǎn)介
MQ滿天飛的時(shí)代,kafka也只是其中之一。
Kafka,一個(gè)基于分布式的高吞吐量的消息發(fā)布-訂閱系統(tǒng)。
具有快速、持久、可擴(kuò)展、處理大量不同消費(fèi)者的特性。Kafka 不會(huì)關(guān)心消息的處理過程及消費(fèi)者隊(duì)列。
- 磁盤線性讀寫,
O(1)讀寫性能 - 高吞吐量
- 顯式的
分布式架構(gòu)
詳細(xì)的介紹可以看這里:http://blog.cloudera.com/blog/2014/09/apache-kafka-for-beginners/
2 名詞解釋
- broker
kafka集群中的服務(wù)器(一個(gè)或多個(gè))被稱為broker。
- topic
顧名思義,topic就是主題的意思。也就是對(duì)消息的一個(gè)分類。kafka中的每個(gè)消息都有一個(gè)分類/類別,這個(gè)類別就是topic。
不同topic的消息在磁盤上是分開存儲(chǔ)的,同時(shí)對(duì)消費(fèi)者是透明的。也就是說當(dāng)你消費(fèi)消息的時(shí)候并不需要知道消息是怎么存儲(chǔ)的,也不需要知道存儲(chǔ)在哪里。
- partition
可以認(rèn)為是topic的物理分組,一個(gè)topic可以分為一個(gè)或多個(gè)partition。partition一兩句話說不清,詳情見后面的小節(jié)。
- producer
這個(gè)好理解,就是消息的生產(chǎn)者。
- consumer
和producer相對(duì)應(yīng),consumer就是消息的消費(fèi)者。通常是各種高級(jí)語言寫的客戶端API,比如Java、Python甚至是JavaScript所寫的客戶端API。
- consumer group
每個(gè)consumer都屬于一個(gè)消費(fèi)者組。不顯示地指定消費(fèi)者組的時(shí)候?qū)儆谀J(rèn)的消費(fèi)者組。
- message
消息是通信的基本單位,producer可以向topic發(fā)布message。新發(fā)布的消息就會(huì)廣播給訂閱了這個(gè)主題de consumer。message只能傳輸給某個(gè)group中的某一個(gè)consumer。
3 partition
kafka作為一個(gè)MQ或者日志系統(tǒng),他的最終數(shù)據(jù)存儲(chǔ)還是離不開磁盤的。kafka對(duì)每個(gè)消息做了分類,即有了topic,每個(gè)topic當(dāng)然也是持久化在磁盤上的。當(dāng)消費(fèi)完之后太過于陳舊的消息(message/topic)將被刪除。
鑒于此,將所有topic都存儲(chǔ)在同一個(gè)目錄里將導(dǎo)致磁盤文件太過于龐大,這樣一來,管理不便,如果一個(gè)磁盤掛了,將導(dǎo)致所有數(shù)據(jù)丟失;而且磁盤的空間總是有限的。也就是說一個(gè)磁盤持久化所有數(shù)據(jù)在生成環(huán)境是不靠譜的。
所以,kafka可以將不同的topic分布式地存儲(chǔ)于不同的磁盤上,這就有了kafka所謂的partition的概念。
partition是一個(gè)有序的、不可變的消息隊(duì)列。每個(gè)消息都有一個(gè)連續(xù)的序列號(hào)即offset。每個(gè)partition又分為若干個(gè)segment。
最簡(jiǎn)單的也就是kafka默認(rèn)的partition分布存儲(chǔ)策略就是hash了。簡(jiǎn)單理解就是所有可用的broker一次輪流一個(gè)一個(gè)地存儲(chǔ)partition。
這么一搞,最終結(jié)果就是:
- 每臺(tái)可用的broker上的數(shù)據(jù)逗比總數(shù)據(jù)要少
- 但是每個(gè)消息數(shù)據(jù)都有冗余
- 一般情況下,一臺(tái)broker宕機(jī)并不影響整個(gè)系統(tǒng)(當(dāng)然如果你只有一臺(tái)broker那就另說了……)
日志文件的存儲(chǔ)位置(partition就在這里了)在server.properties中指定: log.dirs=/Users/hylexus/data/kafka/kafka-logs。
3.1 單機(jī)版partition的磁盤存儲(chǔ)
此處先從單機(jī)版kafka中partition存儲(chǔ)方式說起。
單機(jī)版并沒有partition帶來的好處。
本人此處的設(shè)置是kafka數(shù)據(jù)存儲(chǔ)在log.dirs=/Users/hylexus/data/kafka/kafka-logs。
創(chuàng)建一個(gè)測(cè)試用的topic名為topic01
$ bin/kafka-topics.sh --create \
--zookeeper localhost:2181 \
--replication-factor 1 \
--partitions 4 \ # 分區(qū)數(shù)為4
--topic topic01
查看磁盤上partition的存儲(chǔ)
hylexus@hylexusPC kafka-logs $ pwd
/Users/hylexus/data/kafka/kafka-logs
hylexus@hylexusPC kafka-logs $ ll
drwxr-xr-x 5 hylexus staff 170 5 1 15:46 topic01-0
drwxr-xr-x 5 hylexus staff 170 5 1 15:46 topic01-1
drwxr-xr-x 5 hylexus staff 170 5 1 15:46 topic01-2
drwxr-xr-x 5 hylexus staff 170 5 1 15:46 topic01-3
hylexus@hylexusPC kafka-logs $
單機(jī)版由于只有一個(gè)目錄,partition分布較為簡(jiǎn)單。
3.2 多broker下partition的磁盤存儲(chǔ)
此處的多broker是如下形式:
單機(jī)上啟動(dòng)三個(gè)broker,注冊(cè)到同一個(gè)zookeeper。
創(chuàng)建一個(gè)topic名為topic02,用以測(cè)試
bin/kafka-topics.sh --create \
--zookeeper localhost:2181 \
--replication-factor 2 \ # 2份拷貝
--partitions 4 \ # 4個(gè)partition
--topic topic02
查看磁盤磁盤上partition存儲(chǔ)
hylexus@hylexusPC kafka-logs $ pwd
/Users/hylexus/data/kafka/kafka-logs
hylexus@hylexusPC kafka-logs $ ll
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-0
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-2
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-3
hylexus@hylexusPC kafka-logs-02 $ pwd
/Users/hylexus/data/kafka/kafka-logs-02
hylexus@hylexusPC kafka-logs-02 $ ll
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-0
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-1
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-3
hylexus@hylexusPC kafka-logs-03 $ pwd
/Users/hylexus/data/kafka/kafka-logs-03
hylexus@hylexusPC kafka-logs-03 $ ll
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-1
drwxr-xr-x 5 hylexus staff 170 5 1 16:29 topic02-2
此時(shí)的partition磁盤分布如下:
記broker個(gè)數(shù)為n,則有:
- 第i個(gè)partition分配到第
(i % n)個(gè)broker - 第i個(gè)Partition的第j個(gè)拷貝分配到第
((i + j) % n)個(gè)broker
3.3 partition磁盤存儲(chǔ)總結(jié)
- 每個(gè)partition為一個(gè)目錄
- partiton命名規(guī)則為
topic名稱-有序序號(hào)- 第一個(gè)partiton有序序號(hào)從0開始
- 序號(hào)最大值為partitions數(shù)量減1
- 如果你只是調(diào)用kafka提供的客戶端程序的話,你沒有必要清楚每個(gè)partition是怎么分布的,因?yàn)槟阒皇钦{(diào)用客戶端消費(fèi)數(shù)據(jù)而已
3.4 partition中segment磁盤存儲(chǔ)
接著上面說的,其實(shí)每個(gè)partition就相當(dāng)于一個(gè)大型文件(整個(gè)消息記錄)被分配到多個(gè)大小相等的文件中存儲(chǔ)。大小相等但是消息個(gè)數(shù)不一定相等了,這樣利于管理,可以快速的刪除陳舊的文件,有效地提高了磁盤的利用率。
此處所說的每個(gè)大小相等的文件就是segment(partition的再次細(xì)分)了。
既然數(shù)據(jù)是存儲(chǔ)在磁盤上的,即便比不上磁盤高效,但也要在一個(gè)MQ系統(tǒng)能接受的范圍內(nèi)。
所以,索引就必不可少了,kafka的segment文件分為兩個(gè)主要部分:index+log
- index主要是索引文件,log才是真正的消息數(shù)據(jù)。
- segment文件命名時(shí):
- 第一個(gè)segment文件名稱從零開始,前導(dǎo)零填充至19位
- 其他每個(gè)segment文件名為上一個(gè)segment文件最后一個(gè)message的offset
此處就以單機(jī)版的kafka為例:
為測(cè)試方便,此處我將log.segment.bytes=1024調(diào)整為1024,以便快速看到效果,生成一些message之后,topic01-0磁盤存儲(chǔ)如下:
hylexus@hylexusPC topic01-0 $ pwd
/Users/hylexus/data/kafka/kafka-logs/topic01-0
hylexus@hylexusPC kafka-logs $ ll topic01-0
-rw-r--r-- 1 hylexus staff 0 5 1 19:43 00000000000000000000.index
-rw-r--r-- 1 hylexus staff 990 5 1 19:43 00000000000000000000.log
-rw-r--r-- 1 hylexus staff 0 5 1 19:43 00000000000000000012.index
-rw-r--r-- 1 hylexus staff 990 5 1 19:43 00000000000000000012.log
-rw-r--r-- 1 hylexus staff 0 5 1 19:43 00000000000000000024.index
-rw-r--r-- 1 hylexus staff 998 5 1 19:43 00000000000000000024.log
-rw-r--r-- 1 hylexus staff 0 5 1 19:43 00000000000000000036.index
-rw-r--r-- 1 hylexus staff 994 5 1 19:43 00000000000000000036.log
-rw-r--r-- 1 hylexus staff 0 5 1 19:43 00000000000000000048.index
-rw-r--r-- 1 hylexus staff 1004 5 1 19:43 00000000000000000048.log
3.5 通過offset查找message
就拿上面的segment來說,第一個(gè)segment的命名為零(前導(dǎo)零).{index,log}。
另外,上面我將每個(gè)segment的大小設(shè)置為1024即log.segment.bytes=1024。
00000000000000000000 offset=0
00000000000000000012 offset=12+1==13
00000000000000000024 offset=24+1==25
……
因此,通過offset查找具體消息步驟如下:
- 二分查找定位到segment
- 在某個(gè)具體的segment文件中順序查找到具體message
- 另外,為效率考慮,index所以文件是直接映射到內(nèi)存的
例如:查找offset==23的message
- 二分查找到具體segment為00000000000000000012
- 在00000000000000000012內(nèi)部順序找到offset=23的message