02_Kafka重要概念及相關(guān)操作

Kafka提供的主要功能

生產(chǎn)者 ——>消息隊列 <——消費者

所謂消息對象,本質(zhì)上就是由生產(chǎn)者向消息隊列不斷發(fā)送消息,而消費者則不斷從消息隊列拉取消息钠四。

Apache Kafka本質(zhì)上是一款分布式幔嫂、基于發(fā)布/訂閱機制的消息系統(tǒng),主要使用Scala語言開發(fā)而成的瘪撇。這里使用了【主要】兩字获茬,說明Kafka的源碼并非全部都使用Scala語言開發(fā),有相當一部分代碼是使用Java語言開發(fā)的倔既,特別是針對于客戶端部分恕曲。Kafka的內(nèi)核基本上都是使用Scala語言開發(fā)的,在早期版本的客戶端代碼中渤涌,也是使用Scala語言開發(fā)的佩谣,不過在新版的Kafka中,客戶端代碼部分已經(jīng)換成了Java語言實現(xiàn)实蓬。這里所提到的客戶端主要是針對于生產(chǎn)者茸俭、消費者等功能模塊的代碼吊履。在老版本的客戶端代碼中存在一些已知的問題,因此新版本使用Java語言進行了重新调鬓,減少了錯誤的發(fā)生并增強了穩(wěn)定性艇炎。

Kafka重要概念

生產(chǎn)者(Producer):顧名思義,生產(chǎn)者就是生產(chǎn)消息的組件腾窝,它的主要工作就是源源不斷地生產(chǎn)出消息缀踪,然后發(fā)送給消息隊列。生產(chǎn)者可以向消息隊列發(fā)送各種類型的消息燕锥,如狹義的字符串消息辜贵,也可以發(fā)送二進制消息。生產(chǎn)者是消息隊列的數(shù)據(jù)源归形,只有通過生產(chǎn)者持續(xù)不斷地向消息隊列發(fā)送消息托慨,消息隊列才能不斷處理消息。

消費者(Consumer):所謂消費者暇榴,指的是不斷消費(獲群窨谩)消息的組件,它獲取消息的來源就是消息隊列(即Kafka本身)蔼紧。換句話說婆硬,生產(chǎn)者不斷向消息隊列發(fā)送消息,而消費者則不斷從消息隊列中獲取消息奸例。這里面的消息隊列(即Kafka)則充當一個中介的角色彬犯,連接了生產(chǎn)者與消費者這兩大功能組件。正是從這個意義上來說查吊,借助于消息隊列谐区,我們實現(xiàn)了生產(chǎn)者系統(tǒng)與消費者系統(tǒng)之間的解耦,使得原本需要兩個系統(tǒng)之間有緊密聯(lián)系的狀況變成了兩個系統(tǒng)可以各針對與Kafka進行編程(只要提前約定好一些契約即可)逻卖,這可以使得生產(chǎn)者系統(tǒng)完全不需要了解消費者系統(tǒng)的各種信息(比如說消費者系統(tǒng)的地址宋列、端口號、URL 评也、使用的時REST接口還是RPC等等炼杖;反之亦然)。這正是消息隊列所提供的另外一個絕佳好處:極大降低了系統(tǒng)之間的耦合度盗迟。

代理(Broker):代理這個概念是消息隊列領(lǐng)域中一個常見的概念坤邪。Broker這個單詞原本的意思是經(jīng)紀人,比如說房地產(chǎn)經(jīng)紀人诈乒、股票經(jīng)紀人等罩扇。在消息隊列領(lǐng)域中,它指的其實就是消息隊列產(chǎn)品本身,比如說在Kafka這個領(lǐng)域下喂饥,Broker其實指的就是一臺Kafka Server消约。換句話說,我們可以將部署的一個Kafka Server看作是一個Broker员帮,就是這樣簡單或粮。那么從流程上來說,生產(chǎn)者會將消息發(fā)送給Broker捞高,然后消費者再從Broker中拉取消息氯材。

主題(Topic):主題是Kafka中一個極為重要的概念。首先硝岗,主題是一個邏輯上的概念氢哮,它用于從邏輯上來歸類與存儲消息本身。多個生產(chǎn)者可以向一個Topic發(fā)送消息型檀,同時也可以有多個消費者消費一個Topic中的消息冗尤。Topic還有分區(qū)和副本的概念,后續(xù)介紹胀溺。Topic與消息這兩個概念之間密切相關(guān)裂七,Kafka中的每一條消息都歸屬于某一個Topic,而一個Topic下面可以有任意數(shù)量的消息仓坞。正是借助于Topic這個邏輯上的概念背零,Kafka將各種各樣的消息進行了分門別類,使得不同的消息歸屬于不同的Topic无埃,這樣就可以很好地實現(xiàn)不同系統(tǒng)的生產(chǎn)者可以向同一個Broker發(fā)送消息徙瓶,而不同系統(tǒng)的消費者則可以根據(jù)Topic的名字從Broker中拉取消息。Topic是一個字符串嫉称。通過Topic這樣一個邏輯上的概念倍啥,我們就很好地實現(xiàn)了生產(chǎn)者與消費者之間有針對性的發(fā)送與拉取。

消息(Record):消息是整個消息隊列中最為基本的一個概念澎埠,也是最為原子的一個概念。它指的是生產(chǎn)者發(fā)送與消費者拉取的一個原子事物始藕。一個消息需要關(guān)聯(lián)到一個Topic上蒲稳,表示該消息從屬于哪個Topic。消息由一串字節(jié)所構(gòu)成伍派,其中主要由key和value兩部分內(nèi)容江耀,key與value本質(zhì)上都是字節(jié)數(shù)組。在發(fā)送消息時诉植,我們可以省略掉key部分祥国,而直接使用value部分。正如上一節(jié)的示例那樣,生產(chǎn)者在發(fā)送消息時舌稀,發(fā)送的內(nèi)容是【hello world】啊犬、【welcome】。實際上壁查,他們都是消息的value觉至,即消息真正的內(nèi)容本身;key的主要作用則是根據(jù)一定的策略睡腿,將此消息發(fā)送到指定的分區(qū)中语御,這樣就可以確保包含同一key值的消息全部都寫入到同一個分區(qū)中。因此席怪,我們可以得出這樣一個結(jié)論:對于Kafka的消息來說应闯,真正的消息內(nèi)容本身是由value所承載的。為了提升消息發(fā)送的效率和存儲效率挂捻,生產(chǎn)者會批量將消息發(fā)送給Broker碉纺,并根據(jù)相應(yīng)的壓縮算法在發(fā)送前對消息進行壓縮。

集群(Cluster):集群指的是由多個Broker所共同構(gòu)成的一個整體细层,對外提供統(tǒng)一的服務(wù)惜辑,這類似于我們在部署系統(tǒng)時都會采用集群的方式來進行。借助集群的方式疫赎,Kafka消息隊列系統(tǒng)可以實現(xiàn)高可用與容錯盛撑,即一臺Broker掛掉也不影響整個消息系統(tǒng)的正確運行。集群中的各臺Broker之間是通過心跳(Heartbeat)的方式來檢查其機器是否還存活捧搞。

控制器(Controller):控制器是集群中的概念抵卫。每個集群中會選擇出一個Broker擔任控制器的角色,控制器是Kafka集群的中心胎撇。一個Kafka集群中介粘,控制器這臺Broker之外的其他Broker會根據(jù)控制器的指揮來實現(xiàn)相應(yīng)的功能⊥硎鳎控制器負責管理Kafka分區(qū)的狀態(tài)姻采、管理每個分區(qū)的副本狀態(tài)、監(jiān)聽Zookeeper中數(shù)據(jù)的變化并作出相應(yīng)的反饋等功能爵憎。此外慨亲,控制器也類似于主從概念(比如說MySQL的主從概念),所有的Broker都會監(jiān)聽控制器Leader的狀態(tài)宝鼓,當Leader控制器出現(xiàn)問題或是故障時則重新選擇新的控制器Leader刑棵,這里面涉及到一個選舉算法的問題。

消費者組(Consumer Group):這又是Kafka中的一個核心概念愚铡。消費者與消費者之間密切相關(guān)蛉签。在Kafka中,多個消費者可以共同構(gòu)成一個消費者組,而一個消費者只能從屬于一個消費者組碍舍。消費者組最為重要的一個功能是實現(xiàn)廣播與單播的功能柠座。一個消費者組可以確保其所訂閱的Topic的每個分區(qū)只能被從屬于該消費者組中的唯一一個消費者所消費;如果不同的消費組訂閱了同一個Topic乒验,那么這些消費者組之間是彼此獨立的愚隧,不會受到相互的干擾。因此锻全,如果我們系統(tǒng)一條消息可以被多個消費者所消費狂塘,那么就可以將這些消費者放置到不同的消費者組中,這實際上就是廣播的效果鳄厌;如果希望一條消息只能被一個消費者所消費荞胡,那么就可以將這些消費者放置到同一個消費者組中,這實際上就是單播的效果了嚎。因此泪漂,我們可以將消費者組看作是【邏輯上的訂閱者】,而物理上的訂閱者則是各個消費者歪泳。值得注意的時萝勤,消費者組是一個非常、非常呐伞、非常重要的概念敌卓。很多Kafka初學者都會遇到這樣一個問題:將系統(tǒng)以集群的形式部署(比如說部署到3臺機器或者虛擬機上),每臺機器的指定代碼都是完全一樣的伶氢,那么在運行時趟径,只會有一臺機器會持續(xù)不斷地收到Broker中消息,而其他機器則一條信息業(yè)沒收到癣防。究其本質(zhì)蜗巧,系統(tǒng)部署時采用了集群部署,因此每臺機器的代碼與配置是完全一樣的蕾盯;這樣幕屹,這些機器(消費者)都從屬于同一個消費者組,既然從屬于同一個消費者組级遭,那么這同一個消費者組中香嗓,只會有一個消費者會接收到消息,而其他消費者則完全接受不到任何消息装畅,即單播效果。這一點尤其值得注意沧烈。

啟動ZooKeeper
./zkServer.sh start-foreground
啟動Kafka
./kafka-server-start.sh ../config/server.properties

查看主題列表
./kafka-topics.sh --list --zookeeper localhost:2181
輸出

__consumer_offsets
mytest
test

我們可以看到掠兄,該命令列出了三個主題,其中__consumer_offsets是Kafka Server所創(chuàng)建的用于標識消費者偏移量的主題(Kafka中的消息都是順序保存在磁盤上的,通過offset偏移量來標識消息的順序)蚂夕,它由Kafka Server內(nèi)部使用迅诬;另外兩個是我自己創(chuàng)建的。

查看某個主題(如test)的詳細信息婿牍,則執(zhí)行如下命令
./kafka-topics.sh --describe --topic test --zookeeper localhost:2181

輸出

Topic:test  PartitionCount:1    ReplicationFactor:1 Configs:
    Topic: test Partition: 0    Leader: 0   Replicas: 0 Isr: 0

輸出結(jié)果第一行會顯示出所有分區(qū)的一個總結(jié)信息侈贷;后續(xù)的每一行則給出一個分區(qū)的信息,如果只有一個分區(qū)等脂,那么就只會顯示出一行俏蛮,正如上述輸出那樣。

第一行表示的信息為:
主題名:test
分區(qū)數(shù):1
副本數(shù):1
第二行表示信息為:
主題名:mytest
當前的分區(qū):0
Leader Broker:0
副本:0
lsr(In-Sync Replica):0

這些主題保存在什么地方呢上遥?
實際上搏屑,這些信息都是保存在ZooKeeper中的。Kakfa是重度依賴于ZooKeeper的粉楚。ZooKeeper保存了Kafka所需的原信息以及關(guān)于主題辣恋、消費者偏移量等諸多信息。

打開一個新的命令窗口模软,進入ZooKeeper的bin目錄中伟骨,執(zhí)行如下腳本
./zkCli.sh -server localhost:2181
上述命令表示使用ZooKeeper客戶端腳本工具連接到本機的2181ZooKeeper Server上。
連接成功后顯示

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] 

執(zhí)行ls /命令則輸出 / 下面的所有節(jié)點燃异,如下所示

[cluster, controller_epoch, controller, brokers, zookeeper, admin, isr_change_notification, consumers, log_dir_event_notification, latest_producer_id_block, config]

執(zhí)行'ls2 / '命令輸出/下面的所有節(jié)點和其他相關(guān)信息(ls2 = ls +stat)

[cluster, controller_epoch, controller, brokers, zookeeper, admin, isr_change_notification, consumers, log_dir_event_notification, latest_producer_id_block, config]
cZxid = 0x0
ctime = Thu Jan 01 08:00:00 CST 1970
mZxid = 0x0
mtime = Thu Jan 01 08:00:00 CST 1970
pZxid = 0x110
cversion = 13
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 0
numChildren = 11

執(zhí)行`ls /config/topics'則輸出,同樣執(zhí)行l(wèi)s2 會輸出更多信息

[mytest, test, __consumer_offsets]

創(chuàng)建一個新主題mytest2携狭,命令如下:
./kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic mytest2
當執(zhí)行完上述命令后,控制臺輸出
Created topic "mytest2".
則表示主題mytest2已經(jīng)創(chuàng)建成功特铝。

--replication-factor 與--partitions暑中,這兩個參數(shù),前者表示主題擁有的副本數(shù)鲫剿,后者表示主題擁有的分區(qū)數(shù)鳄逾。關(guān)于分區(qū)與副本的概念,后續(xù)介紹灵莲。

接下里執(zhí)行如下命令
./kafka-topics.sh --list --zookeeper localhost:2181
控制臺輸出

__consumer_offsets
mytest
mytest2
test

可以看到雕凹,多了一個新的主題mytest2。
現(xiàn)在政冻,向新創(chuàng)建的主題mytest2發(fā)送若干條消息枚抵,執(zhí)行如下命令:
./kafka-console-producer.sh --broker-list localhost:9092 --topic mytest2

然后,啟動兩個Kafka Consumer明场。新開兩個控制臺窗口汽摹,分別執(zhí)行如下命令:

./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytest2 --from-beginning
現(xiàn)在,這兩個Kafka Consumer都在等待mytest2主題上新消息的到來苦锨。
在生產(chǎn)者控制臺輸入如下字符串并回車:
hello world
這時逼泣,我們發(fā)現(xiàn)兩個Kafka Consumer均收到該條消息趴泌。
再在生產(chǎn)者控制臺輸入如下字符串并回車:
welcome
我們發(fā)現(xiàn),兩個Kafka Consumer也都收到了該條消息拉庶。

通過這個操作過程嗜憔,我們能夠看到多個Kafka Consumer可以消費同一個主題的同一條消息,這顯然就是廣播概念氏仗,即多個客戶端是可以獲取到同一主題的同一條消息并進行消費的吉捶。

下面關(guān)閉這兩個Kafka Consumer(ctrl+c);然后再分別在這兩個控制臺窗口中執(zhí)行上述同樣的命令:
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytest2 --from-beginning

我們發(fā)現(xiàn),消費者窗口中會顯示出Kafka Server中mytest2主題已經(jīng)擁有的兩條消息:

hello world
welcome

現(xiàn)在再次關(guān)閉兩個Kafka Consumer皆尔;然后分別在這兩個控制臺窗口中 執(zhí)行如下命令(與上述命令相比呐舔,去掉了--from-beginning
這個參數(shù))
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytest2
我們發(fā)現(xiàn),這兩個Kakfa Consumer均不會再顯示出mytest2主題下的信息床佳。
在生產(chǎn)者窗口中輸入如下字符串并回車
people
我們發(fā)現(xiàn)滋早,兩個Kafka Consumer均收到了該條消息。

通過這個操作過程砌们,實際上我們掌握了--from-beginning參數(shù)的作用杆麸。它的作用是
如果消費者尚沒有已建立的可用于消費的偏移量,那么就從Kafka Server日志中最早的消息開始消費浪感,而非最新的消息開始消費昔头。

再次停止兩個Kafka Consumer,然后分別在這兩個控制臺窗口中輸入如下命令:
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytest2 --group mygroup

現(xiàn)在在生產(chǎn)者窗口中輸入如下字符串并回車
byebye

觀察兩個Kafka Consumer控制臺窗口影兽,我們發(fā)現(xiàn)只會有一個消費者窗口收到該條信息揭斧,而另一個Consumer則沒有收到。
繼續(xù)再生產(chǎn)者窗口輸入如下字符串并回車:
person
結(jié)果與之前一樣峻堰,依然只有一臺Consumer(而且是方才收到byebye消息的那臺)收到的該消息讹开。

現(xiàn)在,停止方才收到兩條消息的那臺Kafka Consumer(ctrl+c)捐名,只保留一臺Consumer旦万,再在生產(chǎn)者窗口輸入如下字符串并回車
beijing
我們發(fā)現(xiàn),繼續(xù)運行的這臺Consumer收到了該條消息镶蹋。
實際上成艘,上述操作演示了Kafka消費者組的作用。

現(xiàn)在贺归,將運行的這臺Kafka Consumer停掉淆两,然后分別啟動兩個Kafka Consumer,分別在兩個控制臺中執(zhí)行如下命令:
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytest2 --group mygroup
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytest2 --group mygroup2

注意拂酣,上述兩個命令式運行在兩個控制臺窗口中的秋冰,他么的區(qū)別在于消費者組的名字不同,一個是mygroup婶熬,另一個則是mygroup2丹莲。

在生產(chǎn)者窗口中輸入如下字符串并回車:
tianjing
我們可以清楚地看到光坝,兩個Kafka Consumer均收到了該條消息。究其原因甥材,這兩個Kafka Consumer歸屬于不同的消費者組,因此都可以收到該條消息性含,即實現(xiàn)了廣播的效果洲赵。

下面,我們嘗試將mytest2這個主題刪除商蕴。
在控制臺中執(zhí)行如下命令(該命令表示刪除主題mytest2的信息):
./kafka-topics.sh --zookeeper localhost:2181 --delete --topic mytest2
該命令的輸出結(jié)果如下所示:

Topic mytest2 is marked for deletion.
Note: This will have no impact if delete.topic.enable is not set to true.

該輸出表示:主題mytest2已經(jīng)被標記為刪除狀態(tài)叠萍。同時還給出了一個提示信息,即如果沒有將配置項delete.topic.enable設(shè)置為true绪商,那么這個刪除操作將不起任何作用苛谷。

我們執(zhí)行如下命令,查看主題
./kafka-topics.sh --zookeeper localhost:2181 --list

輸出

__consumer_offsets
mytest
test

從輸出中可以清楚的看到格郁,主題mytest2已經(jīng)消失不見了腹殿,為了更加明確該主題已被刪除,我們執(zhí)行如下命令來查看主題mytest2的詳細信息:
./kafka-topics.sh --zookeeper localhost:2181 --describe --topic mytest2
執(zhí)行上述命令后例书,控制臺沒有任何輸出锣尉,這表明主題mytest2已經(jīng)被刪除了。進一步確認一下决采,回到啟動Kafka Server的控制臺窗口中自沧,我們會發(fā)現(xiàn)窗口輸出了如下日志信息

[2018-05-20 08:54:08,546] INFO Deleting index /tmp/kafka-logs/mytest2-0.fbca21d4e1cf4dd8afe8dacc77146567-delete/00000000000000000000.index (kafka.log.OffsetIndex)
[2018-05-20 08:54:08,559] INFO Deleting index /tmp/kafka-logs/mytest2-0.fbca21d4e1cf4dd8afe8dacc77146567-delete/00000000000000000000.timeindex (kafka.log.TimeIndex)
[2018-05-20 08:54:08,571] INFO Deleted log for partition mytest2-0 in /tmp/kafka-logs/mytest2-0.fbca21d4e1cf4dd8afe8dacc77146567-delete. (kafka.log.LogManager)

從該輸出日志中可以清楚地看到,Kafka Server先是刪除了與主題mytest2相關(guān)的索引信息树瞭,然后刪除了日志信息拇厢,即數(shù)據(jù)文件。

進入到ZooKeeper下的bin目錄晒喷,執(zhí)行如下命令
./zkCli.sh
該命令會連接到ZooKeeper服務(wù)端孝偎,然后再執(zhí)行如下命令:
ls /config/topics
該命令的輸出如下所示
[mytest, test, __consumer_offsets]
這說明,主題mytest2已經(jīng)不存在了厨埋。
基于以上的操作與相應(yīng)的輸出結(jié)果邪媳,我們可以確定,主題mytest2及相關(guān)數(shù)據(jù)已經(jīng)被刪除了(主題刪除操作是不可逆的)荡陷。

值得注意的是雨效,在Kafka1.0之前的版本中,delete.topic.enable屬性值默認為false废赞,因此若想刪除主題徽龟,需要在server.properties配置文件中顯式增加delete.topic.enable=true這一項配置。然而唉地,在Kafka1.0中据悔,該配置項默認就是true传透。因此,极颓,無需顯式指定即可成功刪除主題朱盐;如果不希望刪除主題,那么就需要顯式將delete.topic.enable=false添加到server.properties配置文件中菠隆,這一點尤其要注意兵琳。
另外,在Kafka1.0之前的版本中骇径,如果刪除了主題躯肌,那么被刪除的主題名字會保存到ZooKeeper的/admin/delete_topics節(jié)點中。雖然主題被刪除了破衔,但與主題相關(guān)的消息數(shù)據(jù)依然還會保留清女,需要用戶手動到相關(guān)的數(shù)據(jù)目錄下自行刪除,然后這一切在Kafka1.0中都發(fā)生了變化晰筛。在Kafka1.0中嫡丙,當主題被刪除后,與主題相關(guān)的數(shù)據(jù)也會一并刪除传惠,并且不可逆迄沫。

分區(qū):每個主題可以劃分為多個分區(qū)(每個主題都至少會有一個分區(qū),在之前的示例中卦方,我們在創(chuàng)建主題時所使用的參數(shù)--partitions即表示所創(chuàng)建的主題的分區(qū)數(shù)羊瘩,當時指定值為1)。在同一主題下的不同分區(qū)包含的消息是不同的盼砍。每個消息在被添加到分區(qū)時尘吗,都會被分配一個偏移量(offset),它是消息在所有分區(qū)中的唯一編號浇坐,Kafka是通過offset來確保消息在同一個分區(qū)的消息是有序的睬捶,但是同一主題的多個分區(qū)內(nèi)的消息,Kafka并不會保證其順序性近刘。

關(guān)于分區(qū)與主題之間的關(guān)系擒贸,可以參?見下圖:



從上圖可以看到,消息在每個分區(qū)中是嚴格有序的觉渴,?不同分區(qū)之間的消息則是不保證順序的介劫。
基于這樣的設(shè)計策略,Kafka的性能并不會隨著分區(qū)中消息量的增多而產(chǎn)生損 耗案淋,因此存儲較長時間的數(shù)據(jù)也不會導致什么問題座韵。

Kafka中的消息記錄是保存在磁盤上的,通過為每個消息分配一個offset,即可 以很好地確保同一分區(qū)中消息的順序性誉碴。另外宦棺,Kafka中的消息在磁盤上是有 一定的保留時間的,在這個時間內(nèi)黔帕,消息會存儲在磁盤上;當過了這個時間代咸, 消息即會被丟棄掉,從而釋放磁盤空間成黄。該參數(shù)位于server.properties文件中侣背, 默認為:log.retention.hours=168。即消息默認會保留7天;當然慨默,你可以根 據(jù)實際情況來?由修改該時間,修改后重啟Kafka Server即可?生效弧腥。

下圖展示了Kafka一個分區(qū)中消息的生產(chǎn)與消費情況:



可以看到厦取,每個消息在同一個分區(qū)中都有唯一的一個偏移量(offset)。

分區(qū)是與主題緊密相聯(lián)的一個概念管搪。對于每個主題來說虾攻,它至少會存在一個分區(qū),這是通過在創(chuàng)建主題時所指定的參數(shù)--partitions來確定的更鲁。該參數(shù)的值是?個整數(shù)霎箍,表示所創(chuàng)建的主題所擁有的分區(qū)數(shù)量,我們之前在創(chuàng)建主題時都將該參數(shù)值設(shè)為了1澡为,表示所創(chuàng)建的主題只有一個分區(qū)漂坏。

每個分區(qū)都是一個有序、不可變的消息序列媒至,后續(xù)新來的消息會持續(xù)不不斷地追加到分區(qū)的后面顶别,這相當于一個結(jié)構(gòu)化的提交?志(?家可以將其聯(lián)想為Git的提交日志,Git日志顯然是嚴格有序的)拒啰。分區(qū)中的每?條消息都會被分配一個連續(xù)的id值(即offset)驯绎,該值用于唯一標識分區(qū)中的每一條消息。

分區(qū)在Kafka中扮演著如下作?:

1.分區(qū)中的消息數(shù)據(jù)是存儲在日志文件中的谋旦,?且同一分區(qū)中的消息數(shù)據(jù)是按照發(fā)送順序嚴格有序的剩失。分區(qū)在邏輯上對應(yīng)于一個日志,當生產(chǎn)者將消息寫?分區(qū)時册着,實際上是寫入到了分區(qū)對應(yīng)的日志中拴孤。?日志可以看作是一個邏輯上的概念,它對應(yīng)于磁盤上的一個?錄指蚜。?個日志由多個Segment 構(gòu)成乞巧,每個Segment對應(yīng)于一個索引文件與一個日志文件。

2.借助于分區(qū)摊鸡,我們可以實現(xiàn)Kafka Server的水平擴展绽媒。一臺機器,無論是物理機還是虛擬機蚕冬,運行能力總歸是有上限的。當?臺機?到達能力上限時就無法再擴展是辕,即垂直擴展能力是受到硬件制約的囤热。通過使?用分區(qū),我們可以將一個主題中的消息分散到不同的Kafka Server上获三,這樣當機?運行能力不足時旁蔼,我們只需要增加機?就可以了,在新的機?上創(chuàng)建新的分區(qū)疙教,這樣理論上就可以實現(xiàn)?限的水平擴展能力棺聊。

3.分區(qū)還可以實現(xiàn)并行處理能力,向?個主題所發(fā)送的消息會送給該主題所擁有的不同分區(qū)中贞谓,這樣消息就可以實現(xiàn)并行發(fā)送和處理限佩,由多個分區(qū)來接收所發(fā)送的消息。

創(chuàng)建一個新的主題mytest3:
./kafka-topics.sh --zookeeper localhost:2181 --create --topic mytest3 --partitions 3 --replication-factor 1
執(zhí)行完上述命令后裸弦,創(chuàng)建了新主題mytest3祟同,并且將其--partitions參數(shù)指定為3,這表示mytest3這個主題指定了3個分區(qū)理疙;--replication-factor參數(shù)設(shè)定為1晕城,表示為分區(qū)副本數(shù)量為1。

啟動生產(chǎn)者
./kafka-console-producer.sh --broker-list localhost:9092 --topic mytest3

輸入如下

>hello java
>hello kotlin
>hello python
>hello c++
>hello go
>hello jvm

啟動消費者
./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic mytest3 --from-beginning

輸出如下:

hello kotlin
hello go
hello java
hello c++
hello python
hello jvm

顯然窖贤,我們在消費者端所得到的消息的順序與發(fā)送者發(fā)送消息時的順序是不一樣的砖顷。

分區(qū)有兩條重要原則:
1.同一分區(qū)內(nèi)的消息保證嚴格有序。
2.不同分區(qū)的消息不保證順序性主之。


從上圖可以看出择吊,右側(cè)的Writes表示生產(chǎn)者向Kafka Server的主題寫入消息,該主題有3個分區(qū)槽奕,因此所寫的消息會分布在這3個分區(qū)中几睛;當消費者從Kafka Server的該主題拉取消息時,由于存在3個分區(qū)粤攒,因此這3個分區(qū)的消息都會被拉取出來所森;Kafka Server的分區(qū)間是不保證消息的順序性的,所以會得到如上結(jié)果夯接。

那么這些分區(qū)中的消息位于哪里呢焕济?
打開Kafka安裝目錄中config目錄下的server.properties配置文件,找到下面這一行

# A comma seperated list of directories under which to store log files
log.dirs=/tmp/kafka-logs

log.dirs配置項指定了Kafka的日志文件的存放位置盔几,由于我們并未修改過晴弃,因此日志文件默認位置為:/tmp/kafka-logs。進入該目錄,查看如下



該目錄下存在的就是Kafka的各種消息數(shù)據(jù)以及其它關(guān)鍵數(shù)據(jù)文件上鞠。
值得注意的時际邻,以_consumer_offsets名字開頭的目錄,一共有50個芍阎,分別從0到49世曾。該目錄存放的是Kafka用于判定消費者消費偏移量的系統(tǒng)主題(Kafka Server自行創(chuàng)建,共內(nèi)部使用)谴咸。

mytest-0目錄轮听,是之前創(chuàng)建的主題,當時只創(chuàng)建了一個分區(qū)岭佳,所以用mytest-0來表示該分區(qū)下的數(shù)據(jù)文件血巍。

之前創(chuàng)建的mytest2,這里并沒有珊随,因為我們前面把mytest2主題刪除了藻茂。

以mytest3開頭的目錄共有3個,這正好符合創(chuàng)建mytest3主題時所指定的分區(qū)數(shù)量3玫恳。

在Kafka的文件存儲中宛逗,如果一個主題下存在多個分區(qū)(partitions),那么每個partition就會成為一個目錄鳞绕,partition的命名規(guī)則為:主題名+序號。其中而昨,第一個partition序號為0帆焕,第二個是1惭婿,第三個是2,依次類推叶雹。序號最大值為partition數(shù)量-1财饥。

與partition相關(guān)的另外一個概念segment,稱作段折晦。
一個partition是由一系列有序的钥星、不可變的消息所構(gòu)成。而一個partition中的消息數(shù)量可能會非常多满着,因此顯然不能將所有消息保存到同一個文件中谦炒。因此,類似于log4j的rollin log风喇,當partition中的消息數(shù)量增長到一定程度后宁改,消息文件會進行切割,新的消息文件會被寫到一個新的文件中魂莫,當新的文件增長到一定程度后还蹲,新的消息又會被寫到另一個新的文件中,依次類推;而這一個個新的數(shù)據(jù)文件我們就稱為segment(段)

因此谜喊,一個partition物理上是由一個或多個segment所構(gòu)成潭兽。每個segment中則保存了真實的消息數(shù)據(jù)。如下兩點需要知曉锅论。

  • 每個partition都相當于一個大型文件被分配到多個大小相等的segment(段)數(shù)據(jù)文件中讼溺,每個segment中的消息數(shù)量未必相等(這與消息大小有關(guān),不同的消息所占據(jù)的磁盤空間顯然不同)最易,這個特點使得老的segment文件可以容易就被刪除怒坯,有助于提升磁盤利用效率。
  • 每個partition只需支持順序讀寫就可以了藻懒,segment文件的生命周期是由Kafka Server的配置參數(shù)所確定的剔猿。比如說,server.properties文件中的參數(shù)項log.retention.hours=168就表示7天后刪除老的消息文件嬉荆。

進入到mytest3-0目錄中

?  kafka-logs cd mytest3-0 
?  mytest3-0 ls
00000000000000000000.index     00000000000000000000.timeindex
00000000000000000000.log       leader-epoch-checkpoint

00000000000000000000.index : 這是segment文件的索引文件归敬,它與00000000000000000000.log數(shù)據(jù)文件是成對出現(xiàn)的。后綴.index就表示這是個索引文件鄙早。

00000000000000000000.log :這是segment文件的數(shù)據(jù)文件汪茧,用于存儲實際的消息。當然限番,該文件是二進制格式的舱污。segment文件的命名規(guī)則是partition全局的第一個segment從0開始,后續(xù)每個segment文件名為上一個segment文件最后一條消息的offset值弥虐。沒有數(shù)字則用0填充扩灯。由于這里的數(shù)據(jù)量較少。因此只有一個數(shù)據(jù)文件霜瘪。

00000000000000000000.timeindex :該文件是一個基于消息日期的索引文件珠插,主要用途是在一些根據(jù)日期或者時間來尋找消息的場景下使用,此外在基于時間的日志rolling或是基于時間的日志保留策略等情況下也會使用颖对。實際上捻撑,該文件是Kafka的后續(xù)版本中才增加的,早期版本中是沒有這個文件的缤底。它是對*.index文件的一個補充布讹。*.index是基于偏移量的索引文件,而*.timeindex則是基于時間戳的索引文件训堆。

leader-epoch-checkpoint : 是leader的一個緩存文件描验。實際上,它是與Kafka的HW(High Water)與LEO(Log End Offset)相關(guān)的一個重要文件坑鱼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末膘流,一起剝皮案震驚了整個濱河市絮缅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呼股,老刑警劉巖耕魄,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異彭谁,居然都是意外死亡吸奴,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門缠局,熙熙樓的掌柜王于貴愁眉苦臉地迎上來则奥,“玉大人,你說我怎么就攤上這事狭园《链Γ” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵唱矛,是天一觀的道長罚舱。 經(jīng)常有香客問我,道長绎谦,這世上最難降的妖魔是什么管闷? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮窃肠,結(jié)果婚禮上渐北,老公的妹妹穿的比我還像新娘。我一直安慰自己铭拧,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布恃锉。 她就那樣靜靜地躺著搀菩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪破托。 梳的紋絲不亂的頭發(fā)上肪跋,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音土砂,去河邊找鬼州既。 笑死,一個胖子當著我的面吹牛萝映,可吹牛的內(nèi)容都是我干的吴叶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼序臂,長吁一口氣:“原來是場噩夢啊……” “哼蚌卤!你這毒婦竟也來了实束?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤逊彭,失蹤者是張志新(化名)和其女友劉穎咸灿,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體侮叮,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡避矢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了囊榜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片审胸。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖锦聊,靈堂內(nèi)的尸體忽然破棺而出歹嘹,到底是詐尸還是另有隱情,我是刑警寧澤孔庭,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布尺上,位于F島的核電站,受9級特大地震影響圆到,放射性物質(zhì)發(fā)生泄漏怎抛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一芽淡、第九天 我趴在偏房一處隱蔽的房頂上張望马绝。 院中可真熱鬧,春花似錦挣菲、人聲如沸富稻。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽椭赋。三九已至,卻和暖如春或杠,著一層夾襖步出監(jiān)牢的瞬間哪怔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工向抢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留认境,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓挟鸠,卻偏偏與公主長得像叉信,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子艘希,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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