天天看點

基于Jmeter的性能壓測平台實作

很早就想要一套屬于自己的性能壓測平台,原因是使用了阿裡雲的性能測試PTS,就挺羨慕能有一個這樣的性能測試平台,但畢竟人家的東西我們高攀不起(要錢的),而且阿裡雲的性能測試平台是不支援多種協定的(比如我有一個項目要用websocket測試,結果人家就支援http壓測)。

  說到開發自己的性能測試平台,肯定想到的是Jmeter,因為開源的性能測試工具沒有比它更強大的了,是以第一個想到的是怎麼把它變成性能測試平台,很多人首先想到的是通過jenkins結合jmeter,我想那也隻能叫排程平台,不能叫性能測試平台。通過對Jmeter和Java快速開發架構的深入了解,我發現做一個自己的性能壓測平台是可行的,而且網上也有人正在做。開發的過程肯定是無限的踩坑(開源的東西就這樣),相對收獲來說應該值的。以下是我針對開源的Java快速開發架構和别人實作的部分成品,再結合JMeterEngine的深入學習,梳理的平台架構:

基于Jmeter的性能壓測平台實作

  以下是主要的技術選型及說明:

核心架構:Spring Boot 1.5

安全架構:Apache Shiro 1.3

視圖架構:Spring MVC 4.3

持久層架構:MyBatis 3.3

定時器:Quartz 2.3

資料庫連接配接池:Druid 1.0 (阿裡開源)

日志管理:SLF4J 1.7、Log4j

頁面互動:Vue2.x

前端監控:ECharts 3.8

壓測核心(即JMeterEngine):Apache JMeter 4.0

腳本調用核心:Apache Commons Exec 1.3

遠端執行指令:Ganymed build210

  選用的快速架構是經量級的,而且是友善快速部署的:

  【renren-fast開發架構】,具體可以上網擷取:https://www.renren.io/guide/

性能測試平台的項目結構

stress-test

├─doc  項目SQL語句

├─common 公共子產品

│  ├─aspect 系統日志

│  ├─exception 異常處理

│  ├─validator 背景校驗

│  └─xss XSS過濾

├─config 配置資訊

├─modules 功能子產品

│  ├─api API接口子產品(APP調用)

│  ├─job 定時任務子產品

│  ├─oss 檔案服務子產品

│  ├─sys 權限子產品

│  └─test 壓測子產品

├─RenrenApplication 項目啟動類

├──resources

│  ├─mapper SQL對應的XML檔案

│  ├─static 第三方庫、插件等靜态資源

│  ├─views  項目靜态頁面

│  └─application.yml 環境配置

   

平台已實作的部分功能

  (1)用例管理:

基于Jmeter的性能壓測平台實作

  用例管理支援jmx腳本的上傳和參數化檔案及測試附件的上傳,一個用例建立一個目錄(腳本、參數檔案、附件、測試報告都在同一用例下儲存)。删除用例時會自動删除用例下所關聯的腳本,并一并删除已同步到各個節點的檔案。

  (2)腳本檔案管理

  每個腳本具有啟動和停止壓測線程的功能(具有狀态辨別),每個參數化檔案或附件具有同步到各個節點的功能(同步完成後辨別為同步成功)。

基于Jmeter的性能壓測平台實作

  腳本檔案除了啟動和停止功能,還能配置是否開啟報告生成和是否開戶前端監控,監控為echarts圖形監控,如下:

基于Jmeter的性能壓測平台實作

  調用腳本進行壓測的方法分為兩種:

基于Jmeter的性能壓測平台實作

(3)測試報告管理

  

基于Jmeter的性能壓測平台實作

  預設執行腳本過程中,生成了CSV報告,通過【生成報告】按鈕,觸發将csv報告轉換成html DashBoard(這一步也是通過Commons Exec排程jmeter指令完成):

基于Jmeter的性能壓測平台實作

(4)分布式節點管理

基于Jmeter的性能壓測平台實作

  分布式節點管理通過Ganymed遠端執行linux指令,來啟動或是停止各節點的Jmeter-server,啟動指令格式如下:

//啟動節點

String enableResult = ssh2Util.runCommand(

"cd " + slave.getHomeDir() + "/bin/testCases/" + "\n" +

"sh " + "../jmeter-server -Djava.rmi.server.hostname="+slave.getIp());

  如果是禁用節點,就是通過遠端執行殺程序的指令:

ssh2Util.runCommand("ps -efww|grep -w 'jmeter-server'|grep -v grep|cut -c 9-15|xargs kill -9");

  這種方式挺友善,省了在多台linux節點機上,手動去連接配接和啟動jmeter(分布節點越多越顯得友善快捷)。

  另外跟原來相比,分布式節點管理增加了校準功能,就是為了解決節點因為人為因素停了,而管理端不能及時的作出判斷,現在通過校準可以将背景節點的程序狀态跟前台同步一次(避免程序異常關閉或錯誤啟動),目前不是自動校準。因為無論是實時監聽端口還是定時校準,效率都不是最好的。以後可以嘗試在壓測過程中添加監聽機制,來實時監測節點狀态,而非壓測時段就通過手動點選校準即可,這樣會相對經濟一些。

  (5)監控擴充(Grafana+InfluxDB)

  由于我在以前的一篇文章中寫過有關Grafana+InfluxDB與Jmeter的監控(關于Jmeter長時間壓測的可視化監控報告),可以直接拿過來內建使用。內建的方式是開啟Grafana的匿名登入(在defaults.ini中配置),到官網下一個Jmeter的監控視圖JSON模闆導入,同時以跳轉的方式将Grafana嵌入到平台的iframe中。

var URL_IP = parent.location.host;

var URL_PORT = parent.location.port;

window.location = "http://"+URL_IP.replace(":"+URL_PORT,"")+":3000/d/joulMbxmz/apache-jmeter-dashboard?orgId=1";

基于Jmeter的性能壓測平台實作

   另外可以将Grafana和InfluxDB及一鍵啟動腳本與性能壓測平台一起部署,實作在部署層面上進行內建和無縫對接使用。

  寫到這我們的性能壓測平台前期部分基本介紹完了,還有些功能未開始開發,比如像阿裡雲PTS的壓測場景配置,這比較複雜,相當于是把腳本的場景設定移到WEB界面上,另外還要結合定時器進行腳本的靈活排程(發起壓測、結束壓測、持續時間、測試周期等),目前來看還沒想好怎麼實作。但是可以先實作線程組的線上管理:

  (6)線程組管理

基于Jmeter的性能壓測平台實作

  線程組管理的原理也不複雜,就是上傳腳本時,通過dom4j遞歸掃描Jmx腳本(本質上是xml)的節點,擷取線程組的配置節點參數,儲存入庫,然後在界面上修改和管理,改完還可以同步回Jmx腳本(也是通過dom4j對xml進行set配置)。目前實作的管理的線程組類别包括預設的ThreadGroup、jp@gc - Stepping Thread Group、jp@gc - Ultimate Thread Group,這三種已經算最常用的了。線程組管理的目的就是免去簡單的線程配置(如并發數配置、線程組禁用)還要線下設定,設定完又要上傳,另外腳本的線程組配置在平台界面上也能一目了然,避免又要臨時打開Jmeter工具進行檢視。

  (7)壓測節點監控

基于Jmeter的性能壓測平台實作

  既然有了分布式節點管理,那邊我們也可以做到對節點的分布式監控,在Influxdb-Grafana的基礎上,引入telegraf來實作;我們通過界面上,加入監控開啟和停止的按鈕,再結合節點上部署的一些批處理指令,來實作一鍵啟動監控代理。

  啟動和關閉的核心代碼如下:

/**

* 批量切換節點的監控狀态

*/

@Override

public void updateMonitorBatchStatus(List<Long> slaveIds, Integer monitorStatus) {

String execStr="";

for (Long slaveId : slaveIds) {

StressTestSlaveEntity slave = queryObject(slaveId);

// 本機節點無需遠端操作

if ("127.0.0.1".equals(slave.getIp().trim())) {

Runtime r = Runtime.getRuntime();

//執行本地作業系統指令,不關心傳回結果,

Process p = null;

try {

if(OS_NAME_LC.startsWith("windows")){

if (StressTestUtils.ENABLE.equals(monitorStatus))

execStr = "cmd.exe /c \""+StressTestUtils.getJmeterHome()+"\\telegraf\\start.cmd\" -a";

else

execStr = "cmd.exe /c taskkill /im telegraf.exe /f";

}else{

execStr = "sh "+StressTestUtils.getJmeterHome()+"/telegraf/startUp.sh "+slave.getSlaveName();

execStr = "sh "+StressTestUtils.getJmeterHome()+"/telegraf/stop.sh "+slave.getSlaveName();

}

p = r.exec(execStr);

p.waitFor();

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

} finally {

if(null!=p){

p.destroy();

p=null;

//更新資料庫

slave.setMonitorStatus(monitorStatus);

update(slave);

continue;

//其他節點需要SSH遠端連接配接

SSH2Utils ssh2Util = new SSH2Utils(slave.getIp(), slave.getUserName(),

slave.getPasswd(), Integer.parseInt(slave.getSshPort()));

// 避免跨系統的問題,遠端由于都時linux伺服器,則檔案分隔符統一為/,不然同步檔案會報錯。

String telegrafServer = slave.getHomeDir() + "/telegraf/telegraf";

String md5Str = ssh2Util.runCommand("md5sum " + telegrafServer + " | cut -d ' ' -f1");

if (!checkMD5(md5Str)) {

throw new RRException(slave.getSlaveName() + " 監控子產品出錯!找不到telegraf啟動檔案!");

//如果是開啟監控

if (StressTestUtils.ENABLE.equals(monitorStatus)) {

//啟動監控

execStr =

"sh " + slave.getHomeDir() + "/telegraf/startUp.sh "

+ slave.getSlaveName()+" "+stressTestUtils.getLocalIp();

//禁用監控

execStr = "sh " + slave.getHomeDir() + "/telegraf/stop.sh";

String enableResult = ssh2Util.runCommand(execStr);

logger.error(enableResult);

if (!enableResult.contains("telegraf")) {

throw new RRException(slave.getSlaveName() + " telegraf執行失敗!請先嘗試在節點機指令執行");

  從代碼我們也可以看出,我們将telegraf啟動和配置檔案都放置在jmeter節點的根目錄下,這樣能友善遠端SSH調用,同時我們将監控平台的IP和節點名稱也發送過去,并更新到telegraf.conf檔案中,這樣啟動的telegraf程序就會将監控資料發回到我們的influxdb,并通過grafana監控到。以下是監控的效果:

基于Jmeter的性能壓測平台實作

  這樣我們就實作了對壓測機的監控(在測試過程中不對壓測機監控是不合理的,特别是CPU、記憶體、網絡IO等,萬一出現測試機的性能瓶頸由于不能及時發現就會導緻無用功),除了壓測機的監控,我們可以由點及面,做出一個壓測平台的監控服務平台,對被測服務端也進行監控。

  更正說明:寫這篇文章的時候,阿裡雲的PTS剛剛能支援原生jmeter(但前提是有項目支援你花這錢),也就是能支援websocket的壓測,具體使用說明他們也提供了教程:

https://help.aliyun.com/document_detail/93627.html?spm=5176.7946858.1219570.3.4ced572dQgCraE

繼續閱讀