Jmeter的性能壓測平臺實現


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

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

該平臺已經開源(無Java經驗的測試人員慎入,以免煩擾): https://gitee.com/smooth00/stressTestSystem

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

核心框架: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(現已支持5.1.1版本)
腳本調用內核: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)用例管理:

用例管理支持jmx腳本的上傳和參數化文件及測試附件的上傳,一個用例創建一個目錄(腳本、參數文件、附件、測試報告都在同一用例下保存)。刪除用例時會自動刪除用例下所關聯的腳本,並一併刪除已同步到各個節點的文件。

(2)腳本文件管理

每個腳本具有啓動和停止壓測線程的功能(具有狀態標識),每個參數化文件或附件具有同步到各個節點的功能(同步完成後標識爲同步成功)。

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

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

壓測模式    調用模塊    特點    優缺點
腳本調用模式    Apache Commons Exec    相當於通過遠程執行jmeter命令調用腳本,完全依賴於jmeter bin目錄    優點:實現簡單,無需過多編程;
缺點:無法多線程控制,無法開啓echarts監控,完全依賴本地Jmeter終端
引擎調用模式    JMeterEngine    用的是Jmeter壓測內核,通過runTest方法開啓壓測線程,通過stopTest方法結束壓測線程    優點:更加輕量級,多線程控制,支持單獨停止某個腳本的測試,支持echarts監控,支持個性化擴展開發;
缺點:需要依賴更多編程實現
另外支持將腳本添加到任務,用的是框架本身的任務管理,加上cron表達式生成器插件的應用,可以方便的實現腳本的定時任務創建,這樣就能定時執行腳本(這個是LR所不具備的功能,一般可以用於接口的自動化測試):

 (3)測試報告管理

報告生成模式    調用模塊    特點    優缺點
Jmeter Home命令模式    GenerateReport ByScript    相當於通過執行jmeter命令調用報告,完全依賴於jmeter home目錄    優點:實現簡單,無需特別編程,直接調用;
缺點:無法多線程控制,無法多用戶併發生成報告,完全依賴本地Jmeter_Home目錄的配置
Web進程多線程模式    GenerateReportLocal    採用本地web進程來實現CSV報告文件轉化成html模板報告    優點:更加輕量級,多線程控制,使用更加輕便,配置簡單(不依賴於Jmeter Home的配置);
缺點:需要依賴更多編程實現
默認執行腳本過程中,生成了CSV報告,通過【生成報告】按鈕,觸發將csv報告轉換成html DashBoard(這一步也是通過Commons Exec調度jmeter命令完成),展示效果如下:

除了測試報告,還支持調試報告(顯示接口請求信息,類似於Jmeter的查看結果樹) ,原理是調用xls模板將JTL結果轉爲html報告(區別於測試報告是將CSV結果轉爲html報告),展示效果如下:

(4)分佈式節點管理

分佈式節點管理通過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";


 另外可以將Grafana和InfluxDB及一鍵啓動腳本與性能壓測平臺一起部署,實現在部署層面上進行集成和無縫對接使用。

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

(6)線程組管理

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

(7)壓測節點監控

既然有了分佈式節點管理,那邊我們也可以做到對節點的分佈式監控,在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{
                        if (StressTestUtils.ENABLE.equals(monitorStatus))
                            execStr = "sh "+StressTestUtils.getJmeterHome()+"/telegraf/startUp.sh "+slave.getSlaveName();
                        else
                            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();
            }else{
                //禁用監控
                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執行失敗!請先嚐試在節點機命令執行");
            }
 
            //更新數據庫
            slave.setMonitorStatus(monitorStatus);
            update(slave);
        }
    }
       從代碼我們也可以看出,我們將telegraf啓動和配置文件都放置在jmeter節點的根目錄下,這樣能方便遠程SSH調用,同時我們將監控平臺的IP和節點名稱也發送過去,並更新到telegraf.conf文件中,這樣啓動的telegraf進程就會將監控數據發回到我們的influxdb,並通過grafana監控到。以下是監控的效果:

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

(8)平臺日誌監控

       說是日誌監控,目前只是實現了日誌的前臺展現功能,將info、debug、warn、error不同的日誌級別用顏色標識。獲取日誌的方式是開通websocket通道,用spring-boot推送實時日誌到前端頁面顯示,這種方式其實也沒什麼特別的,在網上能找到大把的實現方式,但其作用還是挺大的,平臺運行或是壓測過程中如果出現異常,直接在前臺跟蹤日誌即可,沒必要再跑到後臺服務器上用tail命令跟蹤了,易用性變強了。

更正說明:寫這篇文章的時候,阿里雲的PTS剛剛能支持原生jmeter(但前提是有項目支持你花這錢),也就是能支持websocket的壓測,具體使用說明他們也提供了教程:https://help.aliyun.com/document_detail/93627.html?spm=5176.7946858.1219570.3.4ced572dQgCraE

版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!https://blog.csdn.net/smooth00/article/details/83380879


————————————————
版權聲明:本文爲CSDN博主「smooth-z」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/smooth00/article/details/83380879

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