一次壓測實戰的復盤

  • 2020 年 7 月 24 日
  • 筆記

前言

​ 由於筆者在電商公司,算二三線的大廠了吧,最近跟京東拼的火熱。因為818大促在即,本人所負責的項目,在大促期間壓力會比較大,有必要對系統主要接口做一次壓測。下面復盤了,我這次壓測從發現問題分析問題總結的全過程,希望能對你有所啟發。

問題

​ 壓測時發現系統的瓶頸在於cpu,那麼考慮為啥瓶頸在cpu,以及如何優化?

發現過程

​ 測試環境使用jmeter進行接口壓測,然後逐步調大並發度,觀察系統吞吐量,然後在ares平台(類似skywalking)上監測JVM內存,CPU,線程狀態等

​ 然後發現,gc信息和內存信息很穩定,但是cpu會達到90%,這時查看jvm的線程狀態,發現又70%左右的線程處於waiting或者timed_waiting狀態;

​ 初步推算會不會是線程過多導致cpu過高。

問題分析

首先分析接口的執行流程以及線程池的使用場景

​ 簡單的描述一下:客戶端發來一個請求,由容器線程接收,然後通過common線程池創建多個線程去並發執行,然後通過latch進行等待,等所有的common線程執行完在合併然後返回給客戶端;每一個common線程是一個小任務可以稱為「單品查佣」,common線程會首先使用select線程池創建4個並行任務進行參數轉換,並且通過latch進行等待然後合併,緊接着繼續並發進行查詢,此時也是使用select線程池先去並發查詢然後再common線程裏面合併計算結果。

上圖顏色相同的表示在同一個線程或者線程池,通過上圖可以大概得出common線程池和select線程池線程個數比為1:5(是不是真的這麼去設置線程池大小呢?)。

開始壓測

壓測環境和結果

說明:由於之前做過一次優化,基本將DB和ES的壓力因素去除了,JVM中的內存,帶寬因素基本也排除了,目的就是為了看CPU壓力。

環境:首先根據業務場景,分析由於整個流程中有多次的RPC調用或者Redis等數據請求所以初步將任務定義為IO等待型,目標機器配置2C4G * 2 ,同用的測試參數

工具:Jmeter

壓測結果:

結果分析

  1. 在common,select線程數分別為5,25時(第一組數據),隨着並發數的上升cpu並沒有徒增,穩定在80%左右,但是tps並沒有線性增長,平均響應時間也明顯下降了不少,但是發現並發數的提高沒有將CPU壓到極限,開始懷疑是業務線程相關了。

這個時候通過ares平台分析JVM線程狀態,發現如下:

分割線—————————————————————————————————————-

然後查看等待狀態的線程,發現大部分是select的線程,而且大部分處於getTask方法上面,熟悉線程池運行原理的同學都知道,這個是在獲取任務,因為沒有任務了所以阻塞等待了,所以可以指定select的線程個數明顯設置過多。從另一方面也說明,common和select的線程個數比不對,不是按照分析1:5 設置。因此下面的測試降低select的線程數。

  1. common和select線程數分別為5,10時,減少了select線程的個數,cpu和tps和剛剛差不多,但是select的等待線程少了,這裡慢慢發現common線程個數對tps和cpu有一定的影響,而select線程個數影響不大。這時發現增大並發數並不會顯著提高TPS,但是響應時間是會明顯增加。

  1. common和select線程數分別為10,10時,大部分common線程在latch上面等待,會不會是select線程不夠用?隨着並發數增多,響應時間在下降,但是tps並沒有增加,具體可以看下圖,common在latch上面(和代碼對應),

  1. common和select線程數分別為10,20時,通過觀察線程狀態,select線程出現等待getTask,cpu會到達94%,tps相應的也會增加,並發數的增加也只是提高了tps,但是會導致響應時間的下降;另外並發增大時,select線程都在執行任務,common線程出現在latch上面等待,但是響應時間慢了,cpu忙了,因為所有的select線程都在運行,線程上下文切換(CS)次數肯定會大量增加(可以vmstat查看),

初步總結

總結: 綜合這4組壓測數據,初步有個簡單的結論,common線程池決定了整體的吞吐量(TPS),但是吞吐量提升的的同時,CPU和響應時間也會增大,而select線程需要依賴common線程的個數,比例在1.5-2之間,少了會導致TPS上不去響應時間也會增加,大了CPU上去了,最終也會導致響應時間的增加,所以common和select線程數的選擇需要有據可詢。那麼針對當前的機器配置,兼顧TPS,響應時間和CPU使用率(低於90%),common線核心程池數設置8,select線程數設為12,此時100的並發數,CPU最高在90%,TPS在760,平均響應時間100ms。

優化方向:

通過線程狀態和業務流程的分析,我們發現可以將並發部分的業務流程進行細分,主要劃分為IO等待型任務和CPU計算型任務,然後使用不同的線程池,IO型的就多設置線程數,CPU型的就少一點。有個初始經驗值

IO 型:2 * CPU個數

CPU型:CPU個數 + 1

另外,分析過程中為了方便線程池配置的變更和觀察使用公共包ThreadPoolManager來管理系統所有的線程池。有需要的可以使用

壓測時機器的其他指標,供參考

Pidstat

Vmstat

Mpstat