不依賴zookeeper的kafka

https://redpanda.com/guides/kafka-tutorial/kafka-without-zookeeper

    多年來,人們一直在同時使用Apache ZooKeeper和Apache Kafka。但是自Apache Kafka 3.3發佈以來,它就可以在沒有ZooKeeper的情況下運行。同時它包含了新的命令kafka-metadata-quorum和kafka-metadata-shell?該如何安裝新版kafka,以及如何使用新命令,在本文中,我將回答這些和其他相關的問題。

歷史背景和時間線

    很久以前,Apache Kafka服務器是一個獨立的服務:一個簡單而功能強大的應用程序,很快就受到了許多人的喜愛。然而,它缺乏高可用性和彈性。系統管理員解決這個問題的標準方法通常是創建多個代理副本用於複製目的,通過Apache ZooKeeper進行協調,該技術很快成爲標準Kafka部署的一部分,兩者協同工作。
    然而,Apache ZooKeeper 並非萬無一失的解決方案。隨着時間的推移,Apache Kafka 技術的彈性、可擴展性和性能期望發生了變化,導致了更加嚴格的需求。進行了許多變更,其中最重要的是將消費者偏移量從 ZooKeeper 遷移到 Kafka,逐步在 Kafka 工具中刪除 ZooKeeper 連接主機,並實現了著名的 KIP-500(Kafka 改進提案 500)。
KIP-500 出現在 2.8 版本中,當時 Kafka Raft(KRaft,用於管理元數據的一種一致性協議 Raft 實現)作爲早期訪問功能出現,儘管在 2022 年 10 月 3 日標記爲生產就緒。從 ZooKeeper 遷移到 KRaft 功能的早期訪問遷移計劃預計將在 Kafka 3.4 版本中發佈。其生產就緒版本計劃在 Kafka 3.5 版本中發佈,同時停止支持 ZooKeeper。最終計劃是從 Kafka 4.0 開始,所有部署都將在沒有 ZooKeeper 的情況下運行。

Kafka version State
2.8 KRaft early access
3.3 KRaft production-ready
3.4 Migration scripts early access
3.5 Migration scripts production-ready; use of ZooKeeper deprecated
4.0 ZooKeeper not supported

image
使用zookeeper(左)與不用zookeeper(右)

在沒有 ZooKeeper 的情況下設置 Kafka 集羣,會有一種特殊類型的服務器 - 控制器(controller)。控制器服務器形成一個集羣仲裁(quorum)。集羣使用 KRaft 算法(我們不在範圍內討論算法的理論描述,更多詳情請參考 KRaft 文檔或 Raft 文檔)選擇一個領導者,該領導者開始爲連接以拉取集羣狀態元數據的其他代理(broker)服務的請求提供服務。代理的模型已經發生了變化:以前,活動的控制器將更改推送到代理,而現在代理從領導者控制器中拉取元數據。
Kafka 社區在其最新發布版本中實現了許多內部更改,其中這些是最重要的之一:

  1. Kafka 集羣的擴展限制已得到解決:Kafka 可以處理更多的主題和分區,並且啓動和恢復時間得到了顯着改善。Kafka 控制器不需要從 ZooKeeper 中讀取所有的元數據 — 每個控制器都在本地保存元數據,這節省了將集羣恢復運行所需的寶貴時間。
  2. 使用 Kafka 技術的知識要求和生產設置比同時使用 Kafka 和 ZooKeeper 更簡單,因爲每種技術都需要設置系統配置、安全性、可觀察性、日誌記錄等。技術越少,依賴關係和相互連接就越少。

不使用 ZooKeeper 部署 Kafka 集羣

我們將部署一個由四個節點組成的集羣,其中包括三個控制器節點(server1、server2 和 server3),它們形成一個控制器仲裁,以及一個普通的代理節點(server4)。我們將使用 Ubuntu 操作系統,但您也可以使用您喜歡的其他受支持的發行版。
對於每個主機,連接並運行以下操作:

  1. 安裝 Java 運行時環境,這是運行 Apache Kafka 所必需的:
sudo apt-get install -y default-jre
  1. 下載並解壓縮軟件包,創建用戶和數據目錄,然後切換到該用戶:
wget https://downloads.apache.org/kafka/3.7.0/kafka_2.13-3.7.0.tgz
sudo tar -xzvf kafka_2.13-3.7.0.tgz -C /opt
sudo mkdir -p /data/kafka
sudo useradd -m -s /bin/bash kafka
sudo chown kafka -R /opt/kafka_2.13-3.7.0 /data/kafka
sudo su - kafka

您將在解壓後的目錄中找到三個默認的 KRaft 配置文件示例。請注意屬性 process.roles,該屬性定義了服務器是否同時爲控制器、代理或兩者兼有。在此步驟中不需要執行任何操作。

ls -1 /opt/kafka_2.13-3.7.0/config/kraft/

Output:
broker.properties
controller.properties
server.properties

現在,我們將生成一個唯一的集羣ID。您將創建並複製一個通用唯一標識符(UUID),該標識符用於在同一集羣中唯一標識代理。稍後我們將使用UUID值。您還將在某些命令輸出中看到UUID值。按照以下步驟進行:
/opt/kafka_2.13-3.7.0/bin/kafka-storage.sh random-uuid

Output:
jkUlhzQmQkic54LMxrB1oA

現在我們準備創建一個由 server1、server2 和 server3 組成的集羣仲裁。對於每個服務器,選擇一個唯一的(在集羣內)節點ID值。爲簡單起見,我們將使用1表示 server1,2表示 server2,3表示 server3。將相應的ID值設置爲 CURRENT_SERVER_INDEX。還要記得更新集羣 UUID 爲您自己的值。以下命令將更新 controller.property 文件並啓動 Kafka 守護進程:

export CURRENT_SERVER_INDEX=1
export CLUSTER_UUID=jkUlhzQmQkic54LMxrB1oA

sed -i "s#node.id=.*#node.id=${CURRENT_SERVER_INDEX}#g" controller.properties

sed -i "s#controller.quorum.voters=.*#controller.quorum.voters=1@server1:9093,2@server2:9093,3@server3:9093#g" controller.properties

sed -i "s#log.dirs=.*#log.dirs=/data/kafka#g" controller.properties

/opt/kafka_2.13-3.7.0/bin/kafka-storage.sh format -t ${CLUSTER_UUID}-c /opt/kafka_2.13-3.7.0/config/kraft/controller.properties

/opt/kafka_2.13-3.7.01/bin/kafka-server-start.sh -daemon /opt/kafka_2.13-3.7.0/config/kraft/controller.properties

請注意,您已經使用 kafka-storage 工具生成了一個 UUID 併爲新的 KRaft 格式格式化了數據目錄。在執行 kafka-server-start.sh 後,您將獲得一個正在運行的 Kafka 控制器服務。
對 server2 和 server3 重複此操作,對應的 ID 分別爲 2 和 3。
最後,我們可以通過在 server4 上運行以下命令來創建一個普通的代理。我們將其ID設置爲 4:

export CURRENT_SERVER_INDEX=4

sed -i "s#node.id=.*#node.id=${CURRENT_SERVER_INDEX}#g" broker.properties

sed -i "s#controller.quorum.voters=.*#controller.quorum.voters=1@server1:9093,2@server2:9093,3@server3:9093#g" broker.properties

sed -i "s#listeners=.*#listeners=PLAINTEXT://server${CURRENT_SERVER_INDEX}:9092#g" broker.properties

sed -i "s#log.dirs=.*#log.dirs=/data/kafka#g" broker.properties

/opt/kafka_2.13-3.7.0/bin/kafka-storage.sh format -t jkUlhzQmQkic54LMxrB1oA -c /opt/kafka_2.13-3.7.01/config/kraft/broker.properties

/opt/kafka_2.13-3.7.0/bin/kafka-server-start.sh -daemon /opt/kafka_2.13-3.7.0/config/kraft/broker.properties

與之前的步驟類似,我們得到一個正在運行的 Kafka 代理守護進程。

爲了填充一些元數據,讓我們創建一個名爲 test1 的主題:

/opt/kafka_2.13-3.7.0/bin/kafka-topics.sh --bootstrap-server 
server4:9092 --create --topic test1
/opt/kafka_2.13-3.7.0/bin/kafka-topics.sh --bootstrap-server 
server4:9092 –list

Output:
test1

KRaft 集羣內部

元數據存儲

在上一節中,我們得到了一個運行的 Kafka 集羣,沒有 ZooKeeper,並且有一個主題。我們現在將從兩個不同的角度來檢查元數據的存儲:元數據日誌段和實用工具。

讓我們檢查每個服務器的數據目錄中有什麼。控制器節點的存儲目錄中包含以下內容:

ls -1 /data/kafka/

Output:
bootstrap.checkpoint
__cluster_metadata-0
meta.properties

文件 bootstrap.checkpoints 包含檢查點標記。meta.properties 文件包含有關當前服務器、版本和集羣 ID 的信息。我們最感興趣的是目錄 __cluster_metadata-0 中的文件,該目錄累積了集羣的所有元數據更改:

ls -1 __cluster_metadata-0/

Output:
00000000000000000000.index
00000000000000000000.log
00000000000000000000.timeindex
00000000000000000159.snapshot
00000000000000000288.snapshot
00000000000000000459.snapshot
00000000000000000630.snapshot
00000000000000000827.snapshot
00000000000000001032.snapshot
00000000000000001257.snapshot
00000000000000001419.snapshot
00000000000000001585.snapshot
leader-epoch-checkpoint
partition.metadata
quorum-state

讓我們檢查這些文件。quorum-state 包含有關當前領導者、領導者時期序列號和偏移量以及控制器節點列表的信息:

cat quorum-state

Output:
{"clusterId":"","leaderId":1,"leaderEpoch":137,"votedId":1,"appliedOffset":0,"currentVoters":[{"voterId":1},{"voterId":2},{"voterId":3}],"data_version":0}

partition.metadata 包含了一些普通的信息,只有一個版本和主題 ID:

cat partition.metadata

Output:
version: 0
topic_id: AAAAAAAAAAAAAAAAAAAAAQ

最後,我們來到最有趣的部分,即可以使用兩個 Kafka 實用工具來探索的日誌段文件:

  • kafka-dump-log,使用 --cluster-metadata-decoder 標誌。
  • kafka-metadata-shell。

kafka-dump-log

我們將運行 kafka-dump-log 命令來解碼集羣元數據。輸出包含不同的事件類型,在我們的示例中,我們將提到三種:

  • 主題創建
  • 主題的分區創建
  • NoOp
    如果您檢查輸出,很可能會注意到有許多 NoOp 事件,它們用於推進日誌結尾偏移(LEO)和高水位標記(HW)。當應用時,它們不會更改控制器或代理狀態,也不包含在元數據快照中。

另一種類型是 TOPIC_RECORD,通過將新主題添加到集羣中來更改狀態。您可能會看到我們之前創建的主題的名稱和 ID。

TOPIC_RECORD 後面是一個 PARTITION_RECORD(由於默認分區數爲一)。該記錄通過添加主題的分區以及新分區狀態來更改代理狀態:其領導副本、副本所在的代理、以及其他元數據,例如初始領導者時期和分區時期。在出現仲裁問題時,您可以轉儲日誌文件,並搜索每個節點的集羣狀態更改。下面是輸出示例:

kafka-dump-log.sh --cluster-metadata-decoder --files 
00000000000000000000.log --print-data-log

Output:
#Topic creation:
| offset: 1137 CreateTime: 1666637387916 keySize: -1 valueSize: 26 sequence: -1 headerKeys: [] payload: 
{"type":"TOPIC_RECORD","version":0,"data":{"name":"test1","topicId":"v2PBI5LYSBKXvb-8fw8pKQ"}}

#Topic’s partition creation:
| offset: 1138 CreateTime: 1666637387916 keySize: -1 valueSize: 48 sequence: -1 headerKeys: [] payload: 
{"type":"PARTITION_RECORD","version":0,"data":{"partitionId":0,"topicId":"v2PBI5LYSBKXvb-8fw8pKQ","replicas":[4],"isr":[4],"removingReplicas":[],"addingReplicas":[],"leader":4,"leaderEpoch":0,"partitionEpoch":0}}

#NoOp heartbeat:
| offset: 1139 CreateTime: 1666637388203 keySize: -1 valueSize: 4 sequence: -1 headerKeys: [] payload: 
{"type":"NO_OP_RECORD","version":0,"data":{}}

kafka-metadata-shell

kafka-metadata-shell 命令是探索日誌文件的另一種方法。讓我們選擇一個日誌文件,並簡要查看其內部結構:

kafka-metadata-shell.sh --snapshot /data/kafka/__cluster_metadata-0/00000000000000000000.log
>> ls /
brokers  features  local  metadataQuorum  topicIds  topics

正如您所看到的,我們已經進入了一個 shell 環境。您可以通過運行 help 命令來查看可用的命令:

>> 
    cat                  Show the contents of metadata nodes.
    cd                   Set the current working directory.
    exit                 Exit the metadata shell.
    find                 Search for nodes in the directory hierarchy.
    help                 Display this help message.
    history              Print command history.
    ls                   List metadata nodes.
    man                  Show the help text for a specific command.
    pwd                  Print the current working directory.

佈局直觀易懂,特別是如果熟悉 ZooKeeper 的數據佈局,對這個就不陌生了。

主題被放置在 /topics 中。在更深的目錄中,您可能會找到帶有底層分區元數據的主題名稱。例如:

>> ls /topics
test1
>> ls /topics/test1
0  id  name
>> ls /topics/test1/name
name
>> cat /topics/test1/name
test1
>> cat /topics/test1/id
v2PBI5LYSBKXvb-8fw8pKQ
>> cat /topics/test1/0/data
{
  "partitionId" : 0,
  "topicId" : "v2PBI5LYSBKXvb-8fw8pKQ",
  "replicas" : [ 4 ],
  "isr" : [ 4 ],
  "removingReplicas" : [ ],
  "addingReplicas" : [ ],
  "leader" : 4,
  "leaderEpoch" : 3,
  "partitionEpoch" : 3
}

您還可以通過檢查 /topicIds 目錄來獲取主題 ID:

>> ls /topicIds/
v2PBI5LYSBKXvb-8fw8pKQ

代理的列表可以在 /brokers 目錄中找到。每個代理都有自己的目錄,並且其中包含其狀態、元數據以及一些註冊屬性:

>> cat /brokers/4/registration
RegisterBrokerRecord(brokerId=4, incarnationId=aUuLVzc7QsmV5hJKiOAdlg, brokerEpoch=4438, endPoints=[BrokerEndpoint(name='PLAINTEXT', host='server4', port=9092, securityProtocol=0)], features=[BrokerFeature(name='metadata.version', minSupportedVersion=1, maxSupportedVersion=7)], rack=null, fenced=true, inControlledShutdown=false)
>> cat /brokers/4/isFenced
false
>> cat /brokers/4/inControlledShutdown
true

還有一個目錄是 /features,目前包含協議版本信息:

>> cat /features/metadata.version
{
  "name" : "metadata.version",
  "featureLevel" : 7
}

仲裁同步元數據存儲在 /metadataQuorum 目錄中。在那裏,您可以找到偏移量和領導者信息:

>> cat /metadataQuorum/offset
18609
>> cat /metadataQuorum/leader
LeaderAndEpoch(leaderId=OptionalInt[2], epoch=138)

在 /local 目錄中,您可以檢查 Kafka 的版本和源代碼提交 ID:

>> cat /local/commitId
e23c59d00e687ff5
>> cat /local/version
3.7.0

kafka-metadata-quorum

讓我們檢查另一個實用工具 kafka-metadata-quorum,它有兩個標誌:--status 和 --replicas。以下示例打印出集羣的狀態:

kafka-metadata-quorum.sh --bootstrap-server server4:9092 describe --status

Output:
ClusterId:              jkUlhzQmQkic54LMxrB1oA
LeaderId:               2
LeaderEpoch:            138
HighWatermark:          9457
MaxFollowerLag:         9458
MaxFollowerLagTimeMs:   -1
CurrentVoters:          [1,2,3]
CurrentObservers:       [4]

在這裏,您可以找到集羣 ID、當前領導者的 ID、領導者時期計數器、高水位值、最大追隨者、追隨者滯後時間,以及控制器仲裁成員和普通代理的列表。

爲了顯示更多多樣化的輸出,針對 --replicas 選項,讓我們停止其中一個控制器(NodeId=1),並查看輸出:

kafka-metadata-quorum.sh --bootstrap-server server4:9092 describe --replication

Output:
NodeId  LogEndOffset  Lag  LastFetchTimestamp  LastCaughtUpTimestamp  Status  
2       10486         0    1666642071929       1666642071929          Leader
1       9952          534  1666641804786       1666641804285          Follower
3       10486         0    1666642071608       1666642071608          Follower
4       10486         0    1666642071609       1666642071609          Observer

您可以看到節點的狀態:控制器的狀態可以是領導者(leader)或追隨者(follower)。普通的代理處於觀察者(observer)狀態,觀察者不是仲裁的一部分,儘管觀察者也有元數據的本地副本。還有一個可能的狀態,即候選者(candidate),它是從追隨者升級到領導者的中間狀態。您可以在 KIP-595 中瞭解更多信息。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章