1. 程式人生 > 實用技巧 >24丨Kafka:效能監控工具之佇列級監控及常用計數器解析

24丨Kafka:效能監控工具之佇列級監控及常用計數器解析

在我看來佇列伺服器是最簡單的一種元件了。因為佇列給我們下手的機會實在是並不多。我們只是用它,如果想改變它就只能去改程式碼,其他的都只是配置問題。

在當前的市場中,Kafka算是用得非常火的一個佇列伺服器了,所以今天,我選擇它來做一些解讀。

雖然我在前面一直在強調分析的思路,但在這一篇中,我打算換個思路,不是像以前那樣,直接給你一個結論型的思維導圖,而是一起來分析一個元件,讓我們看看從哪裡下手,來觀察一個被分析物件的相關配置。

瞭解Kafka的基本知識

我們先看一下這張圖,以便更好地瞭解一個佇列伺服器。

這是Kafka官網上的一個圖。從這個圖中可以看到,對Kafka來說,這就像一個典型的集線器。那它裡面的結構是什麼樣子的呢?根據我的理解,我畫了一個如下的示意圖:

在這個圖中,有三個Broker,也就是三個叢集節點。每個訊息有一個leader partition,還有兩個follower partition。我沒有畫更多的Producer和Consumer、Consumer Group,是覺得線太多了容易亂。

因為Producer和Consumer肯定會從leader partition中讀寫資料,而Kafka也保證了leader在不同broker上的均衡,所以Kafka的叢集能力很好。

我們再看一下訊息是如何在Kafka中被儲存的。

上圖是Kafka資料的儲存方式,也就是每個分割槽都是一直往後面加的。

我們再來看一下它的資料儲存方式。

首先是目錄:

drwxr-xr-x 2 root root 4096 Feb  7 23:39 test-0
drwxr-xr-x 2 root root 4096 Feb  7 01:34 test_perf-1
drwxr-xr-x 2 root root 4096 Feb  7 01:34 test_perf-4

Kafka的目錄是根據topic建立的,每個目錄名中也包括一個partition。比如上面名字中的test_perf-1就是topic名是test_perf,partition就是1。

接著再來看下檔案:

[root@node-2 test-2]# ll
total 10850656
-rw-r--r-- 1 root root     493128 Feb  9 14:14 00000000000000000000.index
-rw-r--r-- 1 root root 1073739646 Feb  9 14:14 00000000000000000000.log
-rw-r--r-- 1 root root     630504 Feb  9 14:14 00000000000000000000.timeindex
-rw-r--r-- 1 root root     443520 Feb  9 14:16 00000000000000240212.index
-rw-r--r-- 1 root root 1073727327 Feb  9 14:16 00000000000000240212.log
-rw-r--r-- 1 root root     551052 Feb  9 14:16 00000000000000240212.timeindex
-rw-r--r-- 1 root root     448840 Feb  9 14:18 00000000000000453584.index
-rw-r--r-- 1 root root 1073729759 Feb  9 14:18 00000000000000453584.log
-rw-r--r-- 1 root root     556920 Feb  9 14:18 00000000000000453584.timeindex
.........................
-rw-r--r-- 1 root root         12 Feb  9 13:14 leader-epoch-checkpoint
[root@node-2 test-2]#

有索引檔案,有資料檔案,也有時間索引檔案,非常明顯的三個字尾名。索引檔案顯然就是指向message在資料檔案中的什麼位置,而這些資料檔案就是一個個的Segment,也就是一段一段的。這些檔案的大小受server.properties檔案中的log.segment.bytes引數限制,預設為1G。

要查到相應的message就要先查索引檔案,找到message的位置;然後從log檔案中找到具體的message。

在這個邏輯中,Segment的大小就很有講究了,太細就會導致索引檔案過大,查詢索引費時間;太粗了就會導致查詢得不夠精準。那麼該如何配置呢?也要通過效能測試才能知道。

有了這些資訊之後,我們再看下Kafka高效的原因:

  1. Kafka直接使用Linux檔案系統的Cache來高效快取資料。
  2. Kafka採用Linux Zero-Copy技術提高發送效能(不懂Linux Zero-copy的請自行補課)。
  3. Kafka服務端採用的是selector多執行緒模式(從邏輯上理解,它和Tomcat的NIO類似,我就不單獨畫圖了,以免佔篇幅)。
  4. Kafka採用二分法找資料。

總體來說,就是一個Java的應用,直接使用檔案系統和作業系統的特性實現了佇列的高效應用場景。

配置檔案

我們先來檢視一下Kafka的配置檔案中都有什麼,為了簡潔,在這裡,我把一些註釋以及和效能無關的配置刪除了。當然如果你有興趣的話,可以到Kafka的config目錄中找到server.properties中,以檢視這些內容。

############################# Socket Server Settings #############################
num.network.threads=3
num.io.threads=8
socket.send.buffer.bytes=102400
socket.receive.buffer.bytes=102400
socket.request.max.bytes=104857600


############################# Log Basics #############################
num.partitions=10
num.recovery.threads.per.data.dir=1


############################# Internal Topic Settings  #############################
offsets.topic.replication.factor=1
transaction.state.log.replication.factor=1
transaction.state.log.min.isr=1


############################# Log Flush Policy #############################
log.flush.interval.messages=10000
log.flush.interval.ms=1000


############################# Log Retention Policy #############################
log.retention.check.interval.ms=300000


############################# Zookeeper #############################
zookeeper.connection.timeout.ms=6000


############################# Group Coordinator Settings #############################
group.initial.rebalance.delay

其實配置檔案並不多,對不對?從配置名稱上也很容易知道它們和什麼相關。這裡比較重要的引數就是Socket Server相關的,以及和log相關的。

我覺得到了這裡,這個邏輯就基本清楚了,對Kafka的效能優化也就有了大體的判斷。

構建Kafka的效能優化思維導圖

我們可以根據以上的知識畫出如下所示的,Kafka的基本優化點:

同樣的,我把作業系統和JDK方面的優化當成獨立的部分,在上圖中只把Kafka相關的內容列出來。

有了上面的知識,也有了這個思維邏輯,那麼就可以理出針對一個Kafka應用要乾的事情:

  1. 先分析一下具體的應用場景,關鍵是topic、partition數量、message大小。
  2. 確定要支撐的業務容量和時間長度。
  3. 分析架構中需要的broker量級、partition、Segment等配置。這些配置應該是架構師給出的準確預估,如果不能給出,那隻能靠我們,也就是做效能測試的人給出具體的結論了。

對元件的效能分析思路

我想告訴你的是對一個元件的效能分析思路。如果你有了下面這張圖所示的思路,那至少可以覆蓋大部分的效能問題了。這個思路就是:

對於Kafka這樣的佇列伺服器來說,狀態計數器是啥子呢?讓我們看一下Kafka的一個Grafana Dashboard。

從這幾個圖就能看得出來,最重要的是每秒產生了多少message,以及消費時間間隔。這兩個對我們來說是最重要的佇列計數器了。

但是它們能不能告訴我們現在的佇列伺服器有沒有瓶頸呢?顯然是不能的。

對於佇列來說,訊息都是非同步被消費者取走的。所以佇列中要有儲存訊息的能力,但是儲存多久呢?永遠儲存嗎?顯然不現實。但是如果儲存得太短了,正常的業務都可能做不下去,所以,我們要制定策略,哪些topic是實時處理的,處理不完怎麼辦?記憶體多大,能儲存多少訊息,積壓了怎麼辦?

所以對於佇列伺服器,只看上面的那幾個計數器,我覺得過於片面。

我們前面提到的grafana+prometheus監控作業系統、MySQL的DashBoard都有非常完整的資料,但是Kafka的DashBoard顯然資訊不夠,不能判斷它自己有沒有問題。

作業系統的監控指標對Kafka來說,也是異常的重要。就像之前我說過的那樣,作業系統是不可繞過的分析節點。所以所有要做效能測試和效能分析的人,首先要學的就是作業系統方面的知識。

示例

下面我們來看一個簡單測試示例。

生產10W訊息

在這個示例中,共生產10W的訊息,每個訊息大小是2000位元組,每秒產生5000個訊息。

[root@node-1 Kafka_2.13-2.4.0]# /home/zee/Kafka/Kafka_2.13-2.4.0/bin/Kafka-producer-perf-test.sh --topic test --num-records 100000 --record-size 2000 --throughput 5000 --producer-props bootstrap.servers=172.18.0.2:9092,172.19.0.14:9092,172.20.0.7:9092
24997 records sent, 4999.4 records/sec (9.54 MB/sec), 15.8 ms avg latency, 398.0 ms max latency.
25010 records sent, 5001.0 records/sec (9.54 MB/sec), 26.0 ms avg latency, 514.0 ms max latency.
25000 records sent, 5000.0 records/sec (9.54 MB/sec), 1.1 ms avg latency, 24.0 ms max latency.
100000 records sent, 4998.000800 records/sec (9.53 MB/sec), 11.03 ms avg latency, 514.00 ms max latency, 1 ms 50th, 52 ms 95th, 305 ms 99th, 501 ms 99.9th.

可以看到每秒有9.53MB的訊息產生,平均響應時延是11.03ms,最大時延是514ms。

生產100W訊息

在這個示例中,共生產100W的訊息,每個訊息大小是2000位元組,每秒產生5000個訊息。

[root@node-4 bin]# /home/zee/Kafka/Kafka_2.13-2.4.0/bin/Kafka-producer-perf-test.sh --topic test_perf --num-records 1000000 --record-size 2000 --throughput 5000 --producer-props bootstrap.servers=172.17.0.11:9092,172.19.0.14:9092,172.20.0.7:9092
24992 records sent, 4996.4 records/sec (9.53 MB/sec), 21.7 ms avg latency, 482.0 ms max latency.
25025 records sent, 5004.0 records/sec (9.54 MB/sec), 0.9 ms avg latency, 16.0 ms max latency.
........
25000 records sent, 5000.0 records/sec (9.54 MB/sec), 0.6 ms avg latency, 9.0 ms max latency.
25005 records sent, 5001.0 records/sec (9.54 MB/sec), 0.7 ms avg latency, 30.0 ms max latency.
1000000 records sent, 4999.625028 records/sec (9.54 MB/sec), 2.05 ms avg latency, 482.00 ms max latency, 1 ms 50th, 1 ms 95th, 16 ms 99th, 267 ms 99.9th.

可以看到每秒有9.54MB的訊息產生,平均響應時延是2.05ms,最大時延是482ms。

生產1000W訊息

在這個示例中,生產1000W訊息,其他引數不變:

[root@node-4 bin]# /home/zee/Kafka/Kafka_2.13-2.4.0/bin/Kafka-producer-perf-test.sh --topic test_perf --num-records 10000000 --record-size 2000 --throughput 5000 --producer-props bootstrap.servers=172.17.0.11:9092,172.19.0.14:9092,172.20.0.7:9092
24992 records sent, 4998.4 records/sec (9.53 MB/sec), 22.7 ms avg latency, 480.0 ms max latency.
25015 records sent, 5002.0 records/sec (9.54 MB/sec), 0.8 ms avg latency, 13.0 ms max latency.
25005 records sent, 5000.0 records/sec (9.54 MB/sec), 0.7 ms avg latency, 21.0 ms max latency.
..........
25000 records sent, 5000.0 records/sec (9.54 MB/sec), 0.7 ms avg latency, 26.0 ms max latency.
25010 records sent, 5001.0 records/sec (9.54 MB/sec), 0.7 ms avg latency, 24.0 ms max latency.
10000000 records sent, 4999.900002 records/sec (9.54 MB/sec), 0.83 ms avg latency, 532.00 ms max latency, 1 ms 50th, 1 ms 95th, 4 ms 99th, 65 ms 99.9th.

從結果可以看到,每秒還是9.54MB大小的訊息,平均時延0.83ms,最大時延是532ms。

來做一個圖比對一下:

從這個圖就明顯看出生產的訊息越少,平均響應時間越長。可見順序寫得越多,那每次寫的平均時間就會越小,所以Kafka在大資料量的讀寫中會表現得非常好。

總結

嚴格來說,這一篇文章是為了告訴你一個邏輯,那就是對一個元件不瞭解的時候,如何用你的基礎技術知識把對元件的效能優化方向整理出來,以及如何通過自己的基礎知識來做一個非常合理的分析。

這個邏輯就是:

  1. 先了解這個元件的基本知識:包括架構、實現原理等資訊。
  2. 再整理出這個元件的配置引數。
  3. 找到合適的全域性監控工具。
  4. 做壓力測試時給出明顯的判斷。

這是個大體的邏輯,當然這個邏輯還有一個前提,那就是你得有相應的基礎知識,在Kafka的這個分析中,要有作業系統和Java的基礎知識,在實操中還需要多找幾個不懂的元件做些練習才能理解這個邏輯的真諦。

就我自己來說,我會找一個完全沒有接觸過的元件,從安裝部署開始直到效能測試、瓶頸判斷、優化分析,看看需要多長時間,我才能理解得了這個元件。

這種思維方式,給了我很多的安全感,就是遇到了沒接觸過的內容,也不至心慌氣短。