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

使用自定义插件进行 Azure 负载测试

解决方案构想

本文是一种解决方案构想。 如果你希望我们在内容中扩充更多信息,例如潜在用例、备用服务、实现注意事项或定价指南,请通过提供 GitHub 反馈来告知我们。

此解决方案提供了有关如何使用 Azure 负载测试的指导,该负载测试是一项可运行 Apache JMeter 脚本和自定义插件来模拟用户和设备行为的服务。 此解决方案还介绍了如何设计关键绩效指标 (KPI) 以及如何开发仪表板,以便使用 Azure Functions 和 Azure 事件中心监视和分析示例应用程序中的负载测试结果。 本文假定你对 JMeter、其插件和自定义插件以及 Azure Functions 和事件中心都有一定的了解。

体系结构

若要执行负载测试,你需要一个测试计划,这是一组指示 JMeter 在测试期间要执行什么操作的说明。 测试计划可以包含多个测试方案,每个方案都有不同的设置和配置。 例如,你可能有一个方案模拟的单个用户访问 Web 应用程序的情况,而另一个方案模拟的多个用户同时访问同一应用程序的情况。

测试计划可以包含多个测试用例,每个方案都有不同的设置和配置。 在本例中,我们假设有一个设备会在一段时间内报告温度和湿度。 设备会将数据发送到 Azure 中的事件中心。 事件中心会触发一个 Azure 函数,该函数将负责处理数据,然后将数据发送到其他下游服务,例如 Azure SQL 数据库。 Azure 函数是我们要测试的服务。 测试计划旨在模拟设备的行为,并将数据发送到事件中心。

Diagram of a sample architecture for load testing.

下载此体系结构的 Visio 文件

数据流

在本例中,数据流如下:

  1. 模拟设备通过 Azure 负载测试代理将数据发送到事件中心。 可以使用 JMeter 自定义插件来模拟设备的任何行为。 Azure 负载测试代理负责在为任何类型的模拟设备运行自定义插件后将数据发送到事件中心。
  2. 事件中心会触发一个 Azure 函数,该函数将负责处理数据,然后将数据发送到其他下游服务,例如 Azure SQL 数据库和 Azure 数字孪生。
  3. Azure Monitor 服务用于监视 Azure 功能和事件中心。
  4. Azure 负载测试服务会从 Azure Monitor 服务收集数据,然后将其显示在仪表板中。

组件

本例中使用了以下组件:

  • Azure 负载测试:使用 Azure 负载测试可以运行 Apache JMeter 脚本和自定义插件,以便模拟用户和设备行为。 它提供了一个用于管理和运行负载测试的 Web 界面,以及一组可用于自动执行过程的 API。 Azure 负载测试是一项完全托管的服务,这意味着无需担心管理服务器或基础结构的问题。 你可以上传 JMeter 脚本和自定义插件,而 Azure 负载测试将处理其余部分。
  • Azure 事件中心:Azure 事件中心是基于云的事件处理服务,可用于实时收集、处理和分析来自各种源的事件和流数据。 事件中心支持多种协议,包括 AMQP(高级消息队列协议)、HTTPS、Kafka 协议、MQTT(消息队列遥测传输)和基于 WebSocket 的 AMQP。 选择正确的协议取决于多种因素,包括正在处理的数据类型、应用程序的特定要求以及协议本身的功能和限制。
  • Azure Functions:Azure Functions 是一种无服务器计算服务,让你无需显式预配或管理基础结构即可运行代码。 它支持多种编程语言,包括 C#、F#、Java、JavaScript、PowerShell、Python 和 TypeScript。 Azure Functions 可用于处理事件中心以及其他来源(如 Azure 存储 和 Azure Cosmos DB)的事件和流数据。
  • JMeter GUI:JMeter GUI 是一种开源负载测试工具,主要用于测试 Web 应用程序的性能。 它最初是为测试 Web 应用程序而开发的。 不过,它也可用于测试其他类型的应用程序,例如 SOAP 和 REST Web 服务、FTP 服务器和数据库。
  • Azure Monitor:Azure Monitor 为 Azure 资源提供监视和警报功能。 它还让你能够监视应用程序和底层基础结构的性能和运行状况。 Azure Monitor 可用于监视事件中心和 Azure Functions,以及 Azure 存储和 Azure Cosmos DB 等其他 Azure 服务。

方案详细信息

Azure 负载测试让你可以采用现有的 Apache JMeter 脚本,并在任何 Azure 资源上以云规模运行负载测试。

JMeter 让测试人员可以创建并执行负载测试、压力测试和功能测试。 它可以模拟多个用户同时访问 Web 应用程序,让测试人员能够识别潜在的性能瓶颈或在较大负载下可能出现的其他问题。 JMeter 可用于度量各种性能指标,例如响应时间、吞吐量和错误率。

JMeter 使用基于 GUI 的界面,从而允许用户创建测试计划,其中可包括多个测试方案,而每个方案都有不同的设置和配置。 测试人员还可以使用插件或编写自定义代码来对 JMeter 进行自定义,从而扩展其开箱即用范围之外的功能。 这些插件可以帮助我们与使用 AMQP 和 Websocket 等非HTTP 协议的服务协同工作。

虽然 JMeter 为负载测试提供了各种特性和功能,但仍可能存在内置功能未涵盖的特定用例或要求。 通过开发自定义插件,测试人员可以添加新功能或自定义现有功能,以便更好地满足其需求

例如,可以开发自定义插件来模拟特定类型的用户行为或生成更真实的测试数据。 此外,还可以开发自定义插件,以便将 JMeter 与其他工具或系统(例如日志记录和报告工具或持续集成和部署管道)集成。 自定义插件有助于简化测试过程,并更轻松地将负载测试纳入到整个软件开发工作流中。 总的来说,他们允许测试人员根据自己的特定需求来定制 JMeter,并提高负载测试工作的准确性和有效性。

在本例中,我们假设有一个设备会在一段时间内报告温度和湿度。 我们可以使用自定义 JMeter 插件来模拟这一简单行为。 在此处提供的自定义插件的当前实现中,我们使用提供的模板生成随机数据。 但是,插件可以包含任何设备的任何可能的复杂行为。 在本例中,设备会将数据发送到 Azure 中的事件中心。 事件中心会触发一个 Azure 函数,该函数将负责处理数据,然后将数据发送到其他下游服务,例如 Azure SQL 数据库。 Azure 函数是我们要测试的服务。 测试计划旨在模拟设备的行为,并将数据发送到事件中心。

可能的用例

将 Azure 负载测试与自定义插件一起使用可在各种方案中发挥作用,例如:

  • 测试使用 AMQP 和 Websocket 等非 HTTP 协议的应用程序的性能。
  • 测试使用自定义协议的应用程序的性能。
  • 测试使用非 Microsoft SDK 的应用程序的性能。
  • 模拟特定类型的用户或设备行为,或生成更真实的测试数据。

自定义插件

JMeter 中的自定义插件是可以添加到 JMeter 中的软件组件,以扩展其开箱即用范围之外的功能。 用户或非 Microsoft 开发人员可以开发自定义插件,以便为 JMeter 添加新功能、功能或集成。 可使用 Java 编程语言和 JMeter 插件开发工具包 (PDK) 开发自定义插件。 PDK 提供了一组工具和 API,可让创建新插件(包括 GUI 元素、侦听器和采样器)变得更轻松。

自定义插件可为 JMeter 添加各种功能。 它们还可以将 JMeter 与日志记录和报告工具等其他系统集成,或将其他数据源用于测试数据。 总之,自定义插件可让用户扩展 JMeter 以满足其特定需求,并提高负载测试工作的准确性和有效性。

若要在 JMeter 中为事件中心实现自定义采样器,请按照 Azure 负载测试插件中提供的说明进行操作。 实现自定义采样器后,可以在 Azure 负载测试中的 JMeter 测试计划中使用它,就像使用任何其他采样器一样。

可以使用控制线程数实现测试计划,线程组可以控制执行特定方案线程(虚拟用户和设备)数量。 每个线程组都可以针对线程数、增加周期数、循环计数和持续时间进行不同的设置。 线程组可以依次或并行运行,具体取决于测试计划配置和应用程序要求。 你可以将采样器添加到线程组中,设置其参数,并根据需要对其进行配置。 自定义采样器可以成为 JMeter 中的强大工具,可用于模拟内置采样器不支持的复杂方案和请求。

使用自定义插件创建 Apache JMeter 脚本

在本节中,你将创建一个示例 JMeter 测试脚本,以使用事件中心对应用程序进行负载测试。

若要创建示例 JMeter 测试脚本,请执行以下操作:

  1. 在本地计算机上创建 LoadTest.jmx 文件:

    touch LoadTest.jmx
    
  2. 在文本编辑器中打开 LoadTest.jmx,然后将以下代码片段粘贴到文件中。 此脚本模拟了会同时将事件发送到事件中心的 36 个虚拟机的负载测试,需要 10 分钟完成:

    <?xml version="1.0" encoding="UTF-8"?>
    <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.5">
        <hashTree>
        <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
            <stringProp name="TestPlan.comments"></stringProp>
            <boolProp name="TestPlan.functional_mode">false</boolProp>
            <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
            <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
            <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
            <collectionProp name="Arguments.arguments"/>
            </elementProp>
            <stringProp name="TestPlan.user_define_classpath"></stringProp>
        </TestPlan>
        <hashTree>
            <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group" enabled="true">
            <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
            <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
                <boolProp name="LoopController.continue_forever">false</boolProp>
                <intProp name="LoopController.loops">-1</intProp>
            </elementProp>
            <stringProp name="ThreadGroup.num_threads">36</stringProp>
            <stringProp name="ThreadGroup.ramp_time">20</stringProp>
            <boolProp name="ThreadGroup.scheduler">true</boolProp>
            <stringProp name="ThreadGroup.duration">600</stringProp>
            <stringProp name="ThreadGroup.delay"></stringProp>
            <boolProp name="ThreadGroup.same_user_on_next_iteration">false</boolProp>
            </ThreadGroup>
            <hashTree>
            <com.microsoft.eventhubplugin.EventHubPlugin guiclass="com.microsoft.eventhubplugin.EventHubPluginGui" testclass="com.microsoft.eventhubplugin.EventHubPlugin" testname="Azure Event Hubs Sampler" enabled="true">
                <stringProp name="eventHubConnectionVarName">EventHubConnectionString</stringProp>
                <stringProp name="eventHubName">telemetry-data-changed-eh</stringProp>
                <stringProp name="liquidTemplateFileName">StreamingDataTemplate.liquid</stringProp>
            </com.microsoft.eventhubplugin.EventHubPlugin>
            <hashTree/>
            </hashTree>
        </hashTree>
        </hashTree>
    </jmeterTestPlan>
    

    com.microsoft.eventhubplugin.EventHubPluginGuicom.microsoft.eventhubplugin.EventHubPlugin 的实现可从 Azure 示例获取。

  3. 在文件中,将 eventHubConnectionVarName 节点的值设为指定事件中心连接字符串主机的变量名称。 例如,如果希望存储事件中心连接字符串的环境变量为 EventHubConnectionString,请将此变量设为 EventHubConnectionString,然后设置环境变量的值。

    重要

    在运行负载测试脚本之前,请确保已将 EventHubConnectionString 的值设为 Azure 负载测试创建过程的一部分。

  4. 在文件中,将 eventHubName 节点的值设为事件中心名称,例如 telemetry-data-changed-eh

  5. liquidTemplateFileName 节点的值设为包含发送到事件中心的消息的文件。 例如,创建一个名为 StreamingDataTemplate.liquid 的文件,如下所示:

    {
        {% assign numberOfMachines = 36 %}
        {% assign machineId = dataGenerator.randomNaturalNumber | modulo: numberOfMachines %}
        "MachineId": "{{machineId | prepend: '0000000000000000000000000000000000000000' | slice: -27, 27 }}"
        "Temperature": {{dataGenerator.randomInt | modulo: 100 }},
        "Humidity": {{dataGenerator.randomInt | modulo: 100 }}
    }
    

    在此示例中,事件中心消息的有效负载是一个 JSON 对象,其中包含三个属性 MachineIdTemperatureHumidity,其中 MachineId 是随机生成的 ID,长度为 27,而 TemperatureHumidity 是小于 100 的随机整数。 此文件是一种 Liquid 模板语法。 Liquid 模板是一种常用模板化语言,可用于各种 Web 开发框架。 Liquid 模板使开发人员能够创建易于更新和修改的动态内容。 它们允许在事件中心消息中插入变量、条件、循环和其他动态元素。 语法非常简单,有很多在线资源可以帮助你入门。 总之,Liquid 模板为创建动态、可定制的信息提供了一种强大而灵活的方式。

  6. 保存并关闭该文件。

    重要

    不要在 JMeter 脚本的采样器名称中包含任何个人数据。 采样器名称显示在 Azure 负载测试测试结果仪表板中。 可以在 Azure 示例下载 Liquid 模板和 JMeter 脚本文件的示例

使用新插件运行负载测试

当 Azure 负载测试启动负载测试时,它首先会将 JMeter 脚本连同所有其他文件一起部署到测试引擎实例上,然后按照使用 Apache JMeter 插件和 Azure 负载测试自定义负载测试中的指示启动负载测试。 在运行测试之前,请转到参数选项卡,定义EventHubConnectionString,然后提供连接到事件中心的连接字符串。

Screenshot that shows the parameters of the test.

环境的性能测试设置

在任何性能测试中,与生产环境相似的环境都很重要。 在本例中,为了更好地了解系统容量和性能,使用以下环境进行性能测试。

根据示例体系结构,以下服务可用于性能测试:

服务 配置
Eventhub 高级版配有一个处理单元 (PU)。
Azure 函数 具有高级计划 (EP1) 的 Linux - 210 个 ACU、3.5 GB 内存和 1 个 vCPU(相当于 Standard_D1_v2)
区域 美国东部

为任何 Azure 服务(包括事件中心和 Azure Functions)选择合适的服务层级是一个复杂的过程,取决于许多因素。 有关详细信息,请参阅 Azure 事件中心定价Azure Functions 定价

设计用于性能测试的 KPI

在设计用于性能测试的关键绩效指标 (KPI) 之前,需要两项内容:业务要求和系统体系结构。 业务要求会告知要度量的 KPI,例如响应时间、吞吐量或错误率。 系统体系结构告诉你如何测试每个组件(如 Web 服务器、数据库或 API)的性能。 它还有助于选择最佳性能测试策略,例如负载测试、压力测试或耐力测试。

在此示例中,业务要求如下:

  • 系统应能够每秒处理 1,000 个请求。
  • 系统可靠性应高于 0.99。
  • 系统应能处理 1,000 台同时报告其个人数据信息的设备。
  • 根据可支持的设备数来指定系统的最大容量。 例如,具有 3 倍当前容量的系统是否支持 1,000 个并发设备?

根据这些要求,性能测试的 KPI 可以是:

KPI 说明
RPS 事件中心的每秒请求
LOAD 性能测试期间向事件中心发送的负载或请求数量
IR 功能执行数量或引入速率
RT Azure 功能执行时间的平均时间
AMU Azure Functions 的平均内存使用量
SR 所有功能执行的成功率
ARS 下游服务平均响应时间(例如 SQL Server 或微服务)
DF 依赖项失败计数,包括内部 Azure 功能错误
MRPS 事件中心无积压情况下的最大 RPS(系统容量)

如何度量 KPI

若要度量 KPI,需要制定性能测试策略。 该策略定义了每个组件的性能测试方法。 本例中使用了以下性能测试策略:

  • 事件中心:事件中心的性能测试方法是向事件中心发送很多消息,然后测量 RPS 和 LOAD。 RPS 是每秒发送到事件中心的消息数。 LOAD 是性能测试期间发送到事件中心的消息总数。 Azure 负载测试服务可以测量 RPS 和 LOAD。
  • Azure Functions:Azure Functions 的性能测试方法是测量以下指标:
    • IR 是功能执行数量或引入速率。
    • RT 是 Azure 功能执行时间的平均时间。
    • AMU 是 Azure Functions 的平均内存使用量。
    • SR 是所有功能执行的成功率。
    • ARS 是平均下游服务响应时间。
    • DF 是依赖项失败计数,包括内部 Azure 功能错误。
    • Azure Monitor 服务可以测量 AMU、ARS 和 DF,但不能测量 IR、RT 或 SR。

若要使用 Azure Monitor 服务度量 KPI,我们需要为 Azure Functions 启用 Application Insights。 有关详细信息,请参阅启用 Application Insights 集成

启用 Azure Monitor 服务后,可以使用以下查询来度量 KPI:

  • IR:FunctionAppLogs | where Category startswith "name-space-of-your-function" and Message startswith "Executed" | summarize count() by FunctionName, Level, bin(TimeGenerated, 1h) | order by FunctionName desc
  • RT:FunctionAppLogs| where Category startswith "name-space-of-your-function" and Message startswith "Executed "| parse Message with "Executed " Name " (" Result ", Id=" Id ", Duration=" Duration:long "ms)"| project TimeGenerated, Message, FunctionName, Result, FunctionInvocationId, Duration
  • SR:FunctionAppLogs| where Category startswith "name-space-of-your-function" and Message startswith "Executed" | summarize Success=countif(Level == "Information" ), Total=count() by FunctionName| extend Result=Success*100.0/Total| project FunctionName, Result| order by FunctionName desc

Azure Monitor 仪表板示例

下面是 Azure Monitor 面板的示例,它根据查询显示了 Azure Functions 的 KPI:

Screenshot samples of the Azure Monitor dashboard.

结论

在本文中,你学习了如何为 Azure 负载测试设计 KPI 并开发仪表板。 您还学习了如何使用 JMeter 中的自定义插件对与事件中心集成的 Azure Functions 执行负载测试。 你可以使用相同的方法对其他 Azure 服务执行负载测试。 你还可以使用 Azure DevOps 为负载测试脚本设置持续集成和交付 (CI/CD) 管道。

有关详细信息,请参阅 Azure 负载测试

作者

本文由 Microsoft 维护, 它最初是由以下贡献者撰写的。

主要作者:

若要查看非公开领英个人资料,请登录领英。

后续步骤