在實際的業務場景中,壓測是必不可少的一環,無論是對服務器、數據庫、網絡等性能瓶頸的評估,還是如瀏覽、下單、支付等重要流量節點的業務連續性保障,亦或是搬站上雲整體業務穩定性的預估,這些都需要性能壓測來幫助你建立對系統和業務的完整認知。根據 Google 的統計,如果網站打開慢每 500 毫秒,用戶訪問量將下降 20%。根據 Amazon 統計,每慢 100 毫秒,交易額下降 1%。這些事件和統計數據為大傢敲響瞭警鐘,也客觀說明瞭性能壓測對於企業應用的重要性。壓測是通過模擬用戶行為對業務系統發起請求,測算出系統的承載能力,並對系統做一次全面的體檢,壓測後可根據壓測表現優化系統瓶頸,防止出現線上故障。業界常見的壓測軟件 JMeter 和 PTS目前 JMeter 是性能壓測領域應用最廣泛的開源軟件。對於場景簡單,要求測試並發量不高的情況下,JMeter 本地測試就能滿足需求。但隨著互聯網用戶的增加,對系統承載更大並發的需求日漸提升,而單臺 JMeter 施壓機的施壓能力有一定上限,所以需要使用多臺施壓機,以提高 JMeter 的施壓能力,這就要使用到 JMeter 的分佈式施壓功能。但 JMeter 的分佈式壓測前置準備較多,需要註意以下幾點:施壓機的防火墻已關閉或打開瞭正確的端口。為 RMI 設置瞭 SSL 或禁用瞭它。所有施壓機都在同一個子網上。如果使用 192.xxx或10.xxx IP 地址,則服務器位於同一子網中。所有施壓機上使用相同版本的 JMeter 和 Java。所有施壓機都已經拷貝瞭切分好的 CSV 數據文件、依賴 jar 包等。已配置好監控數據的收集。由此可見 JMeter 的分佈式壓測需要自己協調各資源,前置準備比較麻煩,對實施壓測的人員來說壓測效率低。PTS 是阿裡雲研發的性能測試工具,最初主要為瞭模擬雙十一流量洪峰,如今已走過十個年頭,在場景編排、壓測執行、壓測監控分析、報告總結等各方面能力相對完善,可提供百萬並發、千萬 TPS 流量發起能力,並且還能完全兼容 JMeter,可天然彌補 JMeter 在性能壓測中的劣勢。對使用 JMerer 無法繞過集群問題的用戶是一個很好的選擇。PTS 的 JMeter 壓測極大的簡化瞭 JMeter 分佈式壓測流程,同時也降低瞭壓測過程中對施壓機的維護成本。使用 PTS 的 JMeter 壓測,用戶隻需要在控制臺配置需要使用的機器數,無須用戶提前準備多臺已安裝相同 Java 和 JMeter 版本的施壓機。同時無須用戶根據施壓機數量去切分 CSV 參數文件;壓測結束後,PTS 會將監控數據匯總產生一個詳細的壓測報告供用戶查閱。相比於直接在命令行執行 JMeter 腳本來說,PTS 使用更加方便,可按需提供海量的施壓能力,並且能提供簡潔直觀的監控和報告。如何發起 PTS 的 JMeter 壓測和所有壓測的核心步驟一樣,使用 PTS 的 JMeter 壓測,也主要集中在創建場景、壓測場景和查看報告三個步驟中。1、創建場景:PTS 的 JMeter 壓測以場景為核心,壓測對象為一個場景,場景中包括JMeter(原生)腳本、JMeter 依賴(一系列依賴 jar 包和一系列 properties 配置)、及一些壓測配置(PTS 壓測的配置,例如公網/VPC 壓測、並發量、引擎數量、壓測時長等)。2、壓測場景:對場景的操作分為兩方面,一是對場景配置的增刪改查,二是對場景的壓測和調試。3、生成報告:每次對場景壓測都會生成一個壓測任務,同時生成一個報告,其中包括壓測的關鍵指標,如 TPS、RT、成功率等,可輔助用戶排查系統性能瓶頸。此外,PTS 默認將報告保存 30 天,可以隨時查看歷史報告,並且提供導出 PDF 格式的報告。在壓測領域,隨著壓測需求日益多樣化,更多用戶希望將雲上的壓測能力繼承到自己的系統,或者根據自己的業務系統,編排自定義的壓測平臺,從而實現自動化定制化壓測需求。所以,為瞭方便用戶便捷調度 PTS 百萬並發的能力,PTS 開通瞭 JMeter 的 OpenAPI,提供瞭如下幾類壓測的核心功能:編輯場景、調試場景、壓測場景、查看運行時數據、查看報告。通過集成 OpenAPI,客戶可以更加方便的在自己的業務場景實現 PTS 百萬級並發壓測的能力,實現場景的增、刪、改、查等各種操作,一鍵啟動壓測,並在壓測過程中,隨時停止壓測。同時生成的壓測報告中,除瞭JMeter 原生的日志外,還有 PTS 針對某個采樣器的成功率、TPS、RT 指標的聚合數據。另外還可以對報告進行查看報告列表、JMeter 原生日志以及 PTS 對 JMeter 采樣器壓測指標的聚合數據等功能。那麼還等什麼呢?來,試著用 PTS 中 JMeter 的 OpenAPI 寫一個屬於你的百萬級並發壓測能力的壓測平臺吧!附錄:具體步驟如下:引入 pom 依賴<!–創建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.10</version>
</dependency>
<!–阿裡雲核心庫。–>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.2</version>
</dependency>復制下列代碼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);
// 設置場景並發,可設置為100萬
scene.setConcurrency(1000000);
// 設置引擎數量 說明:一臺引擎最多能發500並發,最少1並發所以此處能設置的引擎數為[2,1000],另外引擎數量越多消耗vum越快
scene.setAgentCount(2000);
// 設置壓測持續時間 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;
}
}填寫自己的 ak/sk在上述代碼的 getClient 中填寫正確的 ak/sk點擊啟動點擊 main 方法啟動原文鏈接:https://developer.aliyun.com/article/858353?utm_content=g_1000319675本文為阿裡雲原創內容,未經允許不得轉載。