京東熱key探測框架本地壓測數據記錄,單機(8核)QPS約16萬/s,可水平擴展

繼上一次全鏈路壓測時,熱key框架由於Java低版本(1.8.0_131之前的1.8版本)獲取docker內cpu核數有問題,實則獲取的是宿主機的核數,造成線程數量過多,壓測瞬間cpu達到100%,問題也記錄在了另一篇https://blog.csdn.net/tianyaleixiaowu/article/details/106092060)。後來找到了問題原因,併成功修復了。然後還修改了一些其他的小問題,總體感覺框架比較穩定了。我就自己做了一些性能方面的壓測,分別先後使用了4臺、8臺、16臺、32臺機器作爲壓力源,用死循環發送熱key消息的方式,測試worker集羣的性能,worker分別使用了8核、16核兩種規格,數量都是2臺,機器都是部署在docker內的。

首先說一下,我寫的熱key框架文章沒有講前因後果,會顯得比較突兀。所以簡單解釋一下,worker端是一個Java程序,裏面是一個netty server,用來接收來自於後端服務集羣發來的字符串,然後對字符串進行歸併,對相同的字符串數量進行累加,超過一定閾值的字符串,判定爲熱key,然後通過netty推送給這些後端服務集羣。好比一個用戶是個爬蟲,他的userId=123456,他一直不停地訪問後端集羣,那麼後端就會陸續把這個userId發往worker集羣,worker對這個字符串的頻率次數進行累加,譬如超過了設定的2秒10次就算爬蟲,超過後worker集羣就會把這個key推送給所有的後端服務,然後後端服務會記錄到自己內存裏,之後就可以對這個熱key做操作了,譬如禁止他訪問相關接口,做限流等等。

所以,這個worker也就是netty server它的性能就至關重要,後端集羣每秒發過來或者幾萬、幾十萬、幾百萬個key信息,我就需要得到worker單機的QPS性能,然後根據實際的量來決定開多少個worker機器,worker是可以水平擴展的。

worker內部是使用netty單線程的bossGroup和cpu核數個workGroup,work接收到消息後自己不處理,全部寫入到disruptor內,disruptor是200萬的bufferSize,disruptor的消費者也是cpu核數個線程,每個線程只處理特定的key(即hash後取餘分到消費者線程)。理論上消費的速度即是該應用的QPS。所以我通過反覆調節線程數,緩存量等維度來測試性能表現。

之前老是有人抄我文章,到處亂髮,還不註明出處。所以版權聲明:本文爲CSDN博主「天涯淚小武」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。

原文鏈接:https://tianyalei.blog.csdn.net/article/details/106327336

來看一下測試過程:

8核8G單機性能表現

worker端是固定2臺機器,我用了2臺8核8G的,壓力機用了4臺4核的,代碼很簡單就是死循環裏netty發消息,讓worker的netty server來接收並處理。netty server端我做了數量的統計,分別在接收到消息時變量totalReceiveCount數量加1,然後在數量處理完畢的地方totalDealCount加1。

很明顯,接收的速率肯定是大於處理的速率的,接收到了沒處理肯定是不算QPS的,當然處理的過程也很簡單,就是內存計數累加,超過閾值就推送。

我每10秒打印一次接收的數量和處理過的數量,如圖

 

從日誌情況來看,每10秒大概處理了160萬個key信息,接收量也差不多是160萬,也就是基本上接收到的都被處理了,不存在明顯的卡頓阻塞。這是單機的情況,兩臺機器情況是一致的。也就是兩臺每秒30多萬QPS的樣子。cpu佔有率在70以上,但沒有被打滿。當前的cpu佔用原則上已達到極限,故我們認爲8核的單機QPS在16萬。

16核單機性能表現

壓力源不變,還是每10秒160萬個key。

從日誌上看,16核機器也是每10秒160萬比較平穩,接收量和處理量保持一致。

cpu使用率明顯是要比8核的小的多,大概在30%左右。說明在壓力源保持不變的情況下,處理端的吞吐量是恆定的,核數多了,相應的只是cpu佔用小一些。

16核單機調大線程數後性能表現

隨後我把16核機器程序內處理消息的線程數調大一倍,從核數*1個線程,變成核數*2個線程,也就是變成了32個線程,日誌如下,發現其實並沒有什麼變化,甚至有逐步下降的趨勢。

原因也很明顯,這是cpu密集型的應用,單核單線程處理的應該會更快,因爲避免了cpu輪轉切換,加大線程數並沒有實際意義,如果線程過多,甚至導致性能下降。

我又恢復了16個線程,然後加大了disruptor的bufferSize,原來是200萬,改成了1600萬,同時將內存從16G加大到32G,大幅調大了JVM的新生代和老年代內存,同樣是沒什麼鳥用,除了大幅增加了yong GC的耗時,其他的什麼好處也沒有。因爲200萬完全夠用了,接收速率並沒有比處理速率快很多,產生不了幾百萬的差距。

cpu倒是比內存小時佔用更多了,有突破40%的趨勢,主要還是因爲gc時耗時大、耗cpu也高了。所以還是恢復了200萬的bufferSize。

加大壓力源後16核單機性能表現

之後我不斷加大壓力源,從4臺到8臺又到30臺4核4G的。

可能是我壓力源的死循環寫的問題,導致壓力源自身的發送量遲遲上不去,所以到worker接收端這邊,也只是到了10秒200萬的水平,看處理量,也是20萬/s的樣子。

worker端cpu的使用率也達到了50%。從16萬/s的35%cpu到20萬/s的50%。處理量和cpu的增長還算同步,但性價比其實不算高了。

在實際生產中,單機能到10萬的QPS已經算是比較高的場景了,如果不夠用,最好還是加個機器以分擔峯值。

總結:該框架單機8核16萬QPS,處於夠用的狀態,實際上netty server最高能處理多少,我也不清楚,沒有相關的參考標的。如果能遠遠大於目前我的這個處理速率,可能是我程序寫的不夠完善。實際生產中如果量級不大,建議8c8g的機器再根據實際情況水平擴容。如果量級有突發特別密集的不確定因素存在,考慮上16核機器,畢竟16核在20萬QPS時,cpu也才50%。上限遠遠大於8核的。

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