你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

适用于 JavaScript 的 Azure 负载测试客户端库 - 版本 1.0.0

Azure 负载测试向用户提供 JavaScript 中的客户端库,用户可以通过该库与 Azure 负载测试服务进行本机交互。 Azure 负载测试是一项完全托管的负载测试服务,可用于生成大规模负载。 该服务可以模拟应用程序的流量,且无需其托管位置。 开发人员、测试人员和质量保证 (QA) 工程师可以使用该服务来优化应用程序性能、可缩放性或容量。

请严重依赖 REST 客户端文档 来使用此库

文档

提供了各种文档来帮助你入门

入门

目前支持的环境

  • Node.js版本 14.x.x 或更高版本

先决条件

安装 @azure-rest/load-testing

使用 npm安装适用于 JavaScript 的 AzureLoadTesting 客户端 REST 客户端库:

npm install @azure-rest/load-testing

创建客户端并对其进行身份验证AzureLoadTesting

若要使用 Azure Active Directory (AAD) 令牌凭据,请提供从 @azure/标识 库获取的所需凭据类型的实例。

若要使用 AAD 进行身份验证,必须先 npm 安装 @azure/identity

设置后,可以选择要使用的@azure/identity凭据类型。 例如, DefaultAzureCredential 可用于对客户端进行身份验证。

将 AAD 应用程序的客户端 ID、租户 ID 和客户端密码的值设置为环境变量:AZURE_CLIENT_ID、AZURE_TENANT_ID AZURE_CLIENT_SECRET

import AzureLoadTesting, { AzureLoadTestingClient } from "@azure-rest/load-testing";
import { DefaultAzureCredential } from "@azure/identity";

const Client: AzureLoadTestingClient = AzureLoadTesting(Endpoint, new DefaultAzureCredential());

关键概念

以下组件构成 Azure 负载测试服务。 使用适用于 JavaScript 的 Azure 负载测试客户端库,可以使用专用客户端对象来与其中每个组件进行交互。

测试

测试指定测试脚本和配置设置用于运行负载测试。 可以在 Azure 负载测试资源中创建一个或多个测试。

应用组件

为 Azure 托管应用程序运行负载测试时,可以监视不同 Azure 应用程序组件的资源指标(服务器端指标)。 负载测试运行时以及测试完成后,可以在 Azure 负载测试仪表板中监视和分析资源指标。

指标

在负载测试期间,Azure 负载测试收集有关测试执行的指标。 有两种类型的指标:

  1. 客户端指标会显示测试引擎报告的详细信息。 这些指标包括虚拟用户数、请求响应时间、失败的请求数或每秒请求数。

  2. 服务器端指标适用于 Azure 托管应用程序并显示有关 Azure 应用程序组件的信息。 指标可以是数据库读取次数、HTTP 响应类型或容器资源消耗量。

测试引擎

测试引擎是运行 Apache JMeter 测试脚本的计算基础结构。 可以通过配置测试引擎的数量来横向扩展负载测试。 测试脚本跨指定数量的测试引擎并行运行。

测试运行

测试运行表示负载测试的一次执行。 它收集与运行 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

示例

创建负载测试

import { AzureLoadTestingClient } from "@azure-rest/load-testing";
import AzureLoadTesting from "@azure-rest/load-testing";
import { DefaultAzureCredential } from "@azure/identity";

var TEST_ID = "some-test-id";
var DISPLAY_NAME = "my-load-test";

const client: AzureLoadTestingClient = AzureLoadTesting("<Endpoint>", new DefaultAzureCredential());

await client.path("/tests/{testId}", TEST_ID).patch({
  contentType: "application/merge-patch+json",
  body: {
    displayName: DISPLAY_NAME,
    description: "",
    loadTestConfiguration: {
      engineInstances: 1,
      splitAllCSVs: false,
    },
    secrets: {},
    environmentVariables: {},
    passFailCriteria: { passFailMetrics: {} },
  },
});

将 .jmx 文件上传到测试

import { AzureLoadTestingClient, getLongRunningPoller, isUnexpected } from "@azure-rest/load-testing";
import AzureLoadTesting from "@azure-rest/load-testing";
import { AbortController } from "@azure/abort-controller";
import { DefaultAzureCredential } from "@azure/identity";
import { createReadStream } from "fs";

const client: AzureLoadTestingClient = AzureLoadTesting("<Endpoint>", new DefaultAzureCredential());

var TEST_ID = "some-test-id";
const readStream = createReadStream("./sample.jmx");

const fileUploadResult = await client
  .path("/tests/{testId}/files/{fileName}", TEST_ID, "sample.jmx")
  .put({
    contentType: "application/octet-stream",
    body: readStream,
  });

if (isUnexpected(fileUploadResult)) {
  throw fileUploadResult.body.error;
}

let fileValidateResult;
const fileValidatePoller = await getLongRunningPoller(client, fileUploadResult);
try{
fileValidateResult = await fileValidatePoller.pollUntilDone({
  abortSignal: AbortController.timeout(120*1000), // timeout of 120 seconds
});} catch (ex: any) {
new Error("Error in polling file Validation" + ex.message); //polling timed out
}

if (fileValidatePoller.getOperationState().status != "succeeded" && fileValidateResult)
  throw new Error(
    "There is some issue in validation, please make sure uploaded file is a valid JMX." +
      fileValidateResult.body.validationFailureDetails
  );

运行测试和提取指标

import { AzureLoadTestingClient, getLongRunningPoller, isUnexpected } from "@azure-rest/load-testing";
import AzureLoadTesting from "@azure-rest/load-testing";
import { DefaultAzureCredential } from "@azure/identity";
import { AbortController } from "@azure/abort-controller";

const client: AzureLoadTestingClient = AzureLoadTesting("<Endpoint>", new DefaultAzureCredential());

var TEST_ID = "some-test-id";
var DISPLAY_NAME = "my-load-test";
var TEST_RUN_ID = "some-test-run-id";

// Creating/Updating the test run
const testRunCreationResult = await client.path("/test-runs/{testRunId}", TEST_RUN_ID).patch({
  contentType: "application/merge-patch+json",
  body: {
    testId: TEST_ID,
    displayName: DISPLAY_NAME,
  },
});

if (isUnexpected(testRunCreationResult)) {
  throw testRunCreationResult.body.error;
}

if (testRunCreationResult.body.testRunId === undefined)
  throw new Error("Test Run ID returned as undefined.");

const testRunPoller = await getLongRunningPoller(client, testRunCreationResult);
  let testRunResult;

  try {
    testRunResult = await testRunPoller.pollUntilDone({
      abortSignal: AbortController.timeout(60000), // timeout of 60 seconds
    });
  } catch (ex: any) {
    new Error("Error in polling test run completion" + ex.message); //polling timed out
  }

  if (testRunPoller.getOperationState().status != "succeeded")
    throw new Error("There is some issue in running the test, Error Response : " + testRunResult);

  if (testRunResult) {
    let testRunStarttime = testRunResult.body.startDateTime;
    let testRunEndTime = testRunResult.body.endDateTime;

    // get list of all metric namespaces and pick the first one
    const metricNamespaces = await client
      .path("/test-runs/{testRunId}/metric-namespaces", TEST_RUN_ID)
      .get();

    if (isUnexpected(metricNamespaces)) {
      throw metricNamespaces.body.error;
    }

    const metricNamespace = metricNamespaces.body.value[0];

    if (metricNamespace.name === undefined) {
      throw "No Metric Namespace name is defined.";
    }

    // get list of all metric definitions and pick the first one
    const metricDefinitions = await client
      .path("/test-runs/{testRunId}/metric-definitions", TEST_RUN_ID)
      .get({
        queryParameters: {
          metricNamespace: metricNamespace.name,
        },
      });

    if (isUnexpected(metricDefinitions)) {
      throw metricDefinitions.body.error;
    }

    const metricDefinition = metricDefinitions.body.value[0];

    if (metricDefinition.name === undefined) {
      throw "No Metric Namespace name is defined.";
    }

    // fetch client metrics using metric namespace and metric name
    const metricsResult = await client.path("/test-runs/{testRunId}/metrics", TEST_RUN_ID).post({
      queryParameters: {
        metricname: metricDefinition.name,
        metricNamespace: metricNamespace.name,
        timespan: testRunStarttime + "/" + testRunEndTime,
      },
    });

    console.log(metricsResult);
    console.log(testRunResult);
}

疑难解答

日志记录

启用日志记录可能有助于发现有关故障的有用信息。 若要查看 HTTP 请求和响应的日志,请将 AZURE_LOG_LEVEL 环境变量设置为 info。 或者,可以在运行时通过调用 @azure/logger 中的 setLogLevel 来启用日志记录:

import { setLogLevel } from "@azure/logger";

setLogLevel("info");

有关如何启用日志的更详细说明,请查看 @azure/logger 包文档

后续步骤

可在 SDK 的 GitHub 存储库中获取 Azure 加载测试 JavaScript SDK 示例。 这些示例为经常遇到的其他方案提供了示例代码。

请参阅 Azure 负载测试示例

供稿

有关参与此存储库的详细信息,请参阅 参与指南

  1. 分叉它
  2. 创建功能分支 (git checkout -b my-new-feature)
  3. () git commit -am 'Add some feature' 提交更改
  4. 推送到分支 (git push origin my-new-feature)
  5. 创建新的拉取请求