你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
适用于 Java 的 Azure 负载测试客户端库 - 版本 1.0.7
Azure 负载测试向用户提供 Java 中的客户端库,用户可以通过该库与 Azure 负载测试服务进行本机交互。 Azure 负载测试是一项完全托管的负载测试服务,可用于生成大规模负载。 该服务可以模拟应用程序的流量,且无需其托管位置。 开发人员、测试人员和质量保证 (QA) 工程师可以使用它来优化应用程序性能、可伸缩性或容量
此包包含 Microsoft Azure 开发人员负载测试客户端库。
文档
提供了各种文档来帮助你入门
入门
先决条件
- Java 开发工具包 (版本 8 或更高版本的 JDK)
- Azure 订阅
- Azure 负载测试资源
将包添加到产品
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-developer-loadtesting</artifactId>
<version>1.0.7</version>
</dependency>
Authentication
Azure 标识 包提供用于对客户端进行身份验证的默认实现。
默认情况下,Azure Active Directory 令牌身份验证依赖于以下环境变量的正确配置。
AZURE_CLIENT_ID
用于 Azure 客户端 ID。AZURE_TENANT_ID
用于 Azure 租户 ID。AZURE_CLIENT_SECRET
或AZURE_CLIENT_CERTIFICATE_PATH
,用于客户端密码或客户端证书。
此外,可以通过环境变量 AZURE_SUBSCRIPTION_ID
配置 Azure 订阅 ID。
使用上述配置, azure
可以通过以下代码对客户端进行身份验证:
// ensure the user, service principal or managed identity used has Loadtesting Contributor role for the resource
TokenCredential credential = new DefaultAzureCredentialBuilder()
.build();
// create client using DefaultAzureCredential
LoadTestAdministrationClient adminClient = new LoadTestAdministrationClientBuilder()
.credential(credential)
.endpoint("<Enter Azure Load Testing Data-Plane URL>")
.buildClient();
LoadTestRunClient testRunClient = new LoadTestRunClientBuilder()
.credential(credential)
.endpoint("<Enter Azure Load Testing Data-Plane URL>")
.buildClient();
RequestOptions reqOpts = new RequestOptions()
.addQueryParam("orderBy", "lastModifiedDateTime")
.addQueryParam("maxPageSize", "10");
adminClient.listTests(reqOpts);
reqOpts = new RequestOptions()
.addQueryParam("orderBy", "lastModifiedDateTime")
.addQueryParam("status", "EXECUTING,DONE")
.addQueryParam("maxPageSize", "10");
testRunClient.listTestRuns(reqOpts);
关键概念
以下组件构成 Azure 负载测试服务。 使用适用于 Java 的 Azure 负载测试客户端库,可以使用客户端与其中每个组件进行交互。 有两个顶级客户端,它们是库main入口点
LoadTestingClient
LoadTestingAsyncClient
这两个客户端中具有类似的方法,但异步客户端中的方法也是异步的。
顶级客户端有两个子客户端
LoadTestAdministration
TestRun
这些子客户端用于管理和使用服务的不同组件。
负载测试管理客户端
子 LoadTestAdministration
客户端用于管理和配置负载测试、应用组件和指标。
测试
测试指定测试脚本和配置设置用于运行负载测试。 可以在 Azure 负载测试资源中创建一个或多个测试。
应用组件
为 Azure 托管应用程序运行负载测试时,可以监视不同 Azure 应用程序组件的资源指标(服务器端指标)。 负载测试运行时以及测试完成后,可以在 Azure 负载测试仪表板中监视和分析资源指标。
指标
在负载测试期间,Azure 负载测试收集有关测试执行的指标。 有两种类型的指标:
客户端指标会显示测试引擎报告的详细信息。 这些指标包括虚拟用户数、请求响应时间、失败的请求数或每秒请求数。
服务器端指标适用于 Azure 托管应用程序并显示有关 Azure 应用程序组件的信息。 指标可以是数据库读取次数、HTTP 响应的类型或容器资源消耗量。
测试运行客户端
子 TestRun
客户端用于启动和停止与负载测试对应的测试运行。 测试运行表示负载测试的一次执行。 它收集与运行 Apache JMeter 脚本关联的日志、负载测试 YAML 配置、要监视的应用组件列表以及测试结果。
Data-Plane 终结点
Azure 负载测试资源的数据平面可使用以下 URL 格式进行寻址:
00000000-0000-0000-0000-000000000000.aaa.cnt-prod.loadtesting.azure.com
第一个 GUID 00000000-0000-0000-0000-000000000000
是用于访问 Azure 负载测试资源的唯一标识符。 接下来 aaa
是资源的 Azure 区域。
数据平面终结点是从控制平面 API 获取的。
示例:1234abcd-12ab-12ab-12ab-123456abcdef.eus.cnt-prod.loadtesting.azure.com
在上面的示例中, eus
表示 Azure 区域 East US
。
示例
创建负载测试
LoadTestAdministrationClient adminClient = new LoadTestAdministrationClientBuilder()
.credential(new DefaultAzureCredentialBuilder().build())
.endpoint("<endpoint>")
.buildClient();
// construct Test object using nested String:Object Maps
Map<String, Object> testMap = new HashMap<String, Object>();
testMap.put("displayName", "Sample Display Name");
testMap.put("description", "Sample Description");
// loadTestConfig describes the number of test engines to generate load
Map<String, Object> loadTestConfigMap = new HashMap<String, Object>();
loadTestConfigMap.put("engineInstances", 1);
testMap.put("loadTestConfiguration", loadTestConfigMap);
// environmentVariables are plain-text data passed to test engines
Map<String, Object> envVarMap = new HashMap<String, Object>();
envVarMap.put("a", "b");
envVarMap.put("x", "y");
testMap.put("environmentVariables", envVarMap);
// secrets are secure data sent using Azure Key Vault
Map<String, Object> secretMap = new HashMap<String, Object>();
Map<String, Object> sampleSecretMap = new HashMap<String, Object>();
sampleSecretMap.put("value", "https://samplevault.vault.azure.net/secrets/samplesecret/f113f91fd4c44a368049849c164db827");
sampleSecretMap.put("type", "AKV_SECRET_URI");
secretMap.put("sampleSecret", sampleSecretMap);
testMap.put("secrets", secretMap);
// passFailCriteria define the conditions to conclude the test as success
Map<String, Object> passFailMap = new HashMap<String, Object>();
Map<String, Object> passFailMetrics = new HashMap<String, Object>();
Map<String, Object> samplePassFailMetric = new HashMap<String, Object>();
samplePassFailMetric.put("clientmetric", "response_time_ms");
samplePassFailMetric.put("aggregate", "percentage");
samplePassFailMetric.put("condition", ">");
samplePassFailMetric.put("value", "20");
samplePassFailMetric.put("action", "continue");
passFailMetrics.put("fefd759d-7fe8-4f83-8b6d-aeebe0f491fe", samplePassFailMetric);
passFailMap.put("passFailMetrics", passFailMetrics);
testMap.put("passFailCriteria", passFailMap);
// convert the object Map to JSON BinaryData
BinaryData test = BinaryData.fromObject(testMap);
// receive response with BinaryData content
Response<BinaryData> testOutResponse = adminClient.createOrUpdateTestWithResponse("test12345", test, null);
System.out.println(testOutResponse.getValue().toString());
将 .jmx 文件上传到负载测试
LoadTestAdministrationClient adminClient = new LoadTestAdministrationClientBuilder()
.credential(new DefaultAzureCredentialBuilder().build())
.endpoint("<endpoint>")
.buildClient();
// extract file contents to BinaryData
BinaryData fileData = BinaryData.fromFile(new File("path/to/file").toPath());
// receive response with BinaryData content
Response<BinaryData> fileUrlOut = adminClient.uploadTestFileWithResponse("test12345", "sample-file.jmx", fileData, null);
System.out.println(fileUrlOut.getValue().toString());
运行负载测试
LoadTestRunClient testRunClient = new LoadTestRunClientBuilder()
.credential(new DefaultAzureCredentialBuilder().build())
.endpoint("<endpoint>")
.buildClient();
// construct Test Run object using nested String:Object Maps
Map<String, Object> testRunMap = new HashMap<String, Object>();
testRunMap.put("testId", "test12345");
testRunMap.put("displayName", "SDK-Created-TestRun");
// convert the object Map to JSON BinaryData
BinaryData testRun = BinaryData.fromObject(testRunMap);
// start test with poller
SyncPoller<BinaryData, BinaryData> poller = testRunClient.beginTestRun("testrun12345", testRun, null);
Duration pollInterval = Duration.ofSeconds(5);
poller = poller.setPollInterval(pollInterval);
// wait for test to reach terminal state
JsonNode testRunJson = null;
String testStatus;
PollResponse<BinaryData> pollResponse = poller.poll();
while (pollResponse.getStatus() == LongRunningOperationStatus.IN_PROGRESS || pollResponse.getStatus() == LongRunningOperationStatus.NOT_STARTED) {
try {
testRunJson = new ObjectMapper().readTree(pollResponse.getValue().toString());
testStatus = testRunJson.get("status").asText();
System.out.println("Test run status: " + testStatus);
} catch (JsonProcessingException e) {
System.out.println("Error processing JSON response");
// handle error condition
}
// wait and check test status every 5 seconds
try {
Thread.sleep(pollInterval.toMillis());
} catch (InterruptedException e) {
// handle interruption
}
pollResponse = poller.poll();
}
poller.waitForCompletion();
BinaryData testRunBinary = poller.getFinalResult();
try {
testRunJson = new ObjectMapper().readTree(testRunBinary.toString());
testStatus = testRunJson.get("status").asText();
} catch (JsonProcessingException e) {
System.out.println("Error processing JSON response");
// handle error condition
}
String startDateTime = testRunJson.get("startDateTime").asText();
String endDateTime = testRunJson.get("endDateTime").asText();
// get list of all metric namespaces and pick the first one
Response<BinaryData> metricNamespacesOut = testRunClient.getMetricNamespacesWithResponse("testrun12345", null);
String metricNamespace = null;
// parse JSON and read first value
try {
JsonNode metricNamespacesJson = new ObjectMapper().readTree(metricNamespacesOut.getValue().toString());
metricNamespace = metricNamespacesJson.get("value").get(0).get("metricNamespaceName").asText();
} catch (JsonProcessingException e) {
System.out.println("Error processing JSON response");
// handle error condition
}
// get list of all metric definitions and pick the first one
Response<BinaryData> metricDefinitionsOut = testRunClient.getMetricDefinitionsWithResponse("testrun12345", metricNamespace, null);
String metricName = null;
// parse JSON and read first value
try {
JsonNode metricDefinitionsJson = new ObjectMapper().readTree(metricDefinitionsOut.getValue().toString());
metricName = metricDefinitionsJson.get("value").get(0).get("name").get("value").asText();
} catch (JsonProcessingException e) {
System.out.println("Error processing JSON response");
// handle error condition
}
// fetch client metrics using metric namespace and metric name
PagedIterable<BinaryData> clientMetricsOut = testRunClient.listMetrics("testrun12345", metricName, metricNamespace, startDateTime + '/' + endDateTime, null);
clientMetricsOut.forEach((clientMetric) -> {
System.out.println(clientMetric.toString());
});
疑难解答
适用于 Java 的 Azure SDK 提供一致的日志记录案例,可帮助排查应用程序错误并加快解决。 生成的日志会在到达终端状态之前捕获应用程序的流,以帮助查找根本问题。 查看 日志记录 Wiki,获取有关启用日志记录的指南。
后续步骤
可在 SDK 的 GitHub 存储库中获取 Azure 加载测试 Java SDK 示例。 这些示例为经常遇到的其他方案提供了示例代码。 请参阅 Azure 负载测试示例。
贡献
有关参与此存储库的详细信息,请参阅 参与指南。
- 分支
- 创建功能分支 (
git checkout -b my-new-feature
) - ()
git commit -am 'Add some feature'
提交更改 - 推送到分支 (
git push origin my-new-feature
) - 创建新的拉取请求