TL;DR
AutoMQ 基于 S3 共享存储的存算分离架构,在与 Apache Kafka 保证 100% 兼容性的基础上提供了极速弹性、低成本、高性能等优势特性。AutoMQ 相比 Kafka 可以在冷读时提供更好的吞吐性能以及提供更高的极限吞吐。很多客户会关心 AutoMQ 实际的性能表现怎么样。今天本教程会指导用户如何在 AWS 上对 AutoMQ 进行性能测试。
测试环境准备
前提条件
已经按照官方部署文档[2]在 AWS 上正确部署了 AutoMQ。
创建 AutoMQ 控制台
AutoMQ 控制台用于管理具体的数据面集群。按照官方部署文档流程通过 AWS 云市场可以一键完成 AutoMQ 控制台的部署。
创建 AutoMQ 集群
在 AutoMQ 控制台参照官方文档[3]创建一个 6 AKU 规格的集群。6 AKU 表示推荐承载 120 MiB/s 的写入和读取(读写比例1:1),底层实际采用 3 台 r6i.large 实例。

集群创建完毕以后,我们可以从集群实例详情页面获取接入点地址:

AutoMQ S3 CROSS ZONE ROUTER 在 1.3.0 版本提供,目前处于 Early Access 状态。
AKU 能力说明
我们定义了 AKU (AutoMQ Kafka Unit) 用于描述一个 AutoMQ 集群可承载的负载上限。AKU 的限制可以分为两类:
固定限制:任何情况下均无法超出。包括:
分区数量:1 个 AKU 最多创建 1,125 个分区。
推荐限制:根据集群负载的不同,在不同场景下可能超出。包括:
读写流量:根据生产消费比的不同,1 个 AKU 推荐承载的读写流量有所不同
生产消费 1:1 时:1 个 AKU 推荐承载 20 MiB/s 的写入流量和 20 MiB/s 的读取流量。
生产消费 1:3 时:1 个 AKU 推荐承载 12.5 MiB/s 的写入流量和 37.5 MiB/s 的读取流量。可以看到,在高扇出场景,AutoMQ 以承载相对更多的总流量,这是 AutoMQ 写入成本相较于读取成本更高导致的。
请求频率:推荐每秒请求数量 800 个。
如前文所述,在某些场景下,推荐限制是可以超出的,但这通常以其他指标的减少为代价。例如,当集群中读写流量低于 AKU 限制时,请求频率可以超出 AKU 限制。
除此之外,在某些极端场景下,可能无法达到某个指标。例如,当集群中分区数量达到限制,且读取流量均为“冷读”(即消费较老的数据)时,可能无法达到读取流量的 AKU 推荐上限。
Client 环境准备
在与 AutoMQ 数据面相同的 VPC 内准备一台机器,用于生成负载。此处我们采用一台 m6i.large 的机器来生成负载,其默认提供超过 100 MiB/s 以上的网络带宽,可以构造足够的写入压力。
从 AutoMQ Github 仓库 Release 下载社区版代码,其中我们提供了 automq-perf-test.sh 工具,其实现参考了 OpenMessaging Benchmark 框架的核心逻辑,它有如下优势:
相较于 Apache Kafka 自带的 kafka-producer-perf-test.sh 与 kafka-consumer-perf-test.sh 脚本,automq-perf-test.sh 支持了在一个进程中同时启动多个 Producer、Consumer,并向多个 Topic 收发消息,更加贴近实际场景,使用起来更加方便。
相较于 OpenMessaging Benchmark 测试框架,不再需要分布式部署多个 Worker,单机即可一键执行测试。在不特别大规模的测试场景下,部署与使用起来更加方便。
除此之外 automq-perf-test.sh 脚本还支持了更加复杂的冷读测试场景——可以启动多个 Consumer Group,并且每个 Group 分别从不同的位点开始消费,这样可以避免在冷读时复用 Cache,进而测试更加极端场景下的冷读性能。
因为该测试脚本仅依赖 Apache Kafka Client,所以它可以支持对 Apache Kafka、MSK 等兼容 Kafka 协议的流系统进行性能测试。
除此之外,为了保证负载生成工具的正常运行,还需要准备好版本不低于 JDK17 的 Java 环境。
测试用例与结果
测试脚本使用说明
在介绍具体的压测场景前,首先简要介绍一下 automq-perf-test.sh 脚本的使用方式。
启动选项
-
--bootstrap-server指定 Kafka 集群的初始连接节点,形如 host1:port1,host2:port2。值得说明的是,这些地址仅用于初始连接到 Kafka 集群,以获取集群元数据,所以无需提供集群中全部 Broker 的地址,仅需提供少量运行中且可访问的地址即可。
-
--common-configs指定 Kafka Admin Client、Producer 与 Consumer 的公共配置,例如鉴权相关配置。
-
--topic-configs指定 Topic 相关配置,例如消息保留时间等。
-
--producer-configs指定 Producer 相关配置,例如攒批大小、攒批时间、压缩方式等。
-
--consumer-configs指定 Consumer 相关配置,例如单次拉取消息的最大大小等。
-
--reset是否在运行 Benchmark 前删除集群中原有的所有 Topic。
-
--topic-prefix测试使用的 Topic 的前缀。
-
--topics测试时创建的 Topic 的数量。
-
--partitions-per-topic:每个 Topic 中 Partition 的数量,--topics × --partitions-per-topic即为测试使用的 Partition 总数。 -
--producers-per-topic:每个 Topic 上创建的 Producer 的数量。--topics × --producers-per-topic即为测试使用的 Producer 总数。 -
--groups-per-topic每个 Topic 上创建的 Consumer Group 的数量,亦即测试时的读写比(fan-out)。
-
--consumers-per-group:每个 Consumer Group 中 Consumer 的数量。--topics × --groups-per-topic × --consumers-per-group即为测试使用的 Consumer 总数。 -
--record-sizeProducer 发送的每条消息的大小,单位为字节。
-
--send-rate所有 Producer 每秒发送的消息条数的总和。--record-size × --send-rate 即为测试时的写流量。
-
--random-ratio消息中随机数据的比例,常用于 Producer 开启压缩场景的测试。取值为 0.0 至 1.0 之间,值越大,消息中随机数据越多,理论压缩效果越差;默认为 0.0,即每条消息完全一致。
-
--random-pool-size随机消息池的大小,每次发送消息时会从该消息池中随机选取一条。该选项仅在 --random-ratio 大于 0 时生效。
-
--backlog-duration用于追赶读测试场景,控制积攒消息的持续时间,单位为秒。--record-size × --send-rate × --backlog-duration 即为在追赶读前积攒的消息大小。
-
--group-start-delay:用于追赶读测试场景,控制每个 Consumer Group 在追赶读时消费起点的间隔,单位为秒。设置该选项可以使得每个 Consumer Group 的消费进度错开,避免 Cache 复用,以更好地模拟真实追赶读场景。 -
--send-rate-during-catchup:用于追赶读测试场景,控制在追赶读期间 Producer 的发送速率,默认为--send-rate。 -
--warmup-duration进行测试前预热的时长,单位为分钟。在预热期间,前 50% 的时间会逐步提升 Producer 的发送速率至 --send-rate,后 50% 的时间维持在 --send-rate。预热期间的相关指标不会计入最终结果,为了充分预热 JVM,建议将 --warmup-duration 设置为 10 分钟或以上。
-
--test-duration进行正式测试的时长,单位为分钟。仅非追赶读测试场景(--backlog-duration 不大于 0)生效。
-
--reporting-interval:测试期间相关指标的统计间隔,单位为秒。
结果说明
在测试运行期间,将周期性打印如下输出,为过去 --reporting-interval 间隔内的各相关指标:
2024-11-06 16:17:03 - INFO 230.0s | Prod rate 803.83 msg/s / 50.24 MiB/s | Prod err 0.00 err/s | Cons rate 2411.49 msg/s / 150.72 MiB/s | Backlog: 0.00 K msg | Prod Latency (ms) avg: 1.519 - 50%: 1.217 - 99%: 4.947 - 99.9%: 11.263 - Max: 11.263 | E2E Latency (ms) avg: 1.979 - 50%: 1.595 - 99%: 6.264 - 99.9%: 9.451 - Max: 9.735
各字段含义如下:
"Prod rate":每秒发送的消息的数量与大小。
"Prod err":发送报错的频率。
"Cons rate":每秒消费的消息的数量与大小。
"Backlog":Consumer 落后于 Producer 的消息的数量。
"Prod Latency":Producer 发送消息的延迟,"avg"、"50%"、"99%"、"99.9%"、"Max" 分别为延迟的平均值、P50 分位值、P99 分位值、P999 分位值、最大值。
"E2E Latency":每条消息从发送到被 Consumer 消费的延迟。
在测试运行结束时,将打印如下输出,总结测试期间的相关指标:
2024-11-06 16:18:13 - INFO Summary | Prod rate 800.78 msg/s / 50.05 MiB/s | Prod total 0.24 M msg / 14.68 GiB / 0.00 K err | Cons rate 2402.35 msg/s / 150.15 MiB/s | Cons total 0.72 M msg / 44.03 GiB | Prod Latency (ms) avg: 1.614 - 50%: 1.225 - 75%: 1.601 - 90%: 2.451 - 95%: 3.705 - 99%: 7.150 - 99.9%: 16.706 - 99.99%: 40.361 - Max: 136.785 | E2E Latency (ms) avg: 2.126 - 50%: 1.574 - 75%: 2.013 - 90%: 3.230 - 95%: 4.718 - 99%: 10.634 - 99.9%: 30.488 - 99.99%: 46.863 - Max: 142.817
其中各字段含义与前文一致。
Tail Read
Tail Read,即“追尾读”或“热读”,测试 Producer 与 Consumer 间位点差距不大的场景。在该场景下,Producer 发送的消息在被写入 Broker 后立即就会被 Consumer 消费掉,此时 Consumer 消费到的消息直接来自于 Log Cache,无需读取对象存储,资源消耗较少。
下面的这个用例测试了 AutoMQ 的 Tail Read 性能,该测试用例:
-
生产和消费流量比例为 1:1
-
将向 10 个 Topic 合计 1280 个 Partition 中写入数据
-
每秒写入 1600 条大小为 51 KiB 的消息(不进行任何攒批),写入速度为 80 MiB/s
注意 在执行如下脚本前,需要将 --bootstrap-server 地址替换为实际的 AutoMQ 接入点地址。
KAFKA_HEAP_OPTS="-Xmx12g -Xms12g" ./bin/automq-perf-test.sh \
--bootstrap-server 0.kf-v8tj9bmunqdo1og8.wanshao-for-aws.automq.private:9092,1.kf-v8tj9bmunqdo1og8.wanshao-for-aws.automq.private:9092,2.kf-v8tj9bmunqdo1og8.wanshao-for-aws.automq.private:9092 \
--producer-configs batch.size=0 \
--consumer-configs fetch.max.wait.ms=1000 \
--topics 10 \
--partitions-per-topic 128 \
--producers-per-topic 1 \
--groups-per-topic 1 \
--consumers-per-group 1 \
--record-size 52224 \
--send-rate 1600 \
--warmup-duration 10 \
--test-duration 5 \
--reset
注意 一般而言,AutoMQ 单个分区建议支持 4 MiB/s 的写入,可以按照该数值来确定 Topic 具体需要多少分区。在推荐配置下,AutoMQ 可以保证冷读的效率。
执行结果
执行完毕后会在当前目录生成一个和时间相关的报告 JSON 文件,例如 perf-2024-10-31-11-24-57.json,其中的输出结果与 OpenMessaing Benchmark 的输出结果保持一致。
在我们的测试中,可以看到 AutoMQ 集群可以在 80 MiB/s 的写入性能下保持 P99 个位数毫秒的写入延迟,同时没有任何消息积压。

Catch-Up Read
Catch-Up Read,即“追赶读”或“冷读”,测试 Consumer 消费位点远落后于 Producer 位点的场景。在该场景下,首先将暂停 Consumer,在积攒一定大小的消息后,再重新开始消费。此时 Consumer 消费的消息将从对象存储中读取,并由 Block Cache 进行预读与缓存。
在该测试场景下,主要关注以下两方面指标
追赶读速度是否最够快。观察每个 Consumer Group 的消费速度是否超过了 Producer 的写入速度,只有超过了,才意味着 Consumer 可以追上 Producer。
追赶读期间写入流量是否受到影响。观察追赶读期间 Producer 发送消息的流量是否有所下降,以及发送延迟是否升高。
下面的这个用例测试了 AutoMQ 的 Catch-Up Read 性能,该测试用例:
-
生产和消费流量比例为 1:3
-
将向 10 个 Topic 合计 1280 个 Partition 中写入数据
-
每秒写入 800 条大小为 64 KiB 的消息(不进行任何攒批),写入速度为 50 MiB/s
-
在追赶读前将积攒 600 秒数据(~30 GiB),随后启动 3 个 Consumer Group 开始追赶读,每个 Group 的起始位点将有 30 秒的间隔(~1.5 GiB)
注意 在执行如下脚本前,需要将 --bootstrap-server 地址替换为实际的 AutoMQ 接入点地址。
KAFKA_HEAP_OPTS="-Xmx12g -Xms12g" ./bin/automq-perf-test.sh \
--bootstrap-server 0.kf-hsd29pri8q5myud5.wanshao-for-aws.automq.private:9092,1.kf-hsd29pri8q5myud5.wanshao-for-aws.automq.private:9092,2.kf-hsd29pri8q5myud5.wanshao-for-aws.automq.private:9092 \
--producer-configs batch.size=0 \
--consumer-configs fetch.max.wait.ms=1000 \
--topics 10 \
--partitions-per-topic 128 \
--producers-per-topic 1 \
--groups-per-topic 3 \
--consumers-per-group 1 \
--record-size 65536 \
--send-rate 800 \
--backlog-duration 600 \
--group-start-delay 30 \
--warmup-duration 5 \
--reset
执行结果
通过结果输出信息,我们可以观察到 AutoMQ 在冷读期间的写入性能完全没有受到影响。

常见问题排查方法
下面是一些在性能测试时的常见问题与解决方法。
吞吐与延迟不符合预期
在测试过程中,经常遇到的问题是测试结果不符合预期,表现为发送流量低于设定值、发送延迟过高等。该问题的原因可以简要概括为 Client 侧压力过高与 Server 侧压力过高两类。下面介绍一些常见问题的排查与处理方法。
Client 侧 - 网络带宽不足
在各个云厂商中,不同机型拥有不同的网络带宽限制,该限制分为基线(Baseline,最低保证的带宽)与突发(Burst,最高可达到的带宽)两种。
如果尝试在一台网络带宽相对较小的机器上运行较大吞吐的负载,会导致生产或消费流量低于预期。例如,在一台网络带宽为 128 MBps 的 Client 机器上,尝试运行 50 MiB/s 写入 + 150 MiB/s 读取的负载,会发现读取流量最高不会超过 128 MiB/s。
在挑选 Client 机型时,建议根据测试负载选择网络 Baseline 性能满足需求的机型,以避免前述问题。
Client 侧 - GC 压力过高
automq-perf-test.sh 脚本默认使用 ZGC 作为 JVM Garbage Collector,它相较于传统的 G1GC,消耗的 CPU 更多,但 STW (Stop the World) 时间非常短。然而,当 CPU 耗尽或堆内存占用过多时,ZGC 会发生劣化(Allocation Stall),导致 STW 时间大幅升高,进而导致客户端延迟上升。
可以通过检查 ZGC 日志判断是否存在问题:
grep "Garbage Collection (Allocation Stall)" ./logs/kafkaClient-gc.log
如果存在相关日志,则认为 Client 侧 GC 压力过高。可尝试通过如下方法解决:
-
增加 CPU 数量
-
增大 JVM 堆大小
Client 侧 - CPU 压力过高
当 Client CPU 占用过高时,可能会导致 Producer 与 Consumer 在 Client 的延迟升高,进而导致整体延迟升高。一般来说,为了避免 CPU 过高导致的系统性延迟,建议在 Benchmark 期间控制 Client CPU 占用不超过 70%。
如果是首次针对某个集群进行测试,一个经验估算值是:Client 侧的 CPU 数量等于或略小于 Server 侧的 CPU 数量,大概率可以满足测试需求。如果 Server 侧能力由 AKU 衡量,则 Client 侧所需 CPU 数量约为 AKU * 0.8。
当 Client 侧 CPU 过高时,除扩容外,还可以考虑通过适当调低负载的方式降低 Client 侧压力,例如:
-
减少 Producer 与 Consumer 数量
-
减少每个 Topic 的 Partition 的数量(
automq-perf-test.sh脚本中,每个 Producer 都会向 Topic 中的所有 Partition 发送消息,建议--partitions-per-topic不要超过 128,以避免单个 Producer 压力过高) -
增大
--record-size并降低--send-rate
Server 侧 - 网络带宽不足
当 Server 侧的读写流量过高时,可能会超出机器的网络带宽限制,导致网络被限流,读写流量下降。 此时可以:
-
降低吞吐。
-
开启 Producer 压缩(设置 Producer 的
compression.type配置)。但需要注意,开启压缩后,会导致 Client 与 Server CPU 压力有所升高。
Server 侧 - 请求频率过高
当 Server 侧请求频率(Produce + Fetch)过高时,可能会导致 CPU 占用升高,进而导致请求延迟升高。 此时可以:
-
降低请求频率
-
提高 Client 侧攒批程度,具体地说:
对于 Producer,通过调高 batch.size 与 linger.ms 来增大每个 Produce 请求中 Record Batch 的大小,进而降低 Produce 频率。
对于 Consumer,通过调高 fetch.max.wait.ms 来增大 Fetch 请求在 Broker 侧的等待时间,进而降低 Fetch 频率。
对于 Produce 请求频率,有如下估算方法
每个 Record Batch 的大小(BatchSize)=
min(
"batch.size",
"--send-rate" ÷ "--topics" ÷ "--producers-per-topic" ÷ (1000 ÷ "linger.ms") ÷ "--partitions-per-topic"
)
集群 Produce 的总请求频率 = "--record-size" × "--send-rate" ÷ BatchSize
JVM OOM
当测试使用的 Producer 较多且发送延迟较高时,可能会有较多消息积攒在 Producer 的发送缓冲区,进而导致 JVM 内存耗尽,发生 OOM。
可以通过限制 Producer 使用的内存来避免该问题:
减少 Producer 的数量
降低 Producer 配置 buffer.memory 的值
发送延迟间歇性抖动
当集群中 Broker、Partition 数量较多,流量存在波动时,有时会观察到 Produce Latency 的高分位延迟(例如 P99)间歇性抖动——以一分钟或数分钟为间隔,延迟短时间升高,持续 1~3 秒。
这是 AutoMQ 的 AutoBalancer 执行的自动分区重平衡操作导致的:AutoMQ 会定时检查集群中各 Broker 负载,当部分 Broker 负载显著偏高时,会尝试迁移部分 Partition 到其他 Broker,以尽量均匀负载。在 Partition 迁移期间,会有较短时间(秒级)的 Partition 不可用,导致 Producer 发送延迟抖动。
总结
本文主要指导用户如何使用 automq-perf-test.sh 工具对 Kafka 集群进行性能测试。通过该工具,用户可以自行构造不同的工作负载来验证 AutoMQ 在不同热读、冷读场景下的性能表现。
参考资料
[1] Best practices for right-sizing your Apache Kafka clusters to optimize performance and cost: https://aws.amazon.com/cn/blogs/big-data/best-practices-for-right-sizing-your-apache-kafka-clusters-to-optimize-performance-and-cost/
[2] Install Env from Marketplace: https://docs.automq.com/automq-cloud/getting-started/install-byoc-environment/aws/install-env-from-marketplace
[3] Manage Instances: https://docs.automq.com/automq-cloud/using-automq-for-kafka/manage-instances#create-instance
