1. 程式人生 > >360度測試:KAFKA會丟資料麼?其高可用是否滿足需求?

360度測試:KAFKA會丟資料麼?其高可用是否滿足需求?

更多內容,請關注微信公眾號《小姐姐味道》,本文連結

3BB0DD8E-7440-422F-9070-14A0CD3FF8BA.png

請仔細瞭解這張圖,尤其注意有標誌的幾個關注點。我們會不止一次回到這張圖上

背景

Kafka到底能夠應用在高可用的業務上?官方給出的答案是肯定的,最新版,已經支援訊息佇列的事務,但我們對其效能是有疑問的。 Kafka根據配置的ACK級別,其效能表現將特別大,為了找到其適用場景,特做此測試,以便應用kafka時能夠靈活應對。 測試過程還探討了許多丟訊息的場景。相對於大多數僅僅針對kafka叢集本身的測試,本測試還介紹了丟訊息的業務場景。整個方案應該是一個整體,才能夠達到最高級別的高可用,不因該區別對待。

測試目標

  • 叢集高可用,以及需要滿足高可用時需要的最小叢集大小和相關配置以及限制等
  • 訊息不丟失,以及為了滿足訊息不丟失需要的配置和約定等
  • 測試環境

broker:

3臺機器
8 core 
16G 
1T SSD 
Centos 6.8
kafka_2.12-0.10.2.0 
broker jvm引數配置:Xms=8G Xmx=8G
複製程式碼

client:

8 core 
16G 
Centos 6.8
複製程式碼

測試場景

叢集高可靠性配置:

zookeeper.connection.timeout.ms=15000
zookeeper.session.timeout.ms=15000
default.replication.factor=3
num.partitions=6
 min.insync.replicas=2
 unclean.leader.election.enable=false
log.flush.interval.ms=1000 複製程式碼

ack

acks= all
 retries = 3
 request.timeout.ms=5000
複製程式碼

訊息大小:1024byte


failover 測試

測試方法

下線一個節點,測試故障的恢復時間和故障期間的服務水平

測試過程

replica.lag.time.max.ms 從 10s 調整為 60s(延長時間方便觀察),然後 kill Broker 0,挑選 3 個 partition,觀察 ISR 變化如下: 其中,第二 / 三階段入隊成功率受損:

  • 第二階段期間,Partition 96/97/98 均無法寫入,入隊成功率成功率下降至 0%。
  • 第三階段期間,Partition 96 可繼續寫入,但 Partition 97/98 無法寫入,因為寫入要等 Broker 0 回 ack,但 Broker 0 已 kill,入隊成功率下降至 33%。

而實際觀察,第二 / 三階段期間完全沒吞吐,原因是壓測工具不斷報連線失敗,停止了寫入。

原因分析

Kafka Broker leader 是通過 Controller 選舉出來的,ISR 列表是 leader 維護的。 前者的的租約是 Controller 定義的,後者的租約是 Broker 配置 replica.lag.time.max.ms 指定的。 所以,第二階段持續時間較短,是 Controller 的租約時間決定的,第三階段持續時間較長,是 replica.lag.time.max.ms 決定的。 當 Broker 0 被 kill 時,前者影響本來 Broker 0 是 leader 的 1/3 partitions 的入隊成功率,後者影響 Broker 0 作為 follower 的 2/3 partitions 的入隊成功率。

HA結論

kafka在failover期間,會有大約10秒的不可用時間,該時間由 replica.lag.time.max.ms 決定。因此應用程式需要處理此種情況下的異常資訊,設定合理的重試次數和退避演算法。


壓力測試

測試方法

測試指令碼:

./kafka-producer-perf-test.sh --topic test003 --num-records 1000000 --record-size 1024  --throughput -1 --producer.config ../config/producer.properties
複製程式碼

測試結果

不限制併發吞吐量

[[email protected] bin]# time ./kafka-producer-perf-test.sh --topic ack001 --num-records 1000000 --record-size 1024 --throughput -1 --producer.config ../config/producer.properties
[2017-09-14 21:26:57,543] WARN Error while fetching metadata with correlation id 1 : {ack001=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)
81112 records sent, 16219.2 records/sec (15.84 MB/sec), 1416.2 ms avg latency, 1779.0 max latency.
92070 records sent, 18414.0 records/sec (17.98 MB/sec), 1671.7 ms avg latency, 1821.0 max latency.
91860 records sent, 18368.3 records/sec (17.94 MB/sec), 1670.3 ms avg latency, 1958.0 max latency.
91470 records sent, 18294.0 records/sec (17.87 MB/sec), 1672.3 ms avg latency, 2038.0 max latency.
91050 records sent, 18202.7 records/sec (17.78 MB/sec), 1678.9 ms avg latency, 2158.0 max latency.
92670 records sent, 18534.0 records/sec (18.10 MB/sec), 1657.6 ms avg latency, 2223.0 max latency.
89040 records sent, 17808.0 records/sec (17.39 MB/sec), 1715.0 ms avg latency, 2481.0 max latency.
86370 records sent, 17274.0 records/sec (16.87 MB/sec), 1767.5 ms avg latency, 2704.0 max latency.
91290 records sent, 18254.3 records/sec (17.83 MB/sec), 1670.2 ms avg latency, 2553.0 max latency.
92220 records sent, 18444.0 records/sec (18.01 MB/sec), 1658.1 ms avg latency, 2626.0 max latency.
90240 records sent, 18048.0 records/sec (17.63 MB/sec), 1669.9 ms avg latency, 2733.0 max latency.
1000000 records sent, 17671.591150 records/sec (17.26 MB/sec), 1670.61 ms avg latency, 2764.00 ms max latency, 1544 ms 50th, 2649 ms 95th, 2722 ms 99th, 2753 ms 99.9th.
real 0m57.409s
user 0m14.544s
sys 0m2.072s
複製程式碼

限制吞吐量 1w

[[email protected] bin]# time ./kafka-producer-perf-test.sh --topic ack003 --num-records 1000000 --record-size 1024 --throughput 10000 --producer.config ../config/producer.properties
[2017-09-15 10:51:53,184] WARN Error while fetching metadata with correlation id 1 : {ack003=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)
[2017-09-15 10:51:53,295] WARN Error while fetching metadata with correlation id 4 : {ack003=LEADER_NOT_AVAILABLE} (org.apache.kafka.clients.NetworkClient)
49766 records sent, 9953.2 records/sec (9.72 MB/sec), 34.9 ms avg latency, 358.0 max latency.
50009 records sent, 10001.8 records/sec (9.77 MB/sec), 23.9 ms avg latency, 39.0 max latency.
50060 records sent, 10008.0 records/sec (9.77 MB/sec), 23.9 ms avg latency, 49.0 max latency.
49967 records sent, 9991.4 records/sec (9.76 MB/sec), 23.6 ms avg latency, 38.0 max latency.
50014 records sent, 10000.8 records/sec (9.77 MB/sec), 24.0 ms avg latency, 51.0 max latency.
50049 records sent, 10007.8 records/sec (9.77 MB/sec), 23.5 ms avg latency, 37.0 max latency.
49978 records sent, 9995.6 records/sec (9.76 MB/sec), 23.5 ms avg latency, 44.0 max latency.
49803 records sent, 9958.6 records/sec (9.73 MB/sec), 23.7 ms avg latency, 47.0 max latency.
50229 records sent, 10045.8 records/sec (9.81 MB/sec), 23.6 ms avg latency, 46.0 max latency.
49980 records sent, 9996.0 records/sec (9.76 MB/sec), 23.5 ms avg latency, 36.0 max latency.
50061 records sent, 10010.2 records/sec (9.78 MB/sec), 23.6 ms avg latency, 36.0 max latency.
49983 records sent, 9996.6 records/sec (9.76 MB/sec), 23.4 ms avg latency, 37.0 max latency.
49978 records sent, 9995.6 records/sec (9.76 MB/sec), 23.9 ms avg latency, 55.0 max latency.
50061 records sent, 10012.2 records/sec (9.78 MB/sec), 24.3 ms avg latency, 55.0 max latency.
49981 records sent, 9996.2 records/sec (9.76 MB/sec), 23.5 ms avg latency, 42.0 max latency.
49979 records sent, 9991.8 records/sec (9.76 MB/sec), 23.8 ms avg latency, 39.0 max latency.
50077 records sent, 10013.4 records/sec (9.78 MB/sec), 23.6 ms avg latency, 41.0 max latency.
49974 records sent, 9994.8 records/sec (9.76 MB/sec), 23.4 ms avg latency, 36.0 max latency.
50067 records sent, 10011.4 records/sec (9.78 MB/sec), 23.8 ms avg latency, 65.0 max latency.
49963 records sent, 9992.6 records/sec (9.76 MB/sec), 23.5 ms avg latency, 54.0 max latency.
1000000 records sent, 9997.300729 records/sec (9.76 MB/sec), 24.24 ms avg latency, 358.00 ms max latency, 23 ms 50th, 28 ms 95th, 39 ms 99th, 154 ms 99.9th.
real 1m40.808s
user 0m16.620s
sys 0m1.260s
更多...
吞吐量5k 1000000 records sent, 4999.275105 records/sec (4.88 MB/sec), 22.94 ms avg latency, 127.00 ms max latency, 23 ms 50th, 27 ms 95th, 31 ms 99th, 41 ms 99.9th.
吞吐量2w 1000000 records sent, 18990.827430 records/sec (18.55 MB/sec), 954.74 ms avg latency, 2657.00 ms max latency, 739 ms 50th, 2492 ms 95th, 2611 ms 99th, 2650 ms 99.9th.
吞吐量3w 1000000 records sent, 19125.212768 records/sec (18.68 MB/sec), 1527.07 ms avg latency, 3020.00 ms max latency, 1582 ms 50th, 2815 ms 95th, 2979 ms 99th, 3011 ms 99.9th.
複製程式碼

12分割槽,2.6w吞吐量

[[email protected] bin]# time ./kafka-producer-perf-test.sh --topic ack001 --num-records 1000000 --record-size 1024 --throughput 26000 --producer.config ../config/producer.properties
129256 records sent, 25840.9 records/sec (25.24 MB/sec), 31.9 ms avg latency, 123.0 max latency.
129794 records sent, 25953.6 records/sec (25.35 MB/sec), 28.6 ms avg latency, 73.0 max latency.
130152 records sent, 26025.2 records/sec (25.42 MB/sec), 28.3 ms avg latency, 64.0 max latency.
130278 records sent, 26045.2 records/sec (25.43 MB/sec), 28.1 ms avg latency, 55.0 max latency.
130106 records sent, 26010.8 records/sec (25.40 MB/sec), 27.9 ms avg latency, 45.0 max latency.
130080 records sent, 26005.6 records/sec (25.40 MB/sec), 27.7 ms avg latency, 41.0 max latency.
130093 records sent, 26013.4 records/sec (25.40 MB/sec), 74.5 ms avg latency, 343.0 max latency.
1000000 records sent, 25904.051394 records/sec (25.30 MB/sec), 38.33 ms avg latency, 343.00 ms max latency, 28 ms 50th, 122 ms 95th, 242 ms 99th, 321 ms 99.9th.
real 0m39.395s
user 0m12.204s
sys 0m1.616s
複製程式碼

cpu與記憶體無任何變化。網路rx/tx :170Mbps/120Mbps,磁碟IoUtil: 6%。1百萬資料能在2分鐘內完成。

壓測結論

影響提交效率的原因主要有:partition數量 + 超時時長 + 訊息大小 + 吞吐量

  • 不做限制:ack=all的模式,不限制吞吐量,TPS能夠保持在2w左右,平均耗時在1600ms左右,99.9%的記錄能夠兩秒左右正常提交反饋,最大耗時有記錄超過5秒。

  • 超時時長:當將超時時常設定為5秒以上時,提交全部成功(ack)。將超時逐步降低到3秒左右,陸續會有大量超時出現。官方的預設值為30秒,考慮到網路環境的複雜性,建議將此引數設定成10秒,如還有超時,需要客戶端捕獲異常進行特殊處理。

  • 訊息大小:當將訊息大小設定為512byte,提交的TPS能夠打到3w/秒;當增加到2k左右,TPS降低到9k/s,訊息大小與TPS成線性關係。

  • 流量:當限制吞吐量為1.3w左右,減少競爭,效果最佳。平均耗時降低到24毫秒,最大延遲僅300多毫秒,服務水平相當高。

  • 分割槽數量:增加分割槽數能顯著提高處理能力,但分割槽數會影響故障恢復時間。本測試用例僅針對6分割槽的情況,測試證明,當分割槽數增加到12,處理能力幾乎增加一倍,但繼續增加,效能不會再有顯著提升。

最終結論:假定網路狀態良好,在ack=all模式、超時10秒、重試3次、分割槽為6的情況下,能夠承受1.3w/s的訊息請求,其寫入平均耗時不超過30ms,最大耗時不超過500ms。想要增加TPS,可以增加partition到12,能夠達到2.6w/s的高效寫入。

堆積測試

kafka生產和消費理論上不受訊息堆積影響,訊息堆積只是佔用磁碟空間,這裡的訊息堆積是指topic中的訊息數,和訊息是否消費無關


結論

kafka採用基於時間的SLA(服務水平保證),重要訊息儲存3天。

效能

基本配置:訊息1k大小,ack=all,即所有副本都同步的情況。為確保訊息可靠,全部採用3個副本。

  • 3副本,1個partition的情況:6k-8k
  • 3副本,6個partition的情況:1.3w-1.6w
  • 3副本,12個partion的情況:2.6w-2.8w

注意:生產端,考慮一種場景,單條傳送,然後呼叫future.get()確認,TPS會急劇降低到2k以下,請確認確實需要這麼做,否則,使用非同步提交,callback呼叫的方式。相對於ACK模式1.6w的TPS,普通模式提交,能夠達到13w(主要是網路和IO瓶頸,頻寬佔滿)。當吞吐量限制在1w左右並且開啟ACK(非常符合我們的業務特徵),kafka是高效且高可用的,平均耗時僅24毫秒,生產者的最佳實踐是將超時設定成10秒,重試3次。消費者同樣是高效的,6個partition、ack模式,平均耗時在20毫秒左右,具體處理耗時取決於消費端的處理能力。

kafka訊息可靠性

  • 寫3個副本,開啟ack=all模式,每1秒刷一次磁碟。一條訊息要經歷Client --> Leader →Replica這個過程。leader等待所有的replica的ack應答,然後ack給Client端,整個過程多次確認;ack失敗的訊息,會再次重試,此模式能保證資料不丟失。要想達到此種訊息級別,請務必按照架構組提供的最佳實踐進行配置(kafka不同版本間引數相差很多)。
  • 訊息傳遞有三種模式,kafka同步傳送是At least one模式(0.10版)。消費端,要做冪等處理。可能產生重複訊息的場景為:生產端傳送了訊息到leader節點,leader節點同步到所有follower節點並得到確認,此時leader節點當機,未將ack返回給生產端,生產端此時會嘗試重發訊息。然後follower節點中某臺機器提升為leader,重複的資料由此產生。

擴容,故障的影響

  • 單節點當機,短暫影響生產消費,故障恢復時間與leader選舉時間與partition數量有關(約10秒isr探測時間)。使用ACK模式,配合重試,能夠保證故障期間資料不丟失。上圖的2位置。
  • 擴容,等同於節點上線,不影響使用方。但節點到達可用狀態,與整體落後資料量相關(簡單的網路拷貝過程)。根據經驗,部分訊息拉取時間會變長,但影響不大。壓測過程無明顯抖動。建議消費端設定較長的超時來進行處理(包括非同步處理情況)。上圖的3位置。
  • =2節點當機(機房斷電等),服務不可用。故障恢復需要兩個節點達到同步狀態,與整體資料量相關。磁碟每秒fsync,極端情況(全部當機),最多會丟失1秒資料。


什麼時候會丟資料

  • 使用batch模式傳送,緩衝區有資料時沒有優雅關閉,此時緩衝區中資料會丟失。上圖1位置。
  • 使用batch模式消費,拉取訊息後,非同步使用執行緒池處理,如果執行緒池沒有優雅關閉,此時消費資料會丟失。上圖4位置。

風險

  • 壓測TPS僅作參考,實際執行中受網路延遲,壞盤、高低峰流量等影響,服務會有抖動。生產和消費端務必將所有處理失敗的訊息進行記錄,以便極端情況下進行資料回放。
  • 訊息中請勿傳遞大塊不必要資料,訊息大小對服務質量有直接線性影響。(請保持訊息<2kb)
  • 消費端消費,除考慮冪等,不正確的非同步執行緒池使用(比如使用了無界佇列),經常造成消費端故障,請謹慎消費。
  • 如分配了6個partition,如果你有7臺消費機器,其中有一臺會是空閒的。設計時請考慮kafka的限制。
  • 預設kafka生產端開啟了batch提交模式,也就是說,如果此時你的生產者當了,buffer中的訊息會丟。請確保:生產者使用"kill -15"殺程序以給服務flush的機會;同時,如果你的訊息很重要,請同時寫入到日誌檔案中。 請權衡利弊再確認使用。