全部产品
云市场

JMeter 压测 MQTT 服务

更新时间:2019-11-15 16:49:51

若需压测 MQTT 服务,则需使用 MQTT 插件和 JMeter 生成 JMeter 脚本,再将脚本上传到 PTS 控制台进行压测。

背景信息

MQTT 是专为移动互联网(Mobile Internet)、物联网(IoT)设计的超轻量级消息协议,用于连接移动端与云服务双向通信,广泛应用于各种应用领域,如端向云汇报状态、云向端推送消息、端向端发送消息(即时聊天)等场景。

现有使用 MQTT 发布广播消息,共有 5 个订阅客户端,每个消息订阅客户端都收到一份消息的场景,本文以此类场景为例介绍如何使用 PTS 的 JMeter 模式压测 MQTT 服务。

前提条件

  • 已部署可在公网访问的 MQTT 服务。
  • 已安装 JMeter 5.x 版本。

步骤一:安装 MQTT 插件

  1. 下载 mqtt-jmeter 插件最新版本 JAR 包:mqtt-xmeter-1.0.1-jar-with-dependencies.jar

  2. 拷贝插件 JAR 包到 JMeter 安装目录的 lib/ext/ 子目录下。

  1. cp mqtt-xmeter-1.0.1-jar-with-dependencies.jar "${JMETER_HOME:?}"/lib/ext/

步骤二:准备客户端信息 CSV 文件

每个 MQTT 客户端需要提供以下信息:

  • 用户名和密码。

    为保证安全,MQTT 服务器通常需要认证,最常用的认证方式即用户名和密码认证。

  • 客户端 ID(ClientId)。

    客户端 ID 是全局唯一 ID,客户端唯一标识,通常与用户设备关联。如关联手机序列号,则可通过客户端 ID 变化检测用户是否更换了新手机。每个用户可能有一个或多个客户端 ID 。

客户端信息 CSV 文件应包含 UserNamePasswordClientId 这 3 列数据。例如期望压测 10000 台客户端设备同时在线的场景,则需要准备 10000 条客户端信息。

如客户端信息示例 CSV 文件 client.csv 内容如下:

  1. UserName,Password,ClientId
  2. pts_test,pts-pass1,client-test0001
  3. pts_test,pts-pass1,client-test0002
  4. pts_test,pts-pass1,client-test0003

说明

  • 做压测时建议使用测试用户数据,避免泄露真实用户信息,避免真实用户产生脏数据。

  • 使用预先准备的测试客户端 ID 方便服务器做客户端 ID 校验,同时方便跟踪排查问题。

  • 手动编辑 CSV 文件很容易出错,推荐使用 EXECL、Numbers 等软件导出,或使用 Apache commons-csv 程序生成。

步骤三: 本地编辑 JMeter 脚本

本教程以 JMeter 5.x 英文图形界面为例。

  1. 读取客户端 CSV 数据文件。

    1. 打开 JMeter,并新建脚本。
    2. 在 JMeter 左侧文件目录中右键单击 Test Plan ,选择 Add > Threads (Users) > Thread Group

      您还可以右键单击 Test Plan ,选择 Add > Listener > View Results Tree ,添加 View Results Tree 监听器,方便本地调试测试脚本。

    3. Test Plan 区域右键单击 Thread Group ,选择 Add > Logic Controller > Once Only Controller

      JMeter 中一个线程模拟一个 MQTT 客户端设备,使用 Once Only Controller 保证一个线程仅读取一次客户端 CSV 数据文件,绑定一条客户端信息。

    4. Test Plan 区域右键单击 Once Only Controller , 选择 Add > Config Element > CSV Data Set Config 。并在 CSV Data Set Config 对话框中配置以下信息。

      10-csv-config.png

      • Filename :客户端信息 CSV 文件名 client.csv

        注意:只输入文件名 client.csv ,不要包含文件路径,以实现文件最大的通用性。将 client.csv 文件保存到 JMeter 进程启动目录以保证能够被读取到。

      • File encoding:CSV 文件编码格式,本示例使用 UTF-8

      • Recycle on EOF:是否循环读取文件。本示例中选择 False,一条客户端信息只能被读取使用一次(与一个线程绑定),不允许循环读文件。

  2. 建立 MQTT 连接。

    同样使用 Once Only Controller 控制一个客户端(对应一个线程)只需执行一次建连操作。

    1. Test Plan 区域右键单击 Once Only Controller,选择 Add > Sampler > MQTT Connect

    2. MQTT Connect 对话框中配置以下信息。

      20-mqtt-connect.png

      MQTT 连接配置:

      • Server name or IP:MQTT 服务器公网地址。客户端设备通常使用公网访问 MQTT 服务。
      • Port number:MQTT 服务器端口。例如 1883,即使用标准 TCP 端口。
      • MQTT version: MQTT 版本。例如 3.1.1,目前主流 MQTT 服务器都支持 3.1.1 版本。
      • Timeout(s):超时秒数填写,即客户端建立连接、发送消息等相关操作的超时时间。例如 10
      • Protocols:连接协议。选择 TCP,即使用标准 TCP 连接协议。

      MQTT 客户端配置:

      • User name:从 CSV 文件读取 userName 字段。填写 ${userName}
      • Password:从 CSV 文件读取 Password 字段。填写 ${password}
      • ClientId: 从 CSV 文件读取 ClientId 字段。填写 ${clientId}
      • Add random suffix for ClientId:是否添加后缀。本例使用预先准备好的固定客户端 ID,不要添加后缀,则取消勾选。
      • Keep alive(s): 活动心跳间隔秒数。例如 300,即连接空闲时,每 5 分钟发送一次活动心跳。
  3. 配置发布消息。

    1. Test Plan 区域右键单击 Thread Group,选择 Add > Sampler > MQTT Pub Sampler

    2. MQTT Pub Sampler 对话框中配置以下信息。

      30-mqtt-pub.png

    • QoS Level:客户端向服务器发布消息的服务质量。本示例中选择 0,即只发送一次,丢失不重发,可按需选择其他级别。
    • Topic name:消息 topic 。MQTT topic 支持层次结构,使用 / 分割,类似文件路径,如 pts_test/jmeter 等。
    • Add timestamp in payload:是否添加消息头添加发送时间戳。一般勾选此项,方便测试时检查消息延迟。
    • Payloads:消息体。本示例中填写 Aliyun PTS From ${clientId},即在消息体中添加客户端 ID,方便测试和调试检查。
  4. 订阅接收消息。

    1. Test Plan 区域右键单击 Thread Group,选择 Add > Sampler > MQTT Sub Sampler

    2. MQTT Sub Sampler 对话框中配置以下信息。

      40-mqtt-pub.png

      • QoS Level:服务器向客户端推送消息的服务质量。本示例选择 0,即只发送一次,丢失不重发,可按需选择其他级别。
      • Topic name:消息 topic 。应与发布消息的 topic 匹配,如本例中为 pts_test
      • Payload includes timestamp:是否在接收消息后从消息头解析发送时间。一般勾选此项,可计算出消息延迟,即从发布端、途经服务器、最后到达订阅端花费的总时间。
      • Sample on: 选择 specified elapsed time (ms),值填写 1000,表示持续接收消息 1000 毫秒。这段时间内,可能一条消息都接收不到,也可能接收到多条消息。
      • Debug response:一般勾选此项,用于记录接收到的消息内容,方便调试排查问题。正式执行性能测试时可取消该选项以优化性能和减少内存占用。
    3. Test Plan 区域单击 Thread Group,配置 Loop Count3(循环执行 3 次)。

    4. 保存并执行脚本。

      脚本执行结果如下:result_Samplerex_result_response_data

  5. 添加消息订阅线程组。

    当前脚本配置下,执行一次消息订阅可能未收到消息但仍记录为 1 次结果,可能收到多个消息但不能拆分记录消息延迟,导致压测统计数据不准确。

    为了解决此问题,MQTT Sub Sampler 支持另一种工作模式:每收到一条消息产生一个有效的执行结果,这样将更合理。但这种模式下,没有收到消息时线程将一直阻塞,为了避免阻塞整个线程,应将订阅消息拆分到不同的线程组。发布消息线程组移除订阅操作后,应添加等待时间避免单个客户端发布消息过快。实际场景通常是客户端数量多,但每个客户端的消息量少。

    1. Test Plan 区域右键单击 MQTT Pub Sampler ,选择 Add > Time > Constant Timer,设置延时 1000 毫秒,即每次发布消息后等待 1 秒。

      55-mqtt-pub-sleep.png

    2. 新建消息订阅线程组,从消息发布线程组复制读取 CSV 和 MQTT 连接配置,共享 CSV 文件。

      此时一个客户端(对应一条 CSV 记录)要么用于发布消息,要么用于订阅消息,不能两者同时使用。

    3. 在新消息订阅线程组下的单击 MQTT Sub Sampler,然后在 MQTT Sub Sampler 对话框中配置 Sample onnumber of received messages,值设为 1 ,即每收到一条消息产生一条执行结果。

      56-mqtt-sub-msg.png

    4. 执行脚本。

      测试执行脚本结果如下:

      57-result-sub-1.png

步骤四:使用 PTS 压测 MQTT 消息

在 PTS 控制台使用 JMeter 压测场景 ,上传 mqtt-jmeter 插件 JAR 包、JMeter 脚本和客户端信息 CSV 文件。详情请参见 JMeter 原生压测

步骤一:导入 JMeter 脚本

  1. 登录 PTS 控制台,在概览页单击 JMeter 原生压测,或者在左侧导航栏选择 创建压测 > JMeter 压测
  2. 发起 JMeter 压测页面,输入场景名称。
  3. 场景配置页签下,单击+上传文件,添加 JMeter 脚本、JAR 文件(即放置在 JMeter 的安装目录…/lib/ext 下的相关 JAR 文件)和其他数据文件。

    注意:上传的同名文件将覆盖之前上传的文件。如需对比文件,可在该文件的操作列,获取 MD5 值,与您本地文件的 MD5 值进行对比,确认文件是否变更。

    上传文件

    使用限制

    • JMX 脚本文件:文件大小不超过 2MB。可上传多个 JMX 脚本文件,但是压测仅能使用一个 JMX 脚本。发起压测前勾选一个使用。
    • JAR 文件:文件大小不超过 10MB。上传之前,请在本地 JMeter 环境调试 JAR 文件,确保调试通过。
    • CSV 和 ZIP 数据文件:文件大小不超过 60 MB。ZIP 内打包的文件必须是以 .csv 结尾的单个文件。

      注意

      • 准备 CSV 文件时,请不要直接修改 .xlsx 文件的后缀。推荐使用 EXCEL、Numbers 等软件导出,程序生成可以使用 Apache commons-csv。
      • 如果 JMX 脚本中关联了数据文件,务必将 CSV Data Set Config 中的 Filename 改为文件名本身,不要带路径(如下图所示)。否则会读取不到数据文件。同理,如果使用了 __CSVRe 函数或者在 JAR 中有指定文件,均需使用文件名。数据文件定义
  4. 如上传了多个 JMX 文件,勾选一个 JMX 文件作为发起该压测场景使用的 JMeter 脚本。
  5. (可选)为 CSV 文件勾选切分文件,可以保证该文件的数据在每个施压机不重复。不勾选该项,每个施压机上使用同一份数据。详见 JMeter 使用 CSV 参数文件
  6. 选择 JMeter 版本 和 Java 版本。
    • JMeter 版本:支持 Apache JMeter 5.0、4.0 和 3.3。
    • Java 版本:支持 Java 8。

步骤二:施压配置

单击施压配置页签,并完成施压配置。施压配置

配置项说明:

  • 压力来源:可选为国内和阿里云 VPC 内网。
    • 选择国内时,发起压测的节点来自全国各地,根据压测的量级来分配对应的节点资源(IP)。
    • 选择阿里云 VPC 内网时,您需要继续选择地域、VPC-ID、安全组、虚拟交换机等信息,压力来源来自您选择的阿里云 VPC 网络施压机。

      注意:

      • 选择地域后,VPC 信息栏下方会显示当前地域下施压源的可用区,确保选择的交换机与施压源在同一可用区内。若您的交换机不在当前地域的可用区内,请单击创建交换机去创建交换机。
      • 确保选择的交换机的空闲 IP 大于等于施压 IP 数。
  • 并发数:指同时发送压测请求的用户数量。并发数受您购买的资源包限制。
  • 指定 IP 数:指定施压引擎的数量,此项为可选项。引擎数增加会带来计费的增加,计费并发 = 引擎数 * 500,且最大引擎数不超过 100。
    • 增加引擎数会带来计费的增加,请关注施压配置页面右侧的预估消耗 VUM 数。
    • 可设置的最大引擎数受资源包限制,具体可参见指定IP数的帮助提示。
  • 压测时长:指压测总时长,包括预热时间。
  • 预热时间:指压测流量到达已配置的并发数的时间。在这个时间内,并发数递增,直到最大并发数。
  • 循环次数:指每个并发的循环执行次数。

    注意循环次数达到设置值,或压测时长达到设置值,压测都会停止。

若脚本中使用多个线程时:

  • 每个线程使用一条客户端信息,总并发数不能大于 CSV 文件提供的客户端信息条数。
  • 脚本包含两个线程组时,设置总并发后,运行时线程组并发数按原脚本设置并发数的比例分配。例如:原脚本两个线程组并发均为 1,设置场景总并发为 10,则运行时两个线程组并发各为 5:若原脚本修改发布消息并发数为 2,订阅消息并发数为 1,设置场景总并发为 12,则运行时发布消息并发为 8,订阅消息并发为 4。

步骤三(可选):添加监控

如果您有云监控或 ARMS 监控实例,通过添加监控的方式,您可以在压测及报告中便捷地查看相应的监控数据。具体操作及监控数据的查看步骤,参见以下文档:

步骤四:启动压测

完成基本配置之后,在发起 JMeter 压测页面右上角,单击保存去压测,发起压测。稍等数秒,操作页会进入压测态。页面概览如下。 保存去压测

压测过程中,您可以监控压测数据,进行如下操作:

  • 详情页签下,单击单个链路的右侧图标 91788_2,查看其 TPS、成功率、响应时间、流量等实时数据。
  • 选择 JMeter 日志页签,可根据施压机、日志级别、时间范围或施压线程筛选日志,并查看日志详情。
  • 单击页面右上角的查看采样日志,可根据压测 Sampler、响应状态、施压机等筛选日志,查看日志详情。

场景说明:

指标 说明
VUM PTS 的计费单位
压测计时 压测执行的时长,包括预热阶段的时间
场景并发 当前施压的并发值,如果在预热阶段则未达到配置并发,预热结束后即为配置的并发值
场景 TPS(s) 压测周期内,当前场景的平均 TPS 值。TPS = 场景压测期间的全部请求数 / 压测时长。
RT Avg (ms) 压测周期内,所有请求的平均响应时间 (区分成功与失败)
成功率(%) 所有请求的整体请求成功(无断言时 2XX、3XX 的比例;有断言时为断言成功的比例)情况

步骤五:查看压测报告

在压测停止之后,系统会自动收集压测过程中的数据,形成压测报告,展现 JMeter 压测场景和具体指令的压测动态信息。详情请参见JMeter 压测报告

压测结果分析

开始压测后,压测过程中可看到实时并发数(发布消息客户端和订阅消息客户端总数),TPS 和 RT(消息延迟)等统计信息。

62-pts-jmeter-running.png

本示例中发布消息为广播,每个消息订阅客户端都收到一份消息,总共有 5 个订阅客户端,因此可看到接收消息数是发布消息数的 5 倍。压测结束后将生成压测报告,可查看场景并发、TPS、响应时间等变化趋势图和统计数据汇总等信息。如果出现错误,还可以结合请求采样日志和 JMeter 日志等进行排查。

64-pts-jmeter-report.png

常见问题

发布消息包含中文字符时,为什么查看接收到的消息包含乱码?

由于 MQTT 消息体为二进制数据,发布消息时字符串使用系统编码(UTF-8 或 GBK)转为二进制,接收消息时默认使用 ISO-8859-1 将二进制转为字符串,两边编码不一致导致乱码。