
1. 项目概述与背景做消息队列的同学应该都清楚Kafka 这类传统架构在云上跑久了本地磁盘的问题会越来越扎眼容量规划要提前做节点扩容要等数据重平衡存储成本居高不下。尤其是遇到大促、流量突刺磁盘写满、分区不均、迁移耗时这些问题几乎每个运维都踩过。业内其实早就有一个共识——把存储和计算彻底拆开消息日志放到远端共享存储上节点只做无状态的计算这样才能真正享受云的红利。AutoMQ 就是沿着这个思路把 Kafka 协议兼容的消息队列做成了云原生架构。它的核心设计是 Log 层分离写入的日志数据不再依赖本地磁盘而是落到 S3、EBS 这类远程存储服务上节点本地几乎不保留持久化状态。这样一来扩缩容可以做到秒级存储和计算独立伸缩成本和弹性表现都上了一个台阶。不过远程存储的性能直接决定了整个集群的上限选什么存储、怎么配参数就成了一个不能回避的问题。这次我做了一轮 AutoMQ 和 AWS FSx for NetApp ONTAP下面按业内习惯简称 FSxN的联合性能测试。选 FSxN 的原因很直接它是 AWS 上比较成熟的托管文件存储支持 NFS 与 SMB 协议多可用区高可用、快照、分层存储这些能力都内置好了数据库和中间件厂商在它上面跑关键业务已经很普遍。AutoMQ 的远程日志目录可以基于 POSIX 文件系统语义来抽象FSxN 提供的 NFS 挂载正好能对接上。配合 AWS 的 EKS 和 EC2 来承载 AutoMQ 的计算节点整个链路就比较完整了。这篇报告我会从选型思路、环境搭建、压测方法、数据结果到排查经验完整地把测试过程捋一遍。适合两类人看一是正在规划 Kafka 迁移、想用云原生架构替代自建集群的架构师和运维同学二是已经选了 AutoMQ、但拿不准远程日志存储该用 S3 还是 NAS 类服务想看到真实对比数据的人。读完你至少能知道AutoMQ 在 FSxN 上到底能跑到什么程度哪些参数会影响吞吐和延迟以及实际操作中有哪些坑是文档里不会写清楚的。2. AutoMQ 与 FSxN 的协作逻辑2.1 AutoMQ 的存储引擎为什么会需要文件系统接口很多人第一次接触 AutoMQ 时会有一个疑问Kafka 的日志不是可以直接写到 S3 上吗为什么还要通过文件系统语义接入这个问题的答案藏在 AutoMQ 底层的 storage engine 设计里。AutoMQ 的 log 层抽象了一套类似 POSIX 的接口把 stream、segment、offset 这些概念映射到目录和文件上。具体来说每个 topic-partition 的日志由一个个 segment 文件组成segment 在远端的路径是有规律的AutoMQ 通过这套路径规则来定位数据、判断水位、执行归档和清理。S3 对象存储虽然能存数据但它没有目录、没有 rename、没有 append-only 的文件语义也没有类似 POSIX 的锁机制。如果直接对接 S3 APIAutoMQ 的很多内部逻辑——比如创建临时文件、写满后原子发布、读取时按文件路径定位——都需要重写或者打补丁。FSxN 这类支持 NFS 的共享文件系统正好补上了这一环。它对外呈现的是完整 POSIX 语义AutoMQ 几乎不需要改动核心代码就能把远程日志目录当作一个本地目录来用。NFS 协议在 Linux 内核里已经很成熟配合 fstab 自动挂载、noatime 等挂载参数整个接入过程非常平滑。这其实是一种典型的用接口抽象隔离底层实现的做法。AutoMQ 的核心存储引擎只面对文件系统接口对接 S3 也好、FSxN 也好、甚至自建的存储阵列也好都只是换一个驱动的问题。我们选 FSxN本质上就是选了一个高性能、能水平扩展、且具备企业级可靠性的 POSIX 文件后端。测试下来这个选择在吞吐和稳定性上都是站得住脚的。2.2 FSxN 能力盘点与为什么 NAS 反而是合理选项在 AWS 的存储家族里文件存储选择其实不少EFS 简单但性能上限不高EBS 是块存储不能跨节点共享S3 是对象存储没有文件语义。FSxN 的核心竞争力在于三点一是性能可以做到很高单文件系统能跑到数 GB/s 的吞吐和几十万 IOPS二是基于 NetApp ONTAP 演进而来快照、克隆、分层、QoS 这些企业级能力很成熟三是部署在 AWS 托管环境里可用性和运维负担都有保障。为什么说 NAS 对 AutoMQ 反而是合理选项要看消息队列日志的访问模式。Kafka 的读写是顺序写、随机读segment 文件一旦写完就基本不再修改消费者读取时往往是追尾读或者按 offset 读中间数据。这种访问模式对 POSIX 语义的依赖不大但很看重顺序写的带宽和低延迟。S3 在顺序写方面要经过 HTTPS 请求单请求超时和限流问题会拉高 P99而 NFS 挂载后走的是内核文件系统路径网络层是 TCP 直接传输写一个 1 MB 的 segment 块和写本地文件几乎一个体验。当然说 NAS 合理不是为了否定 S3。在实际的生产里两者可以结合使用热数据走 FSxN 保证写入延迟冷数据由 AutoMQ 定期归档到 S3 降低成本。FSxN 支持数据分层到 S3这样热目录在 NAS、冷数据在对象存储就天然打通了。从性价比来看这个组合比全部热数据囤在 EBS要划算得多也比全部走 S3要稳得多。按照我这次的压测数据来看FSxN 在顺序写场景下能跑出约 1.2 GB/s 的稳定写入带宽AutoMQ 的远端写入吞吐跟着就上来了配合 EKS 上的计算节点整体集群规模可以做到线性扩展。这不只是某一项指标好看而是整个链路从存储到计算都撑住了。3. 测试环境与关键配置3.1 测试集群拓扑与硬件选型思路先交代一下整个压测环境的拓扑方便后面读数据时有个坐标系。计算层3 台 EC2 r6i.2xlarge8 vCPU / 64 GiB存储为 gp3 根盘承载 AutoMQ 的 controller 和 broker 节点。AutoMQ 节点是 K8s 部署所以这 3 台机器同时作为 EKS 的 worker 节点。存储层1 个 FSxN 文件系统部署在 us-east-1 的两个可用区Storage 配置为 2048 GB 的 SSD 容量池Protocol 开启 NFSv3 与 NFSv4.1。吞吐能力预配置为 1 GB/s 基准开启弹性吞吐。网络层EKS worker 节点和 FSxN 挂载点位于同一个 VPC安全组放通 2049 端口NFS。客户端另外一台 c6i.2xlarge 用来跑 OpenMessaging Benchmark 压测框架模拟生产者和消费者负载。选 r6i 而不是 c6i 做 broker 是有原因的。AutoMQ 的节点主要负责 CPU 密集的协议解析、索引维护和网络读写数据落盘是异步交给存储驱动的所以内存和 CPU 比本地磁盘 IO 更重要。r6i 的 Intel Ice Lake 处理器主频高单核性能强对于单 partition 顺序写场景特别合适。64 GiB 内存也足够操作系统做 page cache远端文件写入时能被内核缓存吸收一部分降低写入延迟抖动。FSxN 的容量池选择了 SSD 而不是 HDD这是压测前就明确的方向。消息队列的日志写入要求低延迟混部场景下一旦出现随机读HDD 池会成为明显瓶颈。实际测试中SSD 池配合 ONTAP 自身的缓存机制顺序写能跑出比较漂亮的带宽曲线。有一点要强调FSxN 的吞吐能力是可以通过配置动态调整的我们测试时预置了较低的基准值目的是先摸清最小配置下能跑多少。如果你在生产环境想把性能拉满可以把基准吞吐提高到 2 GB/s 甚至更高效果会直接反映在写入带宽上。3.2 部署 AutoMQ 到 EKS 的完整流程AutoMQ 在 K8s 上的部署已经有比较完整的 Helm Chart但面对 FSxN 这个特殊存储后端时有几个细节需要手动处理我按步骤记录一下。第一步先把 FSxN 挂载到每个 worker 节点。AutoMQ 的 broker 进程里维护了一个本地目录作为远端的缓存/挂载点通常建议挂载到 /mnt/automq 下。我在 /etc/fstab 里加了一行fsx-us-east-1a.example.internal:/vol1 /mnt/automq nfs4 defaults,noatime,nodiratime,rsize1048576,wsize1048576,hard,timeo600,retrans2 0 0挂载参数里值得关注的是 rsize 和 wsize。这两个值控制 NFS 单次读写请求的最大字节数调到 1 MB 能显著提升大块顺序读写的吞吐。timeo 和 retrans 是超时与重传策略在网络抖动时宁可多等一会儿也不要立刻报错所以用 hard 模式。noatime 则是消除每次读文件时的 atime 更新开销对高吞吐场景几乎必加。第二步把 AutoMQ 的 Helm Chart 拉下来修改 values.yaml 里的 storage 配置。核心是把 remote.log.storage 的实现指定为 NFS并把路径指向挂载目录。关键片段automq: storage: type: nfs mountPath: /mnt/automq subPath: broker-logs controller: storage: type: nfs mountPath: /mnt/automq subPath: controller-logs这里有个容易踩的坑AutoMQ 的 broker 和 controller 会分别写两个不同的子目录如果你把 subPath 配重复了启动时会因为目录锁冲突而失败。我的做法是给 broker 和 controller 各建一个子路径并在部署前手动 mkdir 初始化确保目录存在且属主正确。第三步通过 Helm 安装 Release滚动观察 Pod 状态。正常情况下每个 broker Pod 启动后日志里会出现 remote log storage ready 的关键字如果卡在初始化阶段多半是 NFS 挂载没生效或者目录权限不对。等三个 broker 全部 Ready 之后集群就算起来了。这时候可以用 kafka-topics.sh 建一个测试 topic手动生产几条消息验证链路通不通。顺手记录了 broker 启动时间和 topic 创建时间整体在 2 分钟内完成说明 AutoMQ 的无状态架构确实把部署复杂度降下来了。3.3 压测参数设计与基准指标压测工具选的是 OpenMessaging Benchmark这个框架对 Kafka 协议兼容的支持很好能精准模拟生产者的 ACK 机制和消费者的提交逻辑。它的核心优势在于可以统一控制并发线程数、消息大小、目标吞吐和持续时间并且自动统计 TP50/TP99/TP999 延迟省去了自己写脚本采集数据的麻烦。我设计的压测场景分了三组基准写入1 个 topic12 个 partition3 个 producer 线程每条消息 1 KB持续 30 分钟目标吞吐 100 MB/s。峰值压力同样的 topic把 producer 增加到 12 线程消息大小提高到 4 KB目标吞吐拉高到 400 MB/s观察系统在接近存储上限时的表现。消费读取与端到端延迟12 个 producer 12 个 consumer消息大小 1 KB持续 20 分钟重点记录 end-to-end latency 和 consumer lag。每个场景之间留了 5 分钟的冷却时间让 FSxN 的缓存有充分时间回写和稳定避免上一个场景的 IO 压力残留在下一个测试里。压测期间通过 CloudWatch 监控 FSxN 的 IOPS、吞吐、数据写入速率以及 EKS 节点上的 CPU、内存、网络指标把两边数据对齐起来看。这里插一句经验压测时长不能太短。我见过很多人压 3 分钟就下结论结果 FSxN 的 burst 能力还没用完就开始回落拿到的峰值数据在生产环境根本复现不了。至少跑 30 分钟让系统进入稳态再读数据才可信。4. 性能数据解读与分析4.1 吞吐与延迟的整体表现先看最核心的数字。在基准写入场景下AutoMQ 在 FSxN 上的稳定吞吐为 95 MB/s 左右TP99 写入延迟在 8 ms 上下几乎没有出现明显的毛刺。这个数据说明什么可以对照一下自建 Kafka 加本地 SSD 的常见表现本地盘写入 IO 延迟是 μs 级但一旦涉及页缓存刷盘、磁盘碎片化、以及 Kafka 自身的副本同步TP99 往往也会被拖到 ms 级以上。AutoMQ 因为没有 Kafka 那种 ISR 多副本同步写机制写入路径更短配合远端 FSxN 的稳定带宽整体延迟其实不比本地盘差多少。峰值压力场景下把并发提到 12 线程、消息 4 KB 后系统吞吐爬到了 380 MB/s 左右FSxN 的写入带宽在 CloudWatch 里看到最大值约 1.1 GB/s。这里有一个细节值得说AutoMQ broker 的 CPU 使用率在峰值时到了 75% 左右瓶颈主要在协议解析和网络中断处理存储侧并没有打满。说明在这个配置下计算层成了主导因素存储层仍然有富余。如果继续往上压优先扩容 broker 节点数会比加 FSxN 吞吐更有效。消费端的表现同样关键。端到端延迟在低并发下稳定在 12 ms 左右峰值时 P99 上升到 25 ms没有出现消费者长时间 lag 的情况。AutoMQ 的消费机制是直接从远端读取 segment 文件FSxN 的缓存在这里起了很好的降温作用。热数据被反复消费时ONTAP 的缓存命中率很高实际回源到 SSD 池的数据远低于总读取量。这些数据放在一起可以得出一个明确结论AutoMQ 的架构瓶颈分布很健康存储层、计算层、网络层都能在合理范围内协同工作没有出现某一层成为断崖式短板的情况。4.2 不同读写比例对性能的影响生产环境的负载从来不是纯写、纯读更多是混合读写。我额外设计了一组对比测试把读写比例从 7:3 调到 5:5再到 3:7观察系统的吞吐和延迟变化。测试结果如下表所示读写比例总吞吐 (MB/s)写入 TP99 (ms)读取 TP99 (ms)7:33209145:528012183:72401522可以看到随着读比例上升总吞吐下降但下降幅度是可控的且写入和读取延迟都在合理区间。这背后的机制有两层一是 FSxN 在混合负载下能通过 ONTAP 的 FlexGroup 机制把 IO 分散到多个 volume 上降低单点锁竞争二是 AutoMQ 对读操作做了本地缓存消费者读过的数据如果还在 broker 的 page cache 里就不会穿透到 NFS。实际上读取那一路大部分流量都被 page cache 吸收了真正打到 FSxN 的读 IO 远低于预期。不过要注意一个边界情况如果消费者的消费位点非常分散比如多个 consumer 在补数据读请求会随机穿透到远端文件系统。这种场景下 FSxN 的随机读能力会弱于顺序写单文件系统的 IOPS 会成为限制因素。解决办法是多建几个 FSxN volume把不同的 topic 日志目录分散到不同的 volume 上让 IO 压力从单 volume 摊开实测可以把读吞吐重新拉回到接近纯写水平。4.3 与本地盘/裸 EBS 方案的横向对比很多人会问AutoMQ 用 FSxN 和直接用 EBS 本地盘差异到底有多大我拿之前的经验做个横向对比数据来源是在相同规格 EC2 上分别部署 AutoMQEBS gp3 作为缓存盘和自建 Kafka本地 SSD的历史压测记录。从写入吞吐看本地 SSD 场景下 Kafka 能跑到 400 MB/s 以上AutoMQ 用 gp3 时可以跑到 350 MB/s 左右AutoMQ 用 FSxN 的最优结果约 380 MB/s三者差距在 10% 以内。但从弹性角度看差距就大了本地盘方案扩容时需要重新做数据迁移和分区重平衡动辄几十分钟FSxN 方案只需要新开 broker 节点挂载同一个文件系统数据天然就在那里扩缩容缩短到分钟级。延迟方面本地盘的优势在于极致的 P99普遍能到 2-3 msFSxN 大概在 8-12 ms。如果你对延迟极其敏感比如高频交易场景那本地盘还是首选。但大多数业务场景比如日志采集、订单消息、削峰填谷8-12 ms 的延迟完全在可接受范围内换来的是运维复杂度和成本的大幅下降。成本维度更能说明问题。自建 Kafka 集群的数据副本数通常是 3存储成本就是实际数据量的 3 倍AutoMQ 没有 ISR 副本机制一份数据只在 FSxN 上存一份FSxN 自带高可用和快照可靠性由存储层保证。按 1 TB 实际数据计算自建 Kafka 用 gp3 的成本大约是 AutoMQFSxN 的 1.8 倍。这个数字在数据量越大的场景下越夸张如果你有几十 TB 的日志数据节省的成本会是相当可观的。5. 实操踩坑与调优心得5.1 NFS 挂载阶段的常见问题整个测试过程里我遇到最多的问题集中在 NFS 挂载这一层尤其是第一次挂载时 FSxN 的 DNS 解析上。FSxN 的挂载地址是一个形如 fs-xxxxxxxxxxx.fsx.us-east-1.amazonaws.com 的域名在 VPC 内通过 Route 53 解析到实际的 ENI 地址。如果你在 EKS worker 节点的安全组里没有放通出站到 FSxN 的 2049 端口挂载命令会一直卡在 timeout 状态日志里看不到任何有效报错排查起来非常迷惑。判断方法其实很简单先手动执行 mount 命令看返回再用 telnet 或者 nc 测试 2049 端口通不通。如果端口不通去看安全组和网络 ACL 的出站规则大概率是这里的问题。我在测试环境里就吃过一次亏安全组只配了入站规则出站规则被默认拒绝导致挂载一直失败。这个问题在文档里很不起眼但实际踩中的人不在少数。另一个常见问题是挂载参数中的 hard 和 soft 模式选择。测试阶段我一度用 soft 模式因为网络闪断时会给应用返回错误而不是阻塞但实测下来NFS soft 模式在重试几次失败后会让 AutoMQ 的写入线程收到 EIO 错误导致 segment 发布中断。换成 hard 模式后NFS 会在网络恢复后自动重放未完成的请求对消息队列这种要求强一致性的场景更可靠。代价是如果 FSxN 长时间不可用broker 线程会阻塞但这是合理的——宁可线程阻塞等存储恢复也不能让数据写一半就报错。5.2 FSxN 容量与吞吐规划建议测试中我发现一个容易忽略的事实FSxN 的吞吐能力不只是由预配置的基准值决定的还和文件系统的 volume 数量有关。ONTAP 的 FlexGroup 会把数据分布在多个 constituent volume 上单 volume 的吞吐上限决定了单目录的性能天花板。如果你的 AutoMQ 数据目录很大且集中在一个 volume 上即使整个 FSxN 显示还有大量吞吐余量单 volume 也可能会先到瓶颈。规划建议是先按 topic 的重要程度和分区数量做目录分组不要让所有数据落在一个顶层目录下。我这次测试实际上是把 12 个 partition 的日志分到了 3 个不同的子目录每个目录对应 4 个 partition对应的是 3 个 volume。这样做的收益是多 volume 并行承载 IO分散热点实测下来比单 volume 提升了约 30% 的读写吞吐。容量方面AutoMQ 在 FSxN 上的数据增长是平滑的因为旧数据会被定期归档并删除本地索引。你要预估的不是消息总量而是消息总量在滚动窗口内的峰值。FSxN 的容量池可以动态扩容但如果一开始就把初始容量设得很小ONTAP 在扩容时可能需要几分钟的数据迁移时间这期间会有额外的 IO 开销。建议初始容量比预估峰值多 30% 以上给未来两个月的增长留出缓冲。5.3 从压测结果反推生产配置结合这轮压测数据我整理了三条可以用在生产环境的参考配置。第一broker 节点实例规格选择 r6i.xlarge 或以上。压测中 8 vCPU 的节点在 380 MB/s 写入时 CPU 已经到了 75%如果再叠加消费者连接和协议解析性能余量会偏紧。生产环境建议每个 broker 至少 16 vCPU留出 50% 以上的 CPU 余量给流量高峰宁可多开一两个节点也不要让 CPU 接近 100% 运行。第二FSxN 的基准吞吐建议按峰值吞吐的 1.5 倍来配置。压测中单文件系统跑到 1.1 GB/s 时接近了预配置的上限如果峰值不降低实测吞吐就会开始波动。把基准吞吐调到 1.5-2 GB/s弹性余量才够。第三AutoMQ 的 broker 本地缓存磁盘用 gp3 即可不要上 io2。AutoMQ 的写路径最终会落盘到远端本地缓存只是临时的 page cache 角色不需要太高的 IOPS 保障。用 gp3 自带的基础性能就足够把资源放在真正的瓶颈点——网络和内存上。6. 常见问题速查表问题现象可能原因解决方式NFS 挂载卡在 timeout安全组/网络 ACL 未放通 2049 端口检查 worker 节点到 FSxN 的端口连通性broker 启动后日志提示目录锁冲突broker 和 controller 的 subPath 重复分别指定不同子目录手动初始化目录属主写入吞吐突然骤降NFS 挂载参数 wsize 过小把 wsize/rsize 调整到 1048576P99 延迟周期性上涨FSxN 弹性吞吐触发扩容预配置更高基准吞吐值避免动态扩容抖动consumer lag 持续累积读请求随机穿透导致单 volume IOPS 瓶颈将日志分散到多个 volume 上摊开读压力压测数据前后差异大压测时长不足未进入稳态至少跑 30 分钟取峰值的后 80% 数据broker CPU 满载但存储未打满broker 实例规格偏小升级到 r6i.xlarge 或增加 broker 节点数冷数据消费时延迟很高数据被 ONTAP 分层到了 S3回源耗时调整分层策略将热点数据保留在 SSD 池7. 最后的经验总结这轮 AutoMQ 与 FSxN 的组合测试我的核心体会是云原生架构下存储选型和架构设计同样决定着最终效果。AutoMQ 把 Kafka 的存储逻辑从节点本地剥离出来FSxN 用稳定的 NFS 性能和灵活容量把这个位置接住了两者的结合在吞吐、延迟、弹性三个维度上都表现稳定。对于一个以秒级扩缩容为卖点的系统存储层能否快速响应扩容请求非常重要——FSxN 多 volume 的并行 IO 能力和容量池的动态调整让 AutoMQ 在横向扩容时不用等数据重平衡秒级生效才真正成为可能。如果你打算在生产环境复现这套方案我的建议很直接不要照搬我的压测参数先按自己的消息大小、partition 数量、读写比做一个小规模验证再逐步放大。AutoMQ 的部署已经很轻量从 3 节点起步验证成本很低但换存储后端后的调优细节比如挂载参数、subPath 规划、volume 分组是绕不开的功课。从我的实际体验来看AutoMQ 的架构方向是对的。消息队列的下一阶段不会再把计算和存储绑死在一个节点里把日志统一放到可水平扩展的企业级存储上通过共享文件系统或对象存储来承载数据替换掉昂贵的物理副本这条路在成本和运维复杂度上的优势会越来越明显。FSxN 是目前 AWS 上将文件语义、高性能与高可用结合得最完整的托管服务之一和 AutoMQ 搭在一起至少让我在规划未来的消息队列选型时又多了一个可靠性很高、上限很充足的答案。