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

使用事件中心和 IoT 中心的自定义插件进行 Azure 负载测试

解决方案构想

本文介绍了一种解决方案构想。 云架构师可以通过本指南来帮助可视化此体系结构的典型实现的主要组件。 以本文为起点,设计一个符合工作负荷特定要求的架构合理的解决方案。

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

IoT 中心包含的核心组件多于事件中心,包括分区。 因此,本文中所述的负载测试方法也适用于 IoT 中心,但更改最少。

体系结构

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

用于负载测试的示例体系结构的关系图。

下载此体系结构的 Visio 文件

数据流

以下数据流对应于上图:

  1. 模拟设备通过负载测试代理将数据发送到事件中心。 可以使用 JMeter 自定义插件模拟设备的任何行为。 负载测试代理在为任何类型的模拟设备运行自定义插件后,将数据发送到事件中心。

  2. 事件中心触发一个 Azure 函数应用,该应用处理数据并将其发送到其他下游服务,例如 Azure SQL 数据库和 Azure 数字孪生。

  3. Azure Monitor 监视函数应用和事件中心。

  4. 负载测试从 Azure Monitor 收集数据,并将其显示在仪表板中。

组件

此示例使用以下组件:

  • 负载测试:使用负载测试运行 Apache JMeter 脚本和自定义插件来模拟用户和设备行为。 负载测试提供了一个基于 Web 的界面,用于管理和运行负载测试和一组 API 来自动执行该过程。 负载测试是一项完全托管的服务,这意味着无需管理服务器或基础结构。 在此体系结构中,负载测试上传了 JMeter 脚本和自定义插件,并且这些脚本是在计算资源上运行的。

  • 事件中心:事件中心是基于云的事件处理服务,可用于实时收集、处理和分析来自各种源的事件和流数据。 事件中心支持多个协议,包括高级消息队列协议(AMQP)、HTTPS、Kafka 协议、消息队列遥测传输(MQTT)和基于 WebSocket 的 AMQP。 此体系结构基于事件,因此负载测试会填充事件以负载测试工作负荷。

  • IoT 中心:IoT 中心是一种云托管的托管服务,充当中心消息中心,用于 IoT 应用程序与其附加设备之间的通信。 可以安全可靠地连接数百万台设备及其后端解决方案。 几乎任何设备都可以连接到 IoT 中心。 可以通过将事件中心客户端更改为 IoT 中心客户端来调整此体系结构以使用 IoT 中心。

  • Azure Functions:Functions 是一种无服务器计算服务,可用于运行代码,而无需管理服务器或基础结构。 它支持多种编程语言,包括 C#、F#、Java、JavaScript、PowerShell、Python 和 TypeScript。 此体系结构使用 Functions 作为主要计算层。 事件中心中的事件数据会触发和横向扩展函数应用。

  • JMeter GUI:JMeter GUI 是一种开源负载测试工具,主要用于测试 Web 应用程序的性能。 但是,还可以使用它来测试其他类型的应用程序,例如 SOAP 和 REST Web 服务、FTP 服务器和数据库。

  • Azure Monitor:Azure Monitor 为 Azure 资源提供监视和警报功能。 使用它监视应用程序和底层基础结构的性能和运行状况。 在此体系结构中,Azure Monitor 在负载测试期间监视 Azure 基础结构组件的运行状况。

方案详细信息

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

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

JMeter 使用基于 GUI 的接口允许用户创建测试计划,其中包括具有不同设置和配置的多个测试方案。 测试人员还可以使用插件或编写自定义代码来定制 JMeter。 这些插件可以帮助用户使用使用非 HTTP 协议的服务,例如 AMQP 和 WebSocket。

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

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

在此示例中,设备报告特定时间段内的温度和湿度。 该示例使用自定义 JMeter 插件模拟此行为。 自定义插件 的当前实现使用提供的模板生成随机数据。 但是,插件可以包含任何设备可能具备的复杂行为。 在此示例中,设备将数据发送到 Azure 中的事件中心。 事件中心触发一个 Azure 函数应用,该应用处理数据并将其发送到其他下游服务,例如 SQL 数据库。 Azure Functions 是体系结构测试的服务。 测试计划旨在模拟设备的行为,并将数据发送到事件中心。

可能的用例

对自定义插件使用负载测试在各种方案中非常有用,例如:

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

自定义插件

在 JMeter 中,自定义插件是可以添加的软件组件,用于扩展其默认功能。 自定义插件将新功能、函数或集成添加到 JMeter。 可以使用 Java 编程语言和 JMeter 插件开发工具包(PDK)开发自定义插件。 PDK 提供了一组工具和 API,可帮助你创建新插件,包括 GUI 元素、侦听器和采样器。

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

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

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

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

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

  1. 在文本编辑器中创建 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" estclass="com.microsoft.eventhubplugin.EventHubPlugin" testname="Azure Event Hubs Sampler" enabled="true">
                    <!-- Azure Event Hub connection configuration using Managed Identity (see repository for instructions) -->
                    <boolProp name="useManagedIdentity">true</boolProp>
                    <stringProp name="eventHubNamespace">telemetry-ehn.servicebus.windows.net</stringProp>
                    <stringProp name="eventHubName">telemetry-data-changed-eh</stringProp>
                    <stringProp name="liquidTemplateFileName">StreamingDataTemplate.liquid</stringProp>
                </com.microsoft.eventhubplugin.EventHubPlugin>
            </hashTree>
        </hashTree>
        </hashTree>
    </jmeterTestPlan>
    

    com.microsoft.eventhubplugin.EventHubPluginGui提供了 com.microsoft.eventhubplugin.EventHubPlugin 实现。

  2. 在文件中,使用分配和测试运行程序托管标识来设置事件中心连接值。 该标识需要对事件中心实例具有写入访问权限。

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

  4. 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 对象,该对象具有三个属性,MachineIdTemperatureHumidityMachineId 是长度为 27 个字符的随机生成的 ID,TemperatureHumidity 是小于 100 的随机整数。 此文件是一种 Liquid 模板语法。 Liquid 模板是各种 Web 开发框架中使用的常用模板语言。 Liquid 模板使开发人员能够创建易于更新和修改的动态内容。 它们允许在事件中心消息中插入变量、条件、循环和其他动态元素。 语法非常简单,有很多在线资源可以帮助你入门。 Liquid 模板提供了一种强大且灵活的方法来创建动态、可自定义的消息。

  5. 保存并关闭该文件。

    重要

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

将自定义插件从事件中心更新到 IoT 中心

自定义插件使用事件中心作为主要目标资源。 以下配置是事件中心的 SDK 客户端设置:

EventHubProducerClient producer = null;
EventHubClientBuilder producerBuilder = new EventHubClientBuilder();

producerBuilder.credential(getEventHubNamespace(), getEventHubName(), new DefaultAzureCredentialBuilder().build());
producer = producerBuilder.buildProducerClient();

EventDataBatch batch = producer.createBatch(new CreateBatchOptions());
batch.tryAdd(new EventData(msg));
producer.send(batch);

以下示例演示如何重复使用同一解决方案、添加 IoT 依赖项,以及更改 SDK 客户端以使用 IoT 中心:

IotHubServiceClientProtocol protocol = IotHubServiceClientProtocol.AMQPS;
ServiceClient client = new ServiceClient(getIoTHostName(), new DefaultAzureCredentialBuilder().build(), protocol);
client.open();

Message message = new Message(msg);
client.send(getDeviceName(), message);

client.close();

使用新插件运行负载测试

当负载测试启动负载测试时,它将首先将 JMeter 脚本以及所有其他文件一起部署到测试引擎实例。 在运行测试之前,请转到参数选项卡来定义和设置任何必需的参数。 有关详细信息,请参阅 使用 Apache JMeter 插件和负载测试自定义负载测试。

为环境设置性能测试

对于性能测试,测试环境必须类似于生产环境。 此示例使用以下环境进行性能测试,以更好地了解系统的容量和性能。

服务 配置
事件中心 高级版配有一个处理单元
Azure Functions(Azure 功能服务) 具有高级计划 (EP1) 的 Linux - 210 个 ACU、3.5 GB 内存和 1 个 vCPU(相当于 Standard_D1_v2)
区域 美国东部

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

设计性能测试 KPI

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

此示例具有以下业务要求:

  • 系统每秒可以处理 1,000 个请求。
  • 系统可靠性高于 0.99。
  • 系统可以处理 1,000 台并发设备报告其个人数据信息。
  • 可以在系统支持的设备数方面指定系统的最大容量。 例如,系统可以支持 1,000 个并发设备,其当前容量是当前容量的三倍。

若要测量系统是否满足这些要求,可以使用以下 KPI 进行测试:

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

度量 KPI

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

  • 事件中心: 事件中心的性能测试方法是将许多消息发送到事件中心,然后测量 RPS 和 LOAD。 RPS 是每秒发送到事件中心的消息数。 LOAD 是性能测试期间发送到事件中心的消息总数。 负载测试可以测量 RPS 和 LOAD。

  • Azure Functions: Functions 的性能测试方法是测量以下指标。

    • 红外线
    • RT
    • AMU
    • ARS
    • DF

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。

显示 Azure Monitor 仪表板示例的屏幕截图。

结束语

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

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

贡献者

Microsoft维护本文。 以下参与者撰写了本文。

主要作者:

要查看非公开的 LinkedIn 个人资料,请登录到 LinkedIn。

后续步骤