原文由rihkddd發(fā)表于TesterHome社區(qū),點(diǎn)擊原文鏈接可與作者直接交流。
壓測(cè)背景
臨近雙十一大家都免不了要對(duì)自己的業(yè)務(wù)系統(tǒng)進(jìn)行壓測(cè)。公司一個(gè)核心業(yè)務(wù)預(yù)計(jì)雙十一會(huì)迎來(lái)數(shù)倍日常流量的業(yè)務(wù)高峰,該系統(tǒng)強(qiáng)依賴(lài)于 Kafka,Kafka 本身是分布式的系統(tǒng),擴(kuò)容比較方便。但是為了保證核心業(yè)務(wù)的穩(wěn)定性和高可用,需要在機(jī)房故障的場(chǎng)景下核心業(yè)務(wù)快速恢復(fù)服務(wù),因此 Kafka 需要跨機(jī)房熱備機(jī)制。
一般情況的 Kafka 集群,都是在同一個(gè) IDC 中的,跨 IDC 的熱備在 Kafka 的使用場(chǎng)景叫做 Mirror,Kafka 內(nèi)置的支持為 MirrorMaker,現(xiàn)在已經(jīng)進(jìn)化到了第二版,下文簡(jiǎn)稱(chēng)為 MM2.
經(jīng)過(guò)前期技術(shù)調(diào)研,基本確定了 MM2 的 Kafka 熱備機(jī)制。為了確定這套方案在雙十一的流量高峰情況下,能滿(mǎn)足消息系統(tǒng)熱備的需求,需要提前做壓測(cè)。
壓測(cè)實(shí)施
MM2的工作原理可以簡(jiǎn)單理解為:在目的端機(jī)房消費(fèi)源端機(jī)房需要復(fù)制的消息。因此MM2 的壓測(cè),本質(zhì)上還是 Kafka 的壓測(cè)。而幸運(yùn)的是 Kafka 作為高性能、廣泛使用的消息隊(duì)列,它本身就提供了 benchmark 工具,可以方便的使用內(nèi)置的命令行進(jìn)行壓測(cè)。
基本的用法如下:
./bin/kafka-producer-perf-test.sh --topic test_perf --num-records 1000000 --record-size 15000 --throughput -1 --producer-props bootstrap.servers=10.xx.xx.1:9094,10.xx.xx.2:9094 acks=1
幾個(gè)重要的參數(shù)解釋如下:
- acks 消息確認(rèn)模式,-1 表示需要確認(rèn)所有副本都寫(xiě)入成功,1 表示只需確認(rèn)一個(gè)副本寫(xiě)入成功,0 表示無(wú)需確認(rèn)。
- --topic topic 名稱(chēng),本例為 test_perf
- --num-records 總共需要發(fā)送的消息數(shù),本例為 1000000
- --record-size 每個(gè)記錄的字節(jié)數(shù),本例為 15000
- --throughput 每秒鐘發(fā)送的記錄數(shù),本例為 -1,表示不做限制
- --producer-props bootstrap.servers=localhost:9092 發(fā)送端的配置信息,本例只指定了 kafka 的鏈接信息
- --producer-num-retries 一個(gè)消息失敗發(fā)送重試次數(shù)
- --request-timeouts-ms 一個(gè)消息請(qǐng)求發(fā)送超時(shí)時(shí)間
消息體的大小,我們可以根據(jù)實(shí)際的業(yè)務(wù)場(chǎng)景構(gòu)造合適的消息大小,例如統(tǒng)計(jì)一批消息的平均大?。?/p>
./bin/kafka-console-consumer.sh --bootstrap-server 10.xx.xx.1:9094,10.xx.xx.2:9094 --topic sdsoms --max-messages=100 | wc
acks 模式需要和實(shí)際生產(chǎn)環(huán)境保持一致即可。
確定了消息體大小,和 acks 之后,可以調(diào)整 num-records 和 throughput,保證有足夠的消息數(shù)量和速率。
性能問(wèn)題
在具體壓測(cè)實(shí)施過(guò)程中,遇到了不少問(wèn)題。經(jīng)過(guò)業(yè)務(wù)預(yù)估,雙十一業(yè)務(wù)高峰時(shí) Kafka 需要承受的 QPS 約為 x 萬(wàn),但是初次壓測(cè)下來(lái)的數(shù)據(jù)僅能到幾千就出現(xiàn)了大量的跨機(jī)房復(fù)制消息延遲。
問(wèn)題分析
通過(guò)對(duì)機(jī)器負(fù)載分析發(fā)現(xiàn):
部署消息遷移服務(wù)的機(jī)器 CPU/磁盤(pán)都沒(méi)有到平靜,實(shí)際上從 MM2 消息遷移的原理來(lái)看,它工作完全是在內(nèi)存中完成,因此磁盤(pán)基本沒(méi)有使用。
那么最有可能的問(wèn)題就出在了網(wǎng)絡(luò)上。
跨 IDC 的消息同步會(huì)面臨幾個(gè)問(wèn)題:
- IDC 之間的網(wǎng)絡(luò)延遲(RTT)會(huì)遠(yuǎn)高于 IDC 內(nèi)的,典型的情況下機(jī)房?jī)?nèi)的延遲往往在 0.1ms 以?xún)?nèi),而廣州到上海的 IDC 延遲一般為 30ms。
- 帶寬有限,且成本高???IDC 的網(wǎng)絡(luò)鋪設(shè)成本高,總帶寬有限,費(fèi)用很高。機(jī)房?jī)?nèi)部雙千兆一般都是標(biāo)配,萬(wàn)兆也很普及,而且一般是免費(fèi)使用。
經(jīng)過(guò)一番分析和計(jì)算,在壓測(cè)的業(yè)務(wù)場(chǎng)景中,消息體較大,達(dá)到了 15000Byte(典型的消息應(yīng)用場(chǎng)景中消息體一般在幾十到幾百 Byte),這個(gè)大小在幾千的 QPS 下,帶寬就需要幾百兆大小。
為了確定是帶寬的原因,一方面同 OP 確定跨機(jī)房的帶寬上限。另一方面在兩個(gè)機(jī)房的機(jī)器上安裝 iperf3 工具測(cè)試速度。
使用 iperf3 工具測(cè)試網(wǎng)絡(luò)速度:
# MM2目的端的機(jī)器(也就是MM2服務(wù)部署機(jī)器)操作
iperf3 -s
# MM2源端的機(jī)器操作
iperf3 -c MM2_host_ip
綜合測(cè)速結(jié)果和 OP 反饋的機(jī)房間帶寬,發(fā)現(xiàn)確實(shí)到了帶寬瓶頸。
所以向 OP 申請(qǐng)臨時(shí)調(diào)高帶寬,帶寬調(diào)高了 X 倍。
本以為,機(jī)房間帶寬增加之后,MM2 的性能應(yīng)該也會(huì)有接近 X 倍的提升。但是實(shí)際情況卻是:
在性能有小幅提升后,在 CPU/磁盤(pán)/網(wǎng)絡(luò)依然沒(méi)有到達(dá)瓶頸的情況下,再出出現(xiàn)了大量的跨機(jī)房消息復(fù)制延遲。
經(jīng)過(guò)一番深入分析發(fā)現(xiàn),在高延遲的網(wǎng)絡(luò)環(huán)境中,打滿(mǎn)帶寬不是一件顯而易見(jiàn)的事情:
我們知道 Kafka 使用的是 TCP 網(wǎng)絡(luò)傳輸協(xié)議,TCP 在經(jīng)過(guò)三次握手之后,開(kāi)始進(jìn)入的流量控制階段,在這個(gè)階段,會(huì)使用滑動(dòng)窗口確定一個(gè) RTT 時(shí)間范圍內(nèi)發(fā)送的數(shù)據(jù)量。在一個(gè) TCP 連接中,如果網(wǎng)絡(luò)延遲很大,那么它實(shí)際上不是那么容易能完全利用帶寬。
這里引入一個(gè)概念:
帶寬時(shí)延乘積,在數(shù)據(jù)通信中,帶寬時(shí)延乘積(英語(yǔ):bandwidth-delay product;或稱(chēng)帶寬延時(shí)乘積、帶寬延時(shí)積等)指的是一個(gè)數(shù)據(jù)鏈路的能力(每秒比特)與來(lái)回通信延遲(單位秒)的乘積。其結(jié)果是以比特(或字節(jié))為單位的一個(gè)數(shù)據(jù)總量,等同在任何特定時(shí)間該網(wǎng)絡(luò)線(xiàn)路上的最大數(shù)據(jù)量——已發(fā)送但尚未確認(rèn)的數(shù)據(jù)。
當(dāng)然,在現(xiàn)代的高延遲、大帶寬網(wǎng)絡(luò)中 TCP 提供了縮放因子來(lái)解決這個(gè)問(wèn)題,可以避免 TCP 默認(rèn)最大窗口 65535 帶來(lái)的帶寬利用不足問(wèn)題。
沿著這個(gè)思路,我們對(duì)服務(wù)的網(wǎng)絡(luò)相關(guān)參數(shù)做了一些調(diào)整,主要增加了 tcp 相關(guān) buffer 大小,雖然帶來(lái)了一些提升,但是離我們的目標(biāo)還很遠(yuǎn)。這是因?yàn)?,考慮一個(gè)線(xiàn)路的傳輸速率時(shí),除了需要考慮 BDP 這個(gè)因素外,還需要考慮丟包率,滑動(dòng)窗口增加,在增加發(fā)送速率的同時(shí),也增加了丟包重傳的成本。
性能優(yōu)化
在帶寬上限提不上去的情況下,還想提升 QPS,那么可行的方案就是減小消息體大小。減小消息體有兩個(gè)思路:
- 壓縮。
- 消息裁剪。
壓縮
壓縮就是在消息生產(chǎn)之后,進(jìn)入 producer 時(shí),進(jìn)行壓縮,之后的同集群落盤(pán)和跨集群 MM2 復(fù)制,就都是壓縮后的消息了。producer 和 consumer 一般都內(nèi)置了消息壓縮的支持,Kafka 支持 GZIP、Snappy、LZ4 三種壓縮算法,從 2.1.0 開(kāi)始正式支持 zstd 算法。各種壓縮算法之間的對(duì)比可以參考這個(gè)文章:http://zhongmingmao.me/2019/08/02/kafka-compression/
在我們的使用場(chǎng)景中,我們希望盡可能的提高壓縮比,降低網(wǎng)絡(luò)傳輸量,雖然 zstd 具有最高的壓縮比,不幸的時(shí)我們使用的版本尚不支持,因此只能退而求其次選擇了 GZIP 算法。但即使時(shí) GZIP 也能獲得很高的壓縮比。
消息剪裁
原來(lái)的消息體很大主要的原因是,很多數(shù)據(jù)其實(shí)不需要,但是為了簡(jiǎn)單方便,都放到了消息中,通過(guò)仔細(xì)分析消息字段,并去除不需要的字段,大幅減小了消息體大小。
通過(guò)上述兩種優(yōu)化的疊加,基本上達(dá)到了預(yù)期的壓測(cè)目標(biāo),希望消息系統(tǒng)可以順利通過(guò)雙十一的考驗(yàn)。
參考資料
[1] https://engineering.salesforce.com/mirrormaker-performance-tuning-63afaed12c21
[2] https://plantegg.github.io/2019/09/28/就是要你懂TCP--性能和發(fā)送接收Buffer的關(guān)系/
[3] http://www.dengshenyu.com/kafka-data-mirror/
[4] https://www.slideshare.net/JiangjieQin/producer-performance-tuning-for-apache-kafka-63147600
原文由rihkddd發(fā)表于TesterHome社區(qū),點(diǎn)擊原文鏈接可與作者直接交流。

今日份的知識(shí)已攝入!想要學(xué)習(xí)更多干貨知識(shí)、結(jié)識(shí)質(zhì)量行業(yè)大牛和業(yè)界精英?
第十屆中國(guó)互聯(lián)網(wǎng)測(cè)試開(kāi)發(fā)大會(huì)·深圳,了解下 >>