Redis + AOF + 分布式存储:警示性基准测试
抱歉,我需要您提供要翻译的完整文本(除代码块和 URL 之外的内容),才能为您进行简体中文翻译。请将文章的正文粘贴在这里,我会保持原有的格式、Markdown 语法以及技术术语不变,只翻译正文部分。谢谢!
概览
我们在本地 SSD SAS 和 Longhorn 上通过 9 种配置对 AOF 持久化进行了测试。结果是决定性的。
在为生产环境迁移到裸金属 Kubernetes 设计缓存层时,我们遇到了一个看似简单却代价高昂的问题:Redis 的 AOF 持久化是否应该放在 Longhorn 分布式存储上?
Redis 文档对答案有所暗示,但直觉和文档并不等同于生产数据。因此,我们在九种配置下运行 redis‑benchmark——变更存储后端、持久化设置和数据集大小——并对影响进行实证测量。
结果毫无歧义,尤其有一个数字值得每位架构师深思。
测试配置
All tests used the same parameters throughout:
requests: 50,000
clients: 20 parallel
payload: 180,000 bytes (~180 KB)
pipeline: keep-alive=1
thread: single‑threaded
The 180 KB payload is intentional—it reflects realistic cache object sizes for the production workload being benchmarked, not the micro‑payload tests commonly seen in vendor benchmarks.
九种环境测试
| 标签 | 存储 | AOF | RDB | 数据集 |
|---|---|---|---|---|
| 本地 · AOF 关闭 | 本地 SSD SAS | 否 | 阈值 | 空 |
| 本地 · AOF 开启(基线) | 本地 SSD SAS | 是 | 阈值 | 空 |
| 本地 · AOF 开启(调优 1) | 本地 SSD SAS | 是 | 阈值 | 空 |
| 本地 · AOF 开启(调优 2) | 本地 SSD SAS | 是 | 阈值 | 空 |
| 本地 · AOF 开启(t2 + 数据) | 本地 SSD SAS | 是 | 阈值 | 375,795 键 |
| Longhorn · AOF 开启(空) | Longhorn | 是 | 阈值 | 空 |
| Longhorn · AOF 开启(数据) | Longhorn | 是 | 阈值 | 375,795 键 |
SET 吞吐量:核心发现
对可写缓存而言,最重要的指标是 负载下的 SET 吞吐量。
| 配置 | SET RPS | SET 平均延迟 | SET p99 延迟 |
|---|---|---|---|
| 本地 · AOF 关闭 | 7,696 | 1.47 ms | 5.12 ms |
| 本地 · AOF 开启(基线) | 1,275 | 14.39 ms | 102.53 ms |
| 本地 · AOF 开启(调优 1) | 1,251 | 15.03 ms | 105.92 ms |
| 本地 · AOF 开启(调优 2) | 1,248 | 15.03 ms | 112.38 ms |
| 本地 · AOF 开启(t2 + 375K 键) | 1,212 | 15.85 ms | 121.15 ms |
| Longhorn · AOF 开启(空) | 577 | 33.56 ms | 225.66 ms |
| Longhorn · AOF 开启(375K 键) | 537 | 36.17 ms | 201.86 ms |
要点:
- 本地 SSD SAS,AOF 已禁用:7,696 SET RPS,p99 ≈ 5 ms。
- Longhorn,AOF 已启用:537 SET RPS,p99 ≈ 202 ms。
这意味着 吞吐量相差 14.3 倍,而 p99 延迟相差 39 倍——在相同的应用代码、相同的 Redis 版本、相同的客户端下。Longhorn 上最坏情况下的单次 SET 达到 903 ms。
本地存储上的 AOF 障碍
即使在高速本地 SSD SAS 上,AOF 也会带来巨大的性能惩罚。
| 指标 | AOF 关闭(仅 RDB) | AOF 开启 |
|---|---|---|
| SET p99 延迟 | 3.8–5.1 ms | 102–121 ms |
| SET 平均延迟 | ~1.5 ms | 14–16 ms |
仅在本地 SSD SAS 上,AOF 就会导致 约 20 倍的 p99 延迟惩罚,而调优几乎没有帮助:
Baseline: 102.5 ms p99
Tuning 1: 105.9 ms p99
Tuning 2: 112.4 ms p99 ← 实际上更糟
为什么?
使用 appendfsync everysec 的 AOF 会强制每秒至少执行一次 fsync()。在处理 180 KB 负载的繁忙单线程 Redis 实例中,这次 fsync 停顿主导了延迟预算。你无法通过调优来绕过它。
为什么 Longhorn 会导致 AOF 灾难性
Longhorn 是一个用于 Kubernetes 的分布式块存储系统,通过在节点之间复制数据来实现持久性。这对于 写入模式受控 的工作负载效果良好,但 Redis AOF 是 连续的、小的、对延迟敏感 的:
- 每一次 AOF 追加都要经过网络到达 Longhorn 控制器。
- 控制器在确认之前会将写入复制到 N 个副本。
- 只有在收到确认后,Redis 才会得到它的
fsync确认。 - Redis 是单线程的,因此会阻塞等待这一次往返。
结果:每一次 SET 都要付出一次网络往返的代价 加上 多副本写入确认的开销。以 180 KB 的负载为例,这种惩罚会急剧上升。
Redis 文档有警告:
“避免在 I/O 路径中存在网络延迟的存储上存放 AOF/RDB 文件,例如 NFS 挂载。”
Longhorn 实际上就是这样一种网络复制的卷。我们的基准测试量化了这一警告:最高延迟 903 ms,p99 为 202 ms。
GET 性能
读取延迟受持久化设置的影响很小,因为 GET 不会写入 AOF 日志。
| 配置 | GET RPS | GET avg latency |
|---|---|---|
| Local · AOF off | 8,027 | 1.47 ms |
| Local · AOF on (baseline) | 2,537 | 4.29 ms |
| Longhorn · AOF on (375K keys) | 2,522 | 4.21 ms |
Longhorn 与本地开启 AOF 的存储相比,并未显著降低 GET 性能,不会显著退化 GET 性能,这表明瓶颈在于持久化写入路径。
PING 延迟:基准
PING 吞吐量展示了在没有持久化的情况下的开销。
| 配置 | PING RPS | PING 平均延迟 |
|---|---|---|
| 本地 · AOF 关闭 | ~37,000 | 0.32 ms |
| 本地 · AOF 开启(基准) | 11,000–18,000 | 0.84–1.50 ms |
| Longhorn · AOF 开启 | 19,000–21,000 | 0.74–0.83 ms |
有趣的是,Longhorn 上的 PING 性能 更好,超过了基准下本地开启 AOF 时的表现。Longhorn 的惩罚仅在 Redis 实际需要写入 AOF 日志时才会显现——这确认了瓶颈正是持久化写入路径,而非一般的 Longhorn I/O 开销。
推荐架构
基于这些结果,适用于需要持久性的写密集型缓存的正确架构如下:
- 在本地高性能 SSD(或 NVMe)存储上运行 Redis。
- 为缓存层禁用 AOF,如需持久性则依赖定期的 RDB 快照。
- 如果必须使用 AOF,请将 AOF 文件挂载在本地磁盘上,而不是网络复制卷(如 Longhorn、NFS 等)。
- 职责分离:
- 使用 Redis(或其他内存存储)作为热缓存层。
- 使用传统数据库或持久化键值存储作为持久层。
- 监控 fsync 延迟(Redis 中的
latency monitor),确保appendfsync策略不会成为隐藏的瓶颈。
分离持久化设计
热路径(主节点)
- Redis,禁用 AOF
- 仅使用 RDB 快照,设置宽松阈值(例如
save 3600 1) - 本地 SSD SAS 存储
- 结果: 7,600+ SET RPS,p99 延迟低于 5 ms
恢复路径(副本)
- Redis 副本,对应主节点
- 仅 RDB 快照 写入持久存储(此处可接受 Longhorn——快照写入不频繁且呈突发)
- 不在热写路径中
该配置在保持完整写入吞吐的同时,实现了 p99 延迟低于 5 ms,并通过副本的周期性快照保证持久性。如果主节点故障,最多只会丢失一次 RDB 快照间隔的数据——这对大多数缓存工作负载来说是可以接受的。
如果需要对每一次写入都实现真正的持久性(缓存场景极少见),正确的做法是使用其他工具——而不是在分布式存储上使用 AOF 的 Redis。
摘要
| Question | Answer |
|---|---|
| Can AOF on local SSD SAS achieve good SET latency? | No. p99 stays above 100 ms regardless of tuning. |
| Can AOF on Longhorn achieve acceptable SET latency? | No. p99 reaches 202 ms, max 903 ms. |
| Does Longhorn affect GET performance with AOF? | Minimally – GETs don’t write to AOF. |
| What’s the right architecture for high‑throughput caching? | AOF disabled on hot path, RDB replica for recovery. |
| Is the Redis documentation warning about network storage accurate? | Definitively yes. Our data confirms it. |
The 14× throughput gap between AOF‑on‑Longhorn and AOF‑off‑local is not a configuration problem; it’s an architectural mismatch. Building a fast cache on slow persistence is a contradiction – and these numbers prove it.
环境详情
- Redis 版本: 7.x
- 存储后端:
- 本地路径供应器(SSD SAS)
- Longhorn 1.6 在 Kubernetes 1.31 上
- redis‑benchmark 参数:
-n 50000 -c 20 -d 180000 --keepalive 1 - 模式: 单线程(未使用
--threads标志) - 数据集: 基线时为空;加载测试时有 375,795 个键
关于 Kubernetes 上的 Redis 架构有疑问吗?请在下方留言。
— Iwan Setiawan,混合云与平台架构师 · portfolio.kangservice.cloud