誰是性能殺手?Kafka多Topic下啓用SSL時延增大問題分析

問題背景html

項目中將Kafka接口進行RESTful封裝,在使用RESTful接口進行性能測試時,發現Topic數增多後,開啓SSL與非SSL進行測試,發現開啓SSL後性能降低得厲害。例如600個Topic總數每一個Topic3分區3副本的場景下,使用1200個線程只發送10個Topic,開啓SSL的TPS只有3100,可是不開啓SSL性能達到11000。java

 

其中測試客戶端會啓動多個線程,每一個線程採用同步發送的方式調用RESTful API發送,即每次發送成功一條後才發送下一條。 客戶端會根據發送線程在Topic數之間進行均分,例如1200個線程發送10個Topic,則每一個Topic同時有120個線程進行發送。git

 

定位與分析過程github

1.SSL性能降低算法

1.定位分析安全

開啓SSL是會致使性能降低的, 主要來自於CPU的耗時與JVM的具體實現,參見Kafka官網的解釋:網絡

 

從咱們以前測試的結果來看,高可靠場景SSL性能降低並無太厲害(從2.3W TPS降低到2.1W TPS)。應該是觸發了某些其餘問題。經過JStack查看啓動SSL下的堆棧,發現存在一些發送線程被Block住:併發

 

這個堆棧裏面作的事情,是來自於java.security.SecureRandom要產生隨機數,採用」SHA1PRNG」算法。在sun/oracle的jdk裏,這個隨機算法的的實如今底層依賴到操做系統提供的隨機數據,默認用的是/dev/random,在讀取時,/dev/random設備會返回小於熵池噪聲總數的隨機字節。/dev/random可生成高隨機性的公鑰或一次性密碼本。若熵池空了,對/dev/random的讀操做將會被阻塞,直到收集到了足夠的環境噪聲爲止。這個問題在網上也查到,主要是JDK提供的SecureRandom函數存在1個全局的鎖,在熵源不足且SSL線程多的時候很容易碰到這個問題,具體見:oracle

https://github.com/netty/netty/issues/3639dom

http://bugs.java.com/view_bug.do?bug_id=6521844

 

2.解決措施

措施一:更新JDK

目前這個問題是在OpenJDK 1.8中解決了,能夠經過升級JDK到使用OpenJDK,可是這個方案不太好替換,而且OpenJDK和原來有什麼不兼容還不清楚。

措施二:採用非阻塞的熵源: /dev/urandom

經過設置-Djava.security.egd=file:/dev/./urandom宏,隨機數時選擇/dev/urandom,它會重複地使用熵池中的數據以產生僞隨機數據避免阻塞,不過隨機安全性會下降。

 

2.Topic多狀況下性能降低

1.定位分析

發如今Topic600個狀況下,非SSL與SSL的時延其實差距並無原先發現的問題那麼大,如下是咱們用SDK接口測試的時延數據:

600個 Topic總量下,400個線程同時發送10個Topic,非SSL與SSL時延對比:

能夠看出時延差距在20%以內,主要的時延增長來自於Topic增多致使的。 

爲何Topic增多會致使時延增多?針對這個問題經過在程序進行打點測試,如下是在不一樣的Topic數量狀況下,針對10個Topic,總髮送5000條消息的場景下,非SSL時延對比:

其中總時延 = 消息的待發送隊列等待時延 + 服務端處理平均時延 + 網絡發送與響應時延。

 

從上面的表格能夠看出基本上每一個處理環節上都增長了時延4~5倍。爲何會出現這種狀況?分析以下可能點:

一、磁盤的寫速度變慢

二、Server因爲Topic多須要過濾信息變慢

三、複製處理在多Topic下變慢。即便無數據,多Topic下複製線程也會一直髮送空請求

四、Topic多資源佔用大

 

經過逐一分析、排除與測試,主要緣由仍是在第三點:服務端在複製處理在Topic數量多的狀況下變慢致使的。

 

例如10個Topic的時候,若是用10個複製線程(目前性能測試就是配置10)用於副本複製,則每一個複製線程會分配到1個Topic;而當Topic有600個的時候,若是仍是10個複製線程用於副本複製,則每一個複製線程會分配到60個Topic。 若是此時只發送前10個Topic的時候,頗有可能只有1個複製線程在工做,其餘的複製線程因爲分配到的Topic沒有數據,基本處於空閒狀態。

 

2.解決措施

既然複製線程變慢,咱們能夠經過繼續增長複製線程的方式提升性能,在600個Topic場景只發送10個Topic場景下,咱們把複製線程提高到60個,這樣10個Topic能儘量分配到不一樣的複製線程中,提升了複製的速度。如下是實際測試結果:

能夠看到增長到60個fetch線程後,時延變爲100ms左右。同時原來的環境下,經過增長複製線程(修改配置num.replica.fetchers=60),在原環境下1200個發送線程即便啓動SSL,性能也能達到11000+。

 

性能提高措施總結

RESTful API是同步接口,可是內部使用的SDK接口是異步發送。根據高可靠場景下異步發送的能力能達到2W+ TPS來看,主要仍是同步接口的併發壓力上不去致使的,能夠經過如下措施來改進:

一、增長請求等待時間linger.ms

經過在客戶端增長參數linger.ms,使得每一個請求回等待指定的時間後再發送,使得每一個請求能夠發送更多的數據,即增長合包率。

二、增長同步發送對同1個Topic的併發數量

三、減小Topic的分區數

由於目前RESTful API並無用盡服務端的能力(1個分區的能力瓶頸還沒達到),默認的3個分區是浪費資源,而且會致使合包率下降,若是採用1個分區,則一樣的壓力下,合包率能提高3倍,這樣性能也能提高。這個措施還能夠支持更多的Topic數。

四、增長複製線程

五、考慮提供異步發送SDK接口

相關文章
相關標籤/搜索