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 API,AutoMQ 的很多内部逻辑——比如创建临时文件、写满后原子发布、读取时按文件路径定位——都需要重写或者打补丁。
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.2xlarge(8 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,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 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 个 topic,12 个 partition,3 个 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:3 | 320 | 9 | 14 |
| 5:5 | 280 | 12 | 18 |
| 3:7 | 240 | 15 | 22 |
可以看到,随着读比例上升,总吞吐下降,但下降幅度是可控的,且写入和读取延迟都在合理区间。这背后的机制有两层:一是 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 上分别部署 AutoMQ(EBS gp3 作为缓存盘)和自建 Kafka(本地 SSD)的历史压测记录。
从写入吞吐看,本地 SSD 场景下 Kafka 能跑到 400 MB/s 以上,AutoMQ 用 gp3 时可以跑到 350 MB/s 左右,AutoMQ 用 FSxN 的最优结果约 380 MB/s,三者差距在 10% 以内。但从弹性角度看差距就大了:本地盘方案扩容时需要重新做数据迁移和分区重平衡,动辄几十分钟;FSxN 方案只需要新开 broker 节点,挂载同一个文件系统,数据天然就在那里,扩缩容缩短到分钟级。
延迟方面,本地盘的优势在于极致的 P99,普遍能到 2-3 ms;FSxN 大概在 8-12 ms。如果你对延迟极其敏感,比如高频交易场景,那本地盘还是首选。但大多数业务场景,比如日志采集、订单消息、削峰填谷,8-12 ms 的延迟完全在可接受范围内,换来的是运维复杂度和成本的大幅下降。
成本维度更能说明问题。自建 Kafka 集群的数据副本数通常是 3,存储成本就是实际数据量的 3 倍;AutoMQ 没有 ISR 副本机制,一份数据只在 FSxN 上存一份(FSxN 自带高可用和快照,可靠性由存储层保证)。按 1 TB 实际数据计算,自建 Kafka 用 gp3 的成本大约是 AutoMQ+FSxN 的 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 调整到 1048576 |
| P99 延迟周期性上涨 | 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 搭在一起,至少让我在规划未来的消息队列选型时,又多了一个可靠性很高、上限很充足的答案。