文章目錄
一、Kafka概述
Kafka
是一個分佈式的基於發佈/訂閱模式的消息隊列,主要應用於大數據實時處理領域。
1.1 MQ應用場景和優缺點
https://hucheng.blog.csdn.net/article/details/102961102
1.2 消息隊列的兩種模式
①點對點模式(一對一,消費者主動拉取數據,消息收到後消息清除)
消息生產者生產消息發送到Queue
中,然後消息消費者從Queue
中取出並且消費消息。
消息被消費以後,Queue
中不再有存儲,所以消息消費者不可能消費到已經被消費的消息。Queue
支持存在多個消費者,但是對一個消息而言,只會有一個消費者可以消費。
②發佈/訂閱模式(一對多,消費者消費數據之後不會清除消息)
消息生產者(發佈)將消息發佈到topic
中,同時有多個消息消費者(訂閱)消費該消息。和點對點方式不同,發佈到topic
的消息會被所有訂閱者消費。
1.3 Kafka基礎架構
Provider: 消息生產者,就是向kafka broker
發消息的客戶端。
Consumer: 消息消費者,向kafka broker
取消息的客戶端 。
Consumer Group (CG): 消費者組由多個consumer
組成。消費者組內每個消費者負責消費不同分區的數據,一個分區只能由一個消費者消費;消費者組之間互不影響。所有的消費者都屬於某個消費者組,即消費者組是邏輯上的一個訂閱者。
Broker : 一臺kafka
服務器就是一個broker
。一個集羣由多個broker
組成。一個broker
可以容納多個topic
。
Topic : 可以理解爲一個隊列,生產者和消費者面向的都是一個topic
;
Partition: 爲了實現擴展性,一個非常大的topic
可以分佈到多個broker
(即服務器)上,一個topic
可以分爲多個partition
,每個partition
是一個有序的隊列;
Replica: 副本,爲保證集羣中的某個節點發生故障時,該節點上的partition
數據不丟失,且kafka
仍然能夠繼續工作,kafka
提供了副本機制,一個topic
的每個分區都有若干個副本,一個leader
和若干個follower
。
leader: 每個分區多個副本的“主”,生產者發送數據的對象,以及消費者消費數據的對象都是leader
。
follower: 每個分區多個副本中的“從”,實時從leader
中同步數據,保持和leader
數據的同步。leader
發生故障時,某個follower
會成爲新的leader
。
二、Kafka快速入門
2.1 安裝部署
集羣規劃:
hadoop100 | hadoop101 | hadoop102 |
---|---|---|
zk | zk | zk |
kafka | kafka | kafka |
集羣部署:
- 解壓安裝包
[root@hadoop100 software]# tar -zxvf kafka_2.11-0.11.0.0.tgz -C /opt/module/
- 修改解壓後的文件名稱
[root@hadoop100 module]# mv kafka_2.11-0.11.0.0/ kafka-0.11.0.0
- 在
kafka
目錄下創建logs
文件夾
[root@hadoop100 kafka-0.11.0.0]# mkdir logs
- 修改配置文件
server.properties
- 配置環境變量
[root@hadoop100 module]# vi /etc/profile
#KAFKA_HOME
export KAFKA_HOME= /opt/module/kafka-0.11.0.2
export PATH=$PATH:$KAFKA_HOME/bin
[root@hadoop100 module]# source /etc/profile
- 分發
kafka
安裝包和環境變量,並修改配置文件中broke.id
爲1、2。 - 啓動集羣
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-server-start.sh -daemon config/server.properties
[root@hadoop101 kafka-0.11.0.0]# bin/kafka-server-start.sh -daemon config/server.properties
[root@hadoop102 kafka-0.11.0.0]# bin/kafka-server-start.sh -daemon config/server.properties
- 關閉集羣
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-server-stop.sh stop
[root@hadoop101 kafka-0.11.0.0]# bin/kafka-server-stop.sh stop
[root@hadoop102 kafka-0.11.0.0]# bin/kafka-server-stop.sh stop
kafka
羣起腳本
for i in `cat /opt/module/hadoop-2.7.2/etc/hadoop/slaves`
do
echo "========== $i =========="
ssh $i 'source /etc/profile&&/opt/module/kafka-0.11.0.2/bin/kafka-server-start.sh -daemon
/opt/module/kafka-0.11.0.2/config/server.properties &'
echo $?
done
2.2 Kafka命令行操作
- 查看當前服務器中的所有
topic
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop100:2181 --list
- 創建
topic
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop100:2181 \
--create --replication-factor 3 --partitions 1 --topic first
選項說明:
--topic
:定義topic
名
--replication-factor
:定義副本數
--partitions
:定義分區數
- 刪除
topic
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop100:2181 \
--delete --topic first
需要server.properties
中設置delete.topic.enable=true
否則只是標記刪除。
- 發送消息
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-console-producer.sh \
--broker-list hadoop100:9092 --topic first
>hello
>world
- 消費消息
[root@hadoop101 kafka-0.11.0.0]# bin/kafka-console-consumer.sh \
--bootstrap-server hadoop100:9092 --from-beginning --topic first
hello
world
--from-beginning
:會把主題中以往所有的數據都讀取出來。
- 查看某個
Topic
的詳情
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop102:2181 \
--describe --topic firs
- 修改分區數(修改的分區數只能大於之前的分區數)
[root@hadoop100 kafka-0.11.0.0]# bin/kafka-topics.sh --zookeeper hadoop102:2181
--alter --topic first --partitions 6
三、Kafka架構深入
3.1 Kafka工作流程
Kafka
中消息是以topic
進行分類的,生產者生產消息,消費者消費消息,都是面向topic
的。
topic
是邏輯上的概念,而partition
是物理上的概念,每個partition
對應於一個log
文件,該log
文件中存儲的就是producer
生產的數據。Producer
生產的數據會被不斷追加到該log
文件末端,且每條數據都有自己的offset
。消費者組中的每個消費者,都會實時記錄自己消費到了哪個offset
,以便出錯恢復時,從上次的位置繼續消費。
3.2 Kafka文件存儲機制
由於生產者生產的消息會不斷追加到log
文件末尾,爲防止log
文件過大導致數據定位效率低下,Kafka
採取了分片和索引機制,將每個partition
分爲多個segment
。每個segment
對應兩個文件:.index
文件和.log
文件。這些文件位於一個文件夾下,該文件夾的命名規則爲:topic
名稱+分區序號。例如,first
這個topic
有三個分區,則其對應的文件夾爲first-0
,first-1
,first-2
。
index
和log
文件以當前segment
的第一條消息的offset
命名,下圖爲index
文件和log
文件的結構示意圖:
.index
文件存儲大量的索引信息,.log
文件存儲大量的數據,索引文件中的元數據指向對應數據文件中message
的物理偏移地址。
3.3 Kafka生產者
① 分區策略
分區的原因:
- 方便在集羣中擴展,每個
Partition
可以通過調整以適應它所在的機器,而一個topic
又可以有多個Partition
組成,因此整個集羣就可以適應任意大小的數據了; - 可以提高併發,因爲可以以
Partition
爲單位讀寫了。
分區的原則:
我們需要將producer
發送的數據封裝成一個ProducerRecord
對象。
- 指明
partition
的情況下,直接將指明的值直接作爲partiton
值; - 沒有指明
partition
值但有key
的情況下,將key
的hash
值與topic
的partition
數進行取餘得到partition
值; - 既沒有
partition
值又沒有key
值的情況下,第一次調用時隨機生成一個整數(後面每次調用在這個整數上自增),將這個值與topic
可用的partition
總數取餘得到partition
值,也就是常說的round-robin
算法。
② 數據可靠性保證
爲保證producer
發送的數據,能可靠的發送到指定的topic
,topic
的每個partition
收到producer
發送的數據後,都需要向producer
發送ack
(acknowledgement
確認收到),如果producer
收到ack
,就會進行下一輪的發送,否則重新發送數據。
1.副本數據同步策略
方案 | 優點 | 缺點 |
---|---|---|
半數以上完成同步,就發送ack | 延遲低 | 選舉新的leader時,容忍n臺節點的故障,需要2n+1個副本 |
全部完成同步,才發送ack | 選舉新的leader時,容忍n臺節點的故障,需要n+1個副本 | 延遲高 |
Kafka
選擇了第二種方案,原因如下:
- 同樣爲了容忍
n
臺節點的故障,第一種方案需要2n+1
個副本,而第二種方案只需要n+1
個副本,而Kafka
的每個分區都有大量的數據,第一種方案會造成大量數據的冗餘。 - 雖然第二種方案的網絡延遲會比較高,但網絡延遲對
Kafka
的影響較小。
2.ISR
採用第二種方案之後,設想以下情景:leader
收到數據,所有follower
都開始同步數據,但有一個follower
,因爲某種故障,遲遲不能與leader
進行同步,那leader
就要一直等下去,直到它完成同步,才能發送ack
。這個問題怎麼解決呢?
Leader
維護了一個動態的in-sync replica set (ISR)
,意爲和Leader
保持同步的follower
集合。當ISR
中的follower
完成數據的同步之後,leader
就會給follower
發送ack
。如果follower
長時間未向leader
同步數據,則該follower
將被踢出ISR
,該時間閾值由replica.lag.time.max.ms
參數設定。Leader
發生故障之後,就會從ISR
中選舉新的leader
。
3.ack應答機制
對於某些不太重要的數據,對數據的可靠性要求不是很高,能夠容忍數據的少量丟失,所以沒必要等ISR
中的follower
全部接收成功。所以Kafka
爲用戶提供了三種可靠性級別,用戶根據對可靠性和延遲的要求進行權衡,選擇以下的配置。
acks
參數配置:
- 0:
producer
不等待broker
的ack
,這一操作提供了一個最低的延遲,broker
一接收到還沒有寫入磁盤就已經返回,當broker
故障時有可能丟失數據; - 1:
producer
等待broker
的ack
,partition
的leader
落盤成功後返回ack
。如果在follower
同步成功之前leader
故障,那麼將會丟失數據;
- -1:
producer
等待broker
的ack
,partition
的leader
和follower
全部落盤成功後才返回ack
。但是如果在follower
同步完成後,broker
發送ack
之前,leader
發生故障,那麼會造成數據重複。
4.故障處理細節
LEO:每個副本的最後一個offset
;
HW:所有副本中最小的LEO
。
- follower故障
follower
發生故障後會被臨時踢出ISR
,待該follower
恢復後,follower
會讀取本地磁盤記錄的上次的HW
,並將log
文件高於HW
的部分截取掉,從HW
開始向leader
進行同步。等該follower
的LEO
大於等於該Partition
的HW
,即follower
追上leader
之後,就可以重新加入ISR
了。 - leader故障
leader
發生故障之後,會從ISR
中選出一個新的leader
,之後,爲保證多個副本之間的數據一致性,其餘的follower
會先將各自的log
文件高於HW
的部分截掉,然後從新的leader
同步數據。
注意:這隻能保證副本之間的數據一致性,並不能保證數據不丟失或者不重複。
③ Exactly Once語義
對於某些比較重要的消息,我們需要保證exactly once
語義,即保證每條消息被髮送且僅被髮送一次。
在0.11
版本之後,Kafka
引入了冪等性機制(idempotent
),配合acks = -1
時的at least once
語義,實現了producer
到broker
的exactly once
語義。
idempotent
+ at least once
= exactly once
使用時,只需將enable.idempotence
屬性設置爲true
,kafka
自動將acks
屬性設爲-1。
3.4 Kafka消費者
① 消費方式
consumer
採用pull
(拉)模式從broker
中讀取數據。
push
(推)模式很難適應消費速率不同的消費者,因爲消息發送速率是由broker
決定的。它的目標是儘可能以最快速度傳遞消息,但是這樣很容易造成consumer
來不及處理消息,典型的表現就是拒絕服務以及網絡擁塞。而pull
模式則可以根據consumer
的消費能力以適當的速率消費消息。
pull
模式不足之處是,如果kafka
沒有數據,消費者可能會陷入循環中,一直返回空數據。針對這一點,Kafka
的消費者在消費數據時會傳入一個時長參數timeout
,如果當前沒有數據可供消費,consumer
會等待一段時間之後再返回,這段時長即爲timeout
。
② 分區分配策略
一個consumer group
中有多個consumer
,一個topic
有多個partition
,所以必然會涉及到partition
的分配問題,即確定那個partition
由哪個consumer
來消費。
Kafka
有兩種分配策略,一是round robin
(輪詢,默認),一是range
。range
分配是以topic
分配partition
,當有多個topic
時,可能會造成partition
分配不均勻
③ offset的維護
由於consumer
在消費過程中可能會出現斷電宕機等故障,consumer
恢復後,需要從故障前的位置的繼續消費,所以consumer
需要實時記錄自己消費到了哪個offset
,以便故障恢復後繼續消費。
Kafka 0.9
版本之前,consumer
默認將offset
保存在Zookeeper
中,從0.9
版本開始,consumer
默認將offset
保存在Kafka
一個內置的topic
中,該topic
爲__consumer_offsets
。
3.5 Kafka 高效讀寫數據
①順序寫磁盤
Kafka
的producer
生產數據,要寫入到log
文件中,寫的過程是一直追加到文件末端,爲順序寫。官網有數據表明,同樣的磁盤,順序寫能到到600M/s
,而隨機寫只有100k/s
。這與磁盤的機械機構有關,順序寫之所以快,是因爲其省去了大量磁頭尋址的時間。
②零複製技術
3.6 Zookeeper在Kafka中的作用
Kafka
集羣中有一個broker
會被選舉爲Controller
,負責管理集羣broker
的上下線,所有topic
的分區副本分配和leader
選舉等工作。Controller
的管理工作都是依賴於Zookeeper
的。
以下爲partition
的leader
選舉過程: