Kafka的介紹和安裝(一)

 

初識Kafka

Kafka 起初是由 LinkedIn 公司採用 Scala 語言開發的一個多分區、多副本且基於 ZooKeeper 協調的分佈式消息系統,現已被捐獻給 Apache 基金會。目前 Kafka 已經定位爲一個分佈式流式處理平臺,它以高吞吐、可持久化、可水平擴展、支持流數據處理等多種特性而被廣泛使用。目前越來越多的開源分佈式處理系統如 Cloudera、Storm、Spark、Flink 等都支持與 Kafka 集成。

Kafka 之所以受到越來越多的青睞,與它所“扮演”的三大角色是分不開的:

  • 消息系統: Kafka 和傳統的消息系統(也稱作消息中間件)都具備系統解耦、冗餘存儲、流量削峯、緩衝、異步通信、擴展性、可恢復性等功能。與此同時,Kafka 還提供了大多數消息系統難以實現的消息順序性保障及回溯消費的功能。
  • 存儲系統: Kafka 把消息持久化到磁盤,相比於其他基於內存存儲的系統而言,有效地降低了數據丟失的風險。也正是得益於 Kafka 的消息持久化功能和多副本機制,我們可以把 Kafka 作爲長期的數據存儲系統來使用,只需要把對應的數據保留策略設置爲“永久”或啓用主題的日誌壓縮功能即可。
  • 流式處理平臺: Kafka 不僅爲每個流行的流式處理框架提供了可靠的數據來源,還提供了一個完整的流式處理類庫,比如窗口、連接、變換和聚合等各類操作。
  •  

基本概念

一個典型的 Kafka 體系架構包括若干 Producer、若干 Broker、若干 Consumer,以及一個 ZooKeeper 集羣,其中 ZooKeeper 是 Kafka 用來負責集羣元數據的管理、控制器的選舉等操作。Producer 將消息發送到 Broker,Broker 負責將收到的消息存儲到磁盤中,而 Consumer 負責從 Broker 訂閱並消費消息。

整個 Kafka 體系結構中引入了以下3個術語:

Producer: 生產者,也就是發送消息的一方。生產者負責創建消息,然後將其投遞到 Kafka 中。

Consumer: 消費者,也就是接收消息的一方。消費者連接到 Kafka 上並接收消息,進而進行相應的業務邏輯處理。

Broker: 服務代理節點。接收來自生產者的消息,爲消息設置偏移量,並提交消息到磁盤保存,對於 Kafka 而言,Broker 可以簡單地看作一個獨立的 Kafka 服務節點或 Kafka 服務實例。如果一臺服務器上只部署了一個 Kafka 實例,也可以將這臺 Kafka 服務器看作Broker。一個或多個 Broker 組成了一個 Kafka 集羣。每個集羣都有一個 broker 同時充當了集羣控制器的角色(自動從集羣的活躍成員中選舉出來),一般用首字母小寫的 broker 來表示服務代理節點。

 

主題(Topic)分區(Partition)偏移量(offset)

Kafka 中的消息以主題爲單位進行歸類,可以說一個主題代表了一類消息。相當於是對消息進行分類,生產者負責將消息發送到特定的主題(發送到 Kafka 集羣中的每一條消息都要指定一個主題),而消費者負責訂閱主題並進行消費。

主題是一個邏輯上的概念,它還可以細分爲多個分區,也稱爲主題分區(Topic-Partition),同一個主題中的分區可以不在一個機器上,有可能會部署在多個機器上,由此來實現 kafka 的伸縮性,同一主題下的不同分區包含的消息也是不同的,分區在存儲層面可以看作一個可追加的日誌(Log)文件,消息在被追加到分區日誌文件的時候都會分配一個特定的偏移量(offset)。offset 是消息在分區中的唯一標識,Kafka 通過它來保證消息在分區內的順序性,不過 offset 並不跨越分區,也就是說,Kafka 保證的是分區有序而不是主題有序。

如上圖所示主題中有4個分區,消息被順序追加到每個分區日誌文件的尾部。Kafka 中的分區可以分佈在不同的服務器(broker)上,也就是說,一個主題可以橫跨多個 broker,以此來提供比單個 broker 更強大的性能和伸縮性。

每一條消息被髮送到 broker 之前,會根據分區規則選擇存儲到哪個具體的分區。如果分區規則設定得合理,所有的消息都可以均勻地分配到不同的分區中。如果一個主題只對應一個文件,那麼這個文件所在的機器I/O將會成爲這個主題的性能瓶頸,而分區解決了這個問題。在創建主題的時候可以通過指定的參數來設置分區的個數,當然也可以在主題創建完成之後去修改分區的數量,通過增加分區的數量可以實現水平擴展。

 

副本(Replica),重平衡(Rebalance

Kafka 爲分區引入了多副本(Replica)機制,消息的備份就叫做 副本,通過增加副本數量可以提升容災能力。副本的數量是可以配置的。同一分區的不同副本中保存的是相同的消息(在同一時刻,副本之間並非完全一樣),Kafka 定義了兩類副本:領導者副本(Leader Replica) 和 追隨者副本(Follower Replica),前者對外提供服務,後者只是被動跟隨,副本之間的“一主多從”關係中,其中 leader 副本負責處理讀寫請求,follower 副本只負責與 leader 副本的消息同步。副本處於不同的 broker 中,當 leader 副本出現故障時,從 follower 副本中重新選舉新的 leader 副本對外提供服務。Kafka 通過多副本機制實現了故障的自動轉移,當 Kafka 集羣中某個 broker 失效時仍然能保證服務可用。

如上圖所示,Kafka 集羣中有4個 broker,某個主題中有3個分區,分別是P1,P2,P3,且副本因子(即副本個數)也爲3,如此每個分區便有1個 leader 副本和2個 follower 副本。生產者和消費者只與 leader 副本進行交互,消息會先發送到 leader 副本,然後 follower 副本才能從 leader 副本中拉取消息進行同步,同步期間內 follower 副本相對於 leader 副本而言會有一定程度的滯後

重平衡:消費者組內某個消費者實例掛掉後,其他消費者實例自動重新分配訂閱主題分區的過程。Rebalance 是 Kafka 消費者端實現高可用的重要手段。

 

AR、ISR、OSR概念

AR(Assigned Replicas):分區中的所有副本的統稱

ISR(In-Sync Replicas):所有與 leader 副本保持一定程度同步的副本(包括 leader 副本在內)的組成(一定程度的同步”是指可忍受的滯後範圍,這個範圍可以通過參數進行配置)

OSR(Out-of-Sync Replicas): leader 副本同步滯後過多的副本(不包括 leader 副本)的組成

可以看出:ISR 集合AR 集合中的一個子集,AR=ISR+OSR。在正常情況下,不存在滯後過多的副本,所有的 follower 副本都應該與 leader 副本保持一定程度的同步,即 AR=ISR,OSR 集合爲空

leader 副本負責維護和跟蹤 ISR 集合中所有 follower 副本的滯後狀態,當 follower 副本落後太多或失效時,leader 副本會把它從 ISR 集合中剔除。如果 OSR 集合中有 follower 副本“追上”了 leader 副本,那麼 leader 副本會把它從 OSR 集合轉移至 ISR 集合。默認情況下,當 leader 副本發生故障時,只有在 ISR 集合中的副本纔有資格被選舉爲新的 leader,而在 OSR 集合中的副本則沒有任何機會(不過這個原則也可以通過修改相應的參數配置來改變)。

 

HW和LEO概念

HW 是 High Watermark 的縮寫,俗稱高水位,它標識了一個特定的消息偏移量(offset),消費者只能拉取到HW之前的消息

LEO 是 Log End Offset 的縮寫,它標識當前日誌文件中下一條待寫入消息的 offset

上圖代表一個日誌文件,這個日誌文件中有9條消息,第一條消息的 offset爲0,最後一條消息的 offset 爲8,offset 爲9的消息用虛線框表示,代表下一條待寫入的消息。其中日誌文件的 HW 爲6,表示消費者只能拉取到 offset 在0至5之間的消息,而 offset 爲6的消息對消費者而言是不可見的。 offset 爲9的位置即爲當前日誌文件的 LEO,LEO 的大小相當於當前日誌分區中最後一條消息的 offset 值加1。

 

分區 ISR 集合中的每個副本都會維護自身的 LEO,而 ISR 集合中最小的 LEO 即爲分區的 HW,對消費者而言只能消費 HW 之前的消息。

在消息寫入 leader 副本之後,follower 副本會發送拉取請求來拉取消息3和消息4以進行消息同步。在同步過程中,不同的 follower 副本的同步效率也不盡相同。如下圖所示,在某一時刻 follower1 完全跟上了 leader 副本而 follower2 只同步了消息3,如此 leader 副本的 LEO 爲5,follower1 的 LEO 爲5,follower2 的 LEO 爲4,那麼當前分區的 HW 取最小值4,此時消費者可以消費到 offset 爲0至3之間的消息。

 

 

只有當所有的副本都成功寫入了消息3和消息4,整個分區的 HW 和 LEO 都變爲5,因此消費者可以消費到 offset 爲4的消息了。

總結

由此可見,Kafka 的複製機制既不是完全的同步複製,也不是單純的異步複製。事實上,同步複製要求所有能工作的 follower 副本都複製完,這條消息纔會被確認爲已成功提交,這種複製方式極大地影響了性能。而在異步複製方式下,follower 副本異步地從 leader 副本中複製數據,數據只要被 leader 副本寫入就被認爲已經成功提交。在這種情況下,如果 follower 副本都還沒有複製完而落後於 leader 副本,突然 leader 副本宕機,則會造成數據丟失。Kafka 使用的這種 ISR 的方式則有效地權衡了數據可靠性和性能之間的關係。

 

Kafka 的特性(設計原則)

  • 高吞吐、低延遲:kakfa 最大的特點就是收發消息非常快,kafka 每秒可以處理幾十萬條消息,它的最低延遲只有幾毫秒;
  • 高伸縮性:每個主題(topic) 包含多個分區(partition),主題中的分區可以分佈在不同的主機(broker)中;
  • 持久性、可靠性:Kafka 能夠允許數據的持久化存儲,消息被持久化到磁盤,並支持數據備份防止數據丟失,Kafka 底層的數據存儲是基於 Zookeeper 存儲的,Zookeeper 我們知道它的數據能夠持久存儲;
  • 容錯性:允許集羣中的節點失敗,某個節點宕機,Kafka 集羣能夠正常工作;
  • 高併發:支持數千個客戶端同時讀寫。

Kafka 的使用場景

  • 活動跟蹤:Kafka 可以用來跟蹤用戶行爲,比如我們經常回去淘寶購物,你打開淘寶的那一刻,你的登陸信息,登陸次數都會作爲消息傳輸到 Kafka ,當你瀏覽購物的時候,你的瀏覽信息,你的搜索指數,你的購物愛好都會作爲一個個消息傳遞給 Kafka ,這樣就可以生成報告,可以做智能推薦,購買喜好等;
  • 傳遞消息:Kafka 另外一個基本用途是傳遞消息,應用程序向用戶發送通知就是通過傳遞消息來實現的,這些應用組件可以生成消息,而不需要關心消息的格式,也不需要關心消息是如何發送的;
  • 度量指標:Kafka也經常用來記錄運營監控數據。包括收集各種分佈式應用的數據,生產各種操作的集中反饋,比如報警和報告;
  • 日誌記錄:Kafka 的基本概念來源於提交日誌,比如我們可以把數據庫的更新發送到 Kafka 上,用來記錄數據庫的更新時間,通過kafka以統一接口服務的方式開放給各種consumer,例如hadoop、Hbase、Solr等;
  • 流式處理:流式處理是有一個能夠提供多種應用程序的領域;
  • 限流削峯:Kafka 多用於互聯網領域某一時刻請求特別多的情況下,可以把請求寫入Kafka 中,避免直接請求後端程序導致服務崩潰。

 

Kafka的安裝

由於kafka依賴zookeeper管理集羣元數據,所以在安裝kafka之前先安裝zookeeper,此外,Kafka 和 ZooKeeper 都是運行在 JVM 之上的服務,所以還需要安裝 JDK。注意:Kafka 從2.0.0版本開始就不再支持 JDK7 及以下版本,

Jdk和zookeeper的安裝:略

在安裝完 JDK 和 ZooKeeper 之後,就可以執行 Kafka broker 的安裝了,官網中下載安裝包kafka_2.11-2.0.0.tgz,解壓,配置環境變量

[root@node1 kafka]# ll kafka_2.11-2.0.0.tgz 
-rw-r--r-- 1 root root 55751827 Jul 31 10:45 kafka_2.11-2.0.0.tgz
[root@node1 kafka]# tar zxvf kafka_2.11-2.0.0.tgz# 解壓
[root@node1 kafka]# cd kafka_2.11-2.0.0
[root@VM_0_5_centos kafka_2.11-2.1.1]# ll
total 52
drwxr-xr-x 3 root root  4096 Feb  9  2019 bin
drwxr-xr-x 2 root root  4096 Feb  9  2019 config
drwxr-xr-x 2 root root  4096 Sep 26 10:11 libs
-rw-r--r-- 1 root root 32216 Feb  9  2019 LICENSE
-rw-r--r-- 1 root root   336 Feb  9  2019 NOTICE
drwxr-xr-x 2 root root  4096 Feb  9  2019 site-docs
[root@VM_0_5_centos kafka_2.11-2.1.1]# pwd
/usr/kafka/kafka_2.11-2.1.1
[root@node1 kafka_2.11-2.0.0]## Kafka的根目錄$KAFKA_HOME,將Kafka_HOME添加到/etc/profile文件中

接下來需要修改 broker 的配置文件 $KAFKA_HOME/conf/server.properties。主要關注以下幾個配置參數即可:

broker.id=0# broker對外提供的服務入口地址
listeners=PLAINTEXT://localhost:9092# 存放消息日誌文件的地址
log.dirs=/tmp/kafka-logs# Kafka所需的ZooKeeper集羣地址,爲了方便演示,我們假設Kafka和ZooKeeper都安裝在本機
zookeeper.connect=localhost:2181/kafka

如果是單機模式,那麼修改完上述配置參數之後就可以啓動服務。如果是集羣模式,那麼只需要對單機模式的配置文件做相應的修改即可:確保集羣中每個 broker 的 broker.id 配置參數的值不一樣,以及 listeners 配置參數也需要修改爲與 broker 對應的IP地址或域名,之後就可以各自啓動服務。注意,在啓動 Kafka 服務之前同樣需要確保 zookeeper.connect 參數所配置的 ZooKeeper 服務已經正確啓動。

#啓動 Kafka 服務:在$KAFKA_HOME 目錄下執行

bin/kafka-server-start.sh config/server.properties

#如果要在後臺運行 Kafka 服務,那麼可以在啓動命令中加入 -daemon 參數或&字符,示例如下:

bin/kafka-server-start.sh –daemon config/server.properties# 或者

bin/kafka-server-start.sh config/server.properties &

#可以通過 jps 命令查看 Kafka 服務進程是否已經啓動,示例如下:

[root@VM_0_5_centos kafka_2.11-2.0.0]# jps -l

12604 org.apache.zookeeper.server.quorum.QuorumPeerMain

23852 kafka.Kafka # 這個就是Kafka服務端的進程

24366 sun.tools.jps.Jps

注意:jps 命令只是用來確認 Kafka 服務的進程已經正常啓動

啓動成功後,可以利用kafka自帶的一些命令來實現消息的發送和消費,Kafka 提供了許多實用的腳本工具,放在 bin 目錄下,其中與主題有關的就是 kafka-topics.sh 腳本

1.創建一個分區數爲4、副本因子爲3的主題 topic-demo,示例如下

[root@node1 kafka_2.11-2.0.0]# bin/kafka-topics.sh --zookeeper localhost: 2181/kafka --create --topic topic-demo --replication-factor 3 --partitions 4

Created topic "topic-demo".

其中 --zookeeper 指定了 Kafka 所連接的 ZooKeeper 服務地址,--topic 指定了所要創建主題的名稱,--replication-factor 指定了副本因子,--partitions 指定了分區個數,--create 是創建主題的動作指令。

可以通過 --describe 展示主題的更多具體信息,示例如下:

[root@node1 kafka_2.11-2.0.0]# bin/kafka-topics.sh --zookeeper localhost: 2181/kafka --describe --topic topic-demo

Topic:topic-demo	PartitionCount:4	ReplicationFactor:3	Configs:
	Topic: topic-demo	Partition: 0	Leader: 2	Replicas: 2,1,0	Isr: 2,1,0
	Topic: topic-demo	Partition: 1	Leader: 0	Replicas: 0,2,1	Isr: 0,2,1
	Topic: topic-demo	Partition: 2	Leader: 1	Replicas: 1,0,2	Isr: 1,0,2
	Topic: topic-demo	Partition: 3	Leader: 2	Replicas: 2,0,1	Isr: 2,0,1

通過腳本 kafka-console-producer.sh 和 kafka-console- consumer.sh發送和消費消息,通過控制檯收發消息。首先我們打開一個 shell 終端,通過 kafka-console-consumer.sh 腳本來訂閱主題 topic-demo,示例如下:

[root@node1 kafka_2.11-2.0.0]# bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic topic-demo

其中 --bootstrap-server 指定了連接的 Kafka 集羣地址,--topic 指定了消費者訂閱的主題。目前主題 topic-demo 尚未有任何消息存入,所以此腳本還不能消費任何消息。

我們再打開一個 shell 終端,然後使用 kafka-console-producer.sh 腳本發送一條消息“Hello, Kafka!”至主題 topic-demo,如下:

[root@node1 kafka_2.11-2.0.0]# bin/kafka-console-producer.sh --broker-list localhost:9092 --topic topic-demo
>Hello, Kafka!
>

其中 --broker-list 指定了連接的 Kafka 集羣地址,--topic 指定了發送消息時的主題。示例中的第二行是通過人工鍵入的方式輸入的,按下回車鍵後會跳到第三行,即“>”字符處。此時原先執行 kafka-console-consumer.sh 腳本的 shell 終端中出現了剛剛輸入的消息“Hello, Kafka!”,示例如下:

[root@node1 kafka_2.11-2.0.0]# bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic topic-demo
Hello, Kafka!

Kafka安裝成功,生產消費成功。

擴展:Kafka中的server.properties的配置文件(集羣環境下:broker.id和listeners每個節點都不相同

#是否允許刪除topic,默認false不能手動刪除
delete.topic.enable=true
#當前機器在集羣中的唯一標識,和zookeeper的myid性質一樣
broker.id=0
#當前kafka服務偵聽的地址和端口,端口默認是9092
listeners = PLAINTEXT://192.168.100.21:9092
#這個是borker進行網絡處理的線程數
num.network.threads=3
#這個是borker進行I/O處理的線程數
num.io.threads=8
#發送緩衝區buffer大小,數據不是一下子就發送的,先會存儲到緩衝區到達一定的大小後在發送,能提高性能
socket.send.buffer.bytes=102400
#kafka接收緩衝區大小,當數據到達一定大小後在序列化到磁盤
socket.receive.buffer.bytes=102400
#這個參數是向kafka請求消息或者向kafka發送消息的請請求的最大數,這個值不能超過java的堆棧大小
socket.request.max.bytes=104857600
#消息日誌存放的路徑
log.dirs=/opt/module/kafka_2.11-1.1.0/logs
#默認的分區數,一個topic默認1個分區數
num.partitions=1
#每個數據目錄用來日誌恢復的線程數目
num.recovery.threads.per.data.dir=1
#默認消息的最大持久化時間,168小時,7天
log.retention.hours=168
#這個參數是:因爲kafka的消息是以追加的形式落地到文件,當超過這個值的時候,kafka會新起一個文件
log.segment.bytes=1073741824
#每隔300000毫秒去檢查上面配置的log失效時間
log.retention.check.interval.ms=300000
#是否啓用log壓縮,一般不用啓用,啓用的話可以提高性能
log.cleaner.enable=false
#設置zookeeper的連接端口
zookeeper.connect=node21:2181,node22:2181,node23:2181
#設置zookeeper的連接超時時間
zookeeper.connection.timeout.ms=6000

Docker安裝kafka


1、下載鏡像

docker pull zookeeper
docker pull wurstmeister/kafka

2、啓動zookeeper容器

docker run -d --name zookeeper  -p 2181:2181 zookeeper

3 、啓動kafka容器

docker run -d --name kafka -p 9092:9092 \
--link zookeeper:zookeeper \
--env KAFKA_BROKER_ID=1 \
--env HOST_IP=192.168.218.131 \
--env KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
--env KAFKA_ADVERTISED_HOST_NAME=192.168.218.131 \
--env KAFKA_ADVERTISED_PORT=9092 \
-t wurstmeister/kafka

中間兩個參數的192.168.218.131改爲宿主機器的IP地址
 

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