1 前言
jmeter是性能壓測領域應用最廣泛開源軟體,提供了非常好的擴充能力,通過社群支援非常多類型的壓測,但是jmeter的分布式壓測、監控等方面的能力還有待提高。而PTS(
Performance Testing Service,性能測試)能夠提供全國多地域、大規模分布式施壓能力、全面的壓測監控能力、壓測分析能力,彌補了jmeter在性能壓測中的劣勢。是以PTS将jmeter和PTS的能力結合,各取所長,并開放了PTS的JMeter OpenAPI,友善使用者直接通過引入pom的方式編碼調用API。本文主要介紹如何使用 PTS的JMeter OpenAPI搭建一個壓測平台,實作直接使用PTS分布式能力運作jmeter腳本進行壓測。其中包含OpenAPI種類和實作的功能,以及如何使用OpenAPI。并附了一份詳細的使用教程,基本可以實作填空式程式設計。
1.1 場景
pts的jmeter壓測以場景為核心,壓測對象為一個場景,場景中包括jmeter腳本、jmeter依賴、及一些壓測配置,每次壓測會生成一個壓測任務同時生成一個報告。對場景的操作分為兩方面,一是對場景配置的增删改查,二是對場景的壓測和調試。

1.2 jmx腳本
即jmeter的原生腳本,可直接在jmeter的GUI頁面中配置導出。
1.3 環境
環境為jmeter壓測的依賴,一個環境包括一系列依賴jar包和一系列properties配置。場景可以綁定某一個環境,以便在壓測過程中引用環境中jar包,而不用每次配置場景都上傳依賴jar包。對環境的操作主要是增删改查。
1.4 其他壓測配置
其他配置主要是PTS壓測的配置,例如公網/VPC壓測、并發量、引擎數量、壓測時長等。
2 依賴
最新版本可以在
maven公網位址查詢。
<!--建立pts場景需要的實體類,如果隻使用jmeter壓測則不需要引入-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>pts-api-entity</artifactId>
<version>1.0.1</version>
</dependency>
<!--PTS Java SDK依賴。-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>pts20201020</artifactId>
<version>1.8.2</version>
<exclusions>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
<version>1.1.14</version>
</dependency>
<!--阿裡雲核心庫。-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.2</version>
</dependency>
3 功能
PTS壓測以場景為中心,借助PTS能力壓測的jmeter也不例外。圍繞jmeter場景,OpenAPI提供了如下幾類功能:編輯場景、調試場景、壓測場景、檢視運作時資料、檢視報告。
- 編輯場景:實作場景的增、删、改、查各種操作。
- 調試場景:實作場景的壓測前調試。調試過程中可以通過壓測資料接口擷取調試結果資料,判斷待壓測API是否通,若不通過可提前停止調試。
- 壓測場景:實作場景的啟動、停止。調試成功後,可通過啟動壓測接口,實作一鍵啟動壓測,并在壓測過程中,随時停止壓測。
- 檢視運作時資料:擷取壓測和調試過程中的實時資料。場景啟動壓測後,pts後端會5s上傳一次資料,這個過程中可以實時看到壓測執行情況,包括采樣器實時采樣的情況、壓測任務所處階段、執行壓測引擎、實時消耗的vum等。
- 檢視報告:查詢壓測最終報告資料。場景每次壓測都會生成一個壓測任務,同時生成一個壓測任務對應的壓測報告,壓測報告中除了jmeter原生的日志外,還有pts針對某個采樣器的成功率、TPS、RT名額的聚合資料。對報告的操作主要包括檢視報告清單、檢視jmeter原生日志以及pts對jmeter采樣器壓測名額的聚合資料。
4 使用
// 使用OpenAPI之前都需要建構一個client
Config config = new Config();
config.setAccessKeyId(accessKeyId);
config.setAccessKeySecret(accessKeySecret);
Client client = new Client(config);
4.1 編輯場景
建立/修改場景
SaveOpenJMeterSceneRequest request = new SaveOpenJMeterSceneRequest();
// 定義場景
SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterScene scene = new SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterScene();
// 設定引擎數量
scene.setAgentCount(2);
// 設定場景名
scene.setSceneName("test");
// 設定檔案清單,包括jmeter腳本、jmeter壓測依賴jar包、配置額度資料檔案等
List<SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList> fileList = new ArrayList<>();
// 設定檔案的屬性 需要設定檔案的名稱和檔案公網可通路的oss位址
SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList file = new SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList();
file.setFileName("json.jar");
file.setFileOssAddress("https://xx.oss-cn-shanghai.aliyuncs.com/json.jar");
fileList.add(file);
SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList testFile = new SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList();
testFile.setFileName("baidu.jmx");
testFile.setFileOssAddress("https://xx.oss-cn-shanghai.aliyuncs.com/baidu.jmx");
fileList.add(testFile);
scene.setFileList(fileList);
// 設定場景并發
scene.setConcurrency(1000);
// 設定壓測持續時間
scene.setDuration(600);
// 設定測試檔案的名稱,這個檔案需包括在檔案清單中
scene.setTestFile("baidu.jmx");
// 若依賴了jmeter環境,課設定jmeter環境
scene.setEnviromentId("UKS1LH");
// 建立場景不需要設定id,修改場景需要設定id
scene.setSceneId("6FZQUTH");
request.setOpenJMeterScene(scene);
SaveOpenJMeterSceneResponse response = client.saveOpenJMeterScene(request);
查詢場景
// 擷取場景詳細資訊
GetOpenJMeterSceneRequest request = new GetOpenJMeterSceneRequest();
request.setSceneId("6FZQUTH");
GetOpenJMeterSceneResponse response = client.getOpenJMeterScene(request);
删除場景
RemoveOpenJMeterSceneRequest request = new RemoveOpenJMeterSceneRequest();
request.setSceneId("6FZQUTH");
RemoveOpenJMeterSceneResponse response = client.removeOpenJMeterScene(request);
4.2 調試場景
開始調試
StartDebuggingJMeterSceneRequest request = new StartDebuggingJMeterSceneRequest();
request.setSceneId("6FZQUTH");
StartDebuggingJMeterSceneResponse response = client.startDebuggingJMeterScene(request);
停止調試
StopDebuggingJMeterSceneRequest request = new StopDebuggingJMeterSceneRequest();
request.setSceneId("6FZQUTH");
StopDebuggingJMeterSceneResponse response = client.stopDebuggingJMeterScene(request);
4.3 壓測場景
開始壓測
StartTestingJMeterSceneRequest request = new StartTestingJMeterSceneRequest();
request.setSceneId("6FZQUTH");
StartTestingJMeterSceneResponse response = client.startTestingJMeterScene(request);
停止壓測
StopTestingJMeterSceneRequest request = new StopTestingJMeterSceneRequest();
request.setSceneId("6FZQUTH");
StopTestingJMeterSceneResponse response = client.stopTestingJMeterScene(request);
4.4 檢視運作時資料
GetJMeterSceneRunningDataRequest request = new GetJMeterSceneRunningDataRequest();
request.setSceneId("6FZQUTH");
GetJMeterSceneRunningDataResponse response = client.getJMeterSceneRunningData(request);
4.5 檢視報告
報告清單
ListJMeterReportsRequest request = new ListJMeterReportsRequest();
// 分頁設定
request.setPageNumber(1);
request.setPageSize(10);
// 查詢條件設定
request.setSceneId("DYYPZIH");
request.setReportId("FLCAE382");
request.setKeyword("test");
request.setBeginTime(1637485804233L);
request.setEndTime(1637485804300L);
ListJMeterReportsResponse response = client.listJMeterReports(request);
采樣器聚合資料
GetJMeterSampleMetricsRequest request = new GetJMeterSampleMetricsRequest();
// 設定報告id
request.setReportId("FLCAE382");
// 設定采樣器的索引,為空或者<0時,指派為-1傳回全場景
request.setSamplerId(0);
request.setBeginTime(1637485804233L);
request.setEndTime(1637485804300L);
GetJMeterSampleMetricsResponse response = client.getJMeterSampleMetrics(request);
采樣器采樣日志
GetJMeterSamplingLogsRequest request = new GetJMeterSamplingLogsRequest();
// 分頁設定
request.setPageNumber(1);
request.setPageSize(10);
// 條件設定
request.setReportId("FLCAE382");
request.setBeginTime(1637224899406L);
request.setEndTime(1637224976000L);
// 關鍵字
request.setKeyword("test");
// 采樣器索引
request.setSamplerId(0);
// 結果是否成功
request.setSuccess(true);
// 線程
request.setThread("main");
// 響應碼
request.setResponseCode("200");
// 最小響應時間
request.setMinRT(0);
// 最大響應時間
request.setMaxRT(1000);
// 壓測引擎編号
request.setAgentId(14201002L);
GetJMeterSamplingLogsResponse response = client.getJMeterSamplingLogs(request);
壓測機器運作日志
GetJMeterLogsRequest request = new GetJMeterLogsRequest();
// 分頁設定
request.setPageNumber(1);
request.setPageSize(10);
// 查詢的壓測引擎索引
request.setAgentIndex(0);
request.setReportId("FLCAE382");
GetJMeterLogsResponse response = client.getJMeterLogs(request);
5 一鍵啟動
壓測的核心步驟:建立場景->壓測場景->檢視報告,以下代碼實作了使用SDK一鍵啟動壓測場景,并且在完成壓測後檢視壓測報告。具體步驟如下:
- 引入pom依賴
- 複制下列代碼
- 填寫自己的ak/sk
- 點選啟動
import com.aliyun.pts20201020.Client;
import com.aliyun.pts20201020.models.*;
import com.aliyun.teaopenapi.models.Config;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class StartingDemo {
public static void main(String[] args) throws Exception {
Client client = getClient();
// 建立場景
String sceneId = createScene(client);
// 啟動場景
String reportId = startTesting(client, sceneId);
// 最多等待次數
int count = 0;
// 查詢是否已生成報告
while (!hasReport(client, reportId) && count++ < 20) {
// 若報告還未生成,則等待(30s)一段時間再查詢
// 根據壓測時間酌情等待
Thread.sleep(30 * 1000);
}
// 檢視報告
getJMeterReport(client, reportId);
}
private static boolean hasReport(Client client, String reportId) throws Exception {
ListJMeterReportsRequest request = new ListJMeterReportsRequest();
// 分頁設定
request.setPageNumber(1);
request.setPageSize(1);
// 查詢條件設定
request.setReportId(reportId);
ListJMeterReportsResponse response = client.listJMeterReports(request);
return response.getBody().getReports().size() > 0;
}
private static void getJMeterReport(Client client, String reportId) throws Exception {
// 檢視機器日志
GetJMeterLogsResponse getJMeterLogsResponse = getJMeterLogs(client, reportId);
List<Map<String, ?>> logs = getJMeterLogsResponse.getBody().getLogs();
// 檢視采樣器聚合資料
GetJMeterSampleMetricsResponse getJMeterSampleMetrics = getJMeterSampleMetrics(client, reportId);
List<String> sampleMetricList = getJMeterSampleMetrics.getBody().getSampleMetricList();
// 檢視采樣日志
GetJMeterSamplingLogsResponse getJMeterSamplingLogs = getJMeterSamplingLogs(client, reportId);
List<String> sampleResults = getJMeterSamplingLogs.getBody().getSampleResults();
}
private static GetJMeterSamplingLogsResponse getJMeterSamplingLogs(Client client, String reportId) throws Exception {
GetJMeterSamplingLogsRequest request = new GetJMeterSamplingLogsRequest();
// 分頁設定
request.setPageNumber(1);
request.setPageSize(10);
// 條件設定
request.setReportId(reportId);
GetJMeterSamplingLogsResponse response = client.getJMeterSamplingLogs(request);
return response;
}
private static GetJMeterSampleMetricsResponse getJMeterSampleMetrics(Client client, String reportId) throws Exception {
GetJMeterSampleMetricsRequest request = new GetJMeterSampleMetricsRequest();
// 設定報告id
request.setReportId(reportId);
GetJMeterSampleMetricsResponse response = client.getJMeterSampleMetrics(request);
return response;
}
private static GetJMeterLogsResponse getJMeterLogs(Client client, String reportId) throws Exception {
GetJMeterLogsRequest request = new GetJMeterLogsRequest();
// 分頁設定
request.setPageNumber(1);
request.setPageSize(10);
// 查詢的壓測引擎索引
request.setReportId(reportId);
GetJMeterLogsResponse response = client.getJMeterLogs(request);
return response;
}
private static String startTesting(Client client, String sceneId) throws Exception {
StartTestingJMeterSceneResponse startTestingSceneResponse = startTestingScene(client, sceneId);
String reportId = startTestingSceneResponse.getBody().getReportId();
return reportId;
}
private static StartTestingJMeterSceneResponse startTestingScene(Client client, String sceneId) throws Exception {
StartTestingJMeterSceneRequest request = new StartTestingJMeterSceneRequest();
request.setSceneId(sceneId);
StartTestingJMeterSceneResponse response = client.startTestingJMeterScene(request);
return response;
}
private static String createScene(Client client) throws Exception {
SaveOpenJMeterSceneRequest request = new SaveOpenJMeterSceneRequest();
// 定義場景
SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterScene scene = new SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterScene();
// 設定場景名
scene.setSceneName("test");
// 設定檔案清單,包括jmeter腳本、jmeter壓測依賴jar包、配置額度資料檔案等
List<SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList> fileList = new ArrayList<SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList>();
// 設定檔案的屬性 需要設定檔案的名稱和檔案公網可通路的oss位址
SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList testFile = new SaveOpenJMeterSceneRequest.SaveOpenJMeterSceneRequestOpenJMeterSceneFileList();
testFile.setFileName("baidu.jmx");
testFile.setFileOssAddress("https://pts-openapi-test.oss-cn-shanghai.aliyuncs.com/baidu.jmx");
fileList.add(testFile);
scene.setFileList(fileList);
// 設定場景并發
scene.setConcurrency(1000);
// 設定引擎數量 說明:一台引擎最多能發500并發,最少1并發是以此處能設定的引擎數為[2,1000],另外引擎數量越多消耗vum越快
scene.setAgentCount(2);
// 設定壓測持續時間 60s
scene.setDuration(60);
// 設定測試檔案的名稱,這個檔案需包括在檔案清單中
scene.setTestFile("baidu.jmx");
request.setOpenJMeterScene(scene);
SaveOpenJMeterSceneResponse response = client.saveOpenJMeterScene(request);
return response.getBody().getSceneId();
}
private static Client getClient() throws Exception {
// 填寫自己的AK/SK
String accessKeyId = "ak";
String accessKeySecret = "sk";
Config config = new Config();
config.setAccessKeyId(accessKeyId);
config.setAccessKeySecret(accessKeySecret);
Client client = new Client(config);
return client;
}
}