Redis vs DynamoDB vs DAX:我对 AWS 缓存性能进行了基准测试(结果出乎意料)
Source: Dev.to
抱歉,我需要您提供要翻译的具体文本内容。请将文章的正文粘贴在这里,我会按照要求将其翻译成简体中文,并保留原始的格式、Markdown 语法以及代码块和 URL。谢谢!
对 DynamoDB 读取进行内存缓存基准测试
在许多后端系统中,用户数据几乎在每一次请求时都会被获取。一个常见的假设是,加入内存缓存能够提升任何系统的读取性能。
为了验证这一假设,我在无服务器架构下对三种访问 DynamoDB 中用户数据的方法进行了基准测试:
| 方法 | 描述 |
|---|---|
| Baseline | AWS Lambda + DynamoDB(无缓存) |
| Cache‑aside | Lambda → Redis → DynamoDB |
| DAX | Lambda → DynamoDB Accelerator(DAX) → DynamoDB |
目标是判断一家初创公司的 CTO 是否应该在缓存服务上投入。我原本预期缓存方案能够轻松超越基线,但即使在 200 请求/秒(12 000 请求/分钟)的负载下,这一假设也未能成立。
实验设置
所有三个测试的架构尽可能保持一致——使用 eu‑central‑1 AWS 区域中最便宜的可用选项。
1. 基线(DDB + Lambda)
| 组件 | 配置 |
|---|---|
| Lambda | Python 3.12,256 MiB 内存,10 秒超时 |
| DynamoDB | 按请求计费模式 |
| 访问模式 | 直接从 DynamoDB 读取(无缓存) |
| 延迟 | 最高(无缓存) |
2. DAX(DynamoDB Accelerator)
| 组件 | 配置 |
|---|---|
| Lambda | Python 3.12,256 MiB 内存,10 秒超时 |
| DAX 集群 | dax.t3.small(单节点,复制因子 = 1),部署在 VPC 隔离子网中 |
| 缓存 | 由 DAX 自动管理(默认项 TTL ≈ 5 分钟,查询缓存 TTL ≈ 5 分钟) |
| 访问模式 | Lambda → DAX → DynamoDB |
| 客户端 | amazondax Python 客户端(通过 pip 安装) |
3. Redis(AWS ElastiCache)
| 组件 | 配置 |
|---|---|
| Lambda | Python 3.12,256 MiB 内存,10 秒超时 |
| Redis 集群 | cache.t4g.micro(单节点,无自动故障转移),部署在 VPC 隔离子网中 |
| 缓存 TTL | 30 秒(可通过 REDIS_TTL_SECONDS 配置) |
| 访问模式 | 1️⃣ Lambda 首先检查 Redis 2️⃣ 未命中 → 从 DynamoDB 读取,并以 30 秒 TTL 存入 Redis 3️⃣ 命中 → 返回缓存数据 |
| 客户端 | 标准 redis-py 客户端,连接超时 1 秒 |
测试方法论
- 负载水平 – 50 reads / s(3 000 reads / min)和 200 reads / s(12 000 reads / min)。
- 负载 – 所有运行使用相同大小,采用热点/混合键分布。
- 指标 – 第95百分位延迟(p95)。
- 工具 – 开源负载测试库 k6(JavaScript 脚本)。
所有三种方法都获取了相同的 DynamoDB 项,例如:
{
"pk": "ITEM#123",
"sk": "META",
"itemId": "123",
"title": "Example Item Title",
"body": "This is the body content of the item",
"updatedAt": 1736467200,
"etag": "a7f8d9e1c2b3a4f5e6d7c8b9a0f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c6b7a8f9"
}
结果 – 50 RPS(建立基准)
| Access Pattern | p95 Latency (ms) | Avg Latency (ms) | Dropped Iterations | Notes |
|---|---|---|---|---|
| Lambda + DynamoDB(基准) | ~63 | ~48 | 0 | 快速、稳定、无瓶颈 |
| Redis(热身运行) | ~68 | ~66 | 22 | 缓存未命中 + 写回成本 |
| Redis(稳态) | ~63 | ~48 | 0 | 与基准相匹配,无延迟提升 |
| DAX(单个小节点) | ~1040 | ~957 | 19 | 缓存饱和,无法使用 |
解释
- 基准 – 在 50 RPS 下,Lambda + DynamoDB 组合实现了约 63 ms 的 p95 延迟,且无丢失。按需 DynamoDB 并未承受压力。
- Redis – 第一次(热身)运行出现缓存未命中,导致延迟升高。缓存预热后,延迟与基准相同,但没有提升。
- DAX – 过小的
dax.t3.small节点出现 CPU 受限,导致请求排队,p95 延迟 > 1 秒。这表明缓存尺寸不当会降低性能。
结论(50 RPS)
基准表现出色,且无需额外缓存。添加 Redis 虽然降低了 DynamoDB 的负载,但未带来可测量的延迟优势。尺寸不足的 DAX 则适得其反。
结果 – 200 RPS(未出现的预期交叉点)
| 访问模式 | p95 延迟 (ms) | 平均延迟 (ms) | 丢失的迭代次数 | 备注 |
|---|---|---|---|---|
| Lambda + DynamoDB(基线) | ~63 | ~48 | 13 | 稳定,线性扩展 |
| Redis(热运行) | ~64 | ~52 | 40 | 负载下缓存填充 |
| Redis(稳态) | ~70 | ~58 | 79 | 略逊于基线 |
| DAX(单个小节点) | ~1050 | ~968 | 5 399 | 集群饱和 |
解释
- 基线 – 即使在 200 RPS 时,Lambda + DynamoDB 仍保持约 63 ms 的 p95 延迟,验证了其可扩展性。
- Redis – 再次显示出两个阶段。热身运行产生未命中延迟;稳态运行略慢于基线,可能是由于额外的网络跳数以及负载下偶发的缓存未命中。
- DAX – 单个小节点完全饱和,导致延迟极高并出现数千次迭代丢失。
结论(200 RPS)
基线仍是性能最佳、最简洁的方案。Redis 在此负载下并未提供延迟优势,而尺寸不足的 DAX 集群会显著恶化性能。
总体要点
- Baseline Lambda + DynamoDB 往往已足够 – 按需计费和自动扩展即使在 200 RPS 时也能保持低延迟。
- Cache‑aside Redis 可以减轻 DynamoDB 的读取压力,但会增加网络跳数;除非读写比例极高或对延迟有更严格的 SLA,否则可能并不会提升响应时间。
- DAX 并非即插即用的加速器 – 必须做好容量规划;节点规模不足会成为瓶颈。
- 只有在以下情况下缓存才有意义
- 读写比例极高(例如 > 100:1)。
- 延迟要求低于 10 ms,而基线无法满足。
- 工作负载表现出强烈的时间局部性,值得为此承担额外的运维复杂度。
对于大多数流量较小(≤ 200 RPS)的初创公司来说,最简单的架构——Lambda 直接查询 DynamoDB——能够提供最佳的成本‑性能平衡。是否加入缓存应基于具体的延迟或成本降低目标,而不是“缓存总是有帮助”的假设。
缓存预热与 Redis 稳定性
缓存预热后,Redis 稳定下来,但并未超越基线。在稳态下:
- p95 延迟 稍微上升至约 70 ms。
- 丢失的迭代次数 多于仅使用 DynamoDB 的情况。
DAX @ 200 RPS: 负载下的饱和
- 有效吞吐量远低于目标速率。
- p95 延迟 超过了一秒。
- 成千上万的迭代被丢弃。
此行为表明 DAX 对规模高度敏感——较小的实例根本没有任何优势。
结论:200 RPS
即使在 200 RPS 时,该系统的主要成本不是数据库访问,而是网络和托管服务开销。添加缓存并没有消除该成本——它反而增加了成本,因为您仍需为按需或无服务器的 Redis 实例付费,具体取决于您的选择。
这些结果实际上证明了什么
- DynamoDB on‑demand 在简单读取场景下的扩展性极佳。
- Redis 减轻了数据库的压力,但并不降低延迟。
- Cache warm‑up 很重要。
- 错误配置的 DAX 比没有缓存更糟。
- Latency optimization 与 scaling optimization 是不同的问题。
结论与经验教训
两组 50 RPS 和 200 RPS 基准测试的结果得出了一个明确且有些违背直觉的结论:对于此工作负载,使用 DynamoDB 按需模式的 Lambda 已经足够快,添加缓存并未提升用户可感知的延迟。
- 在两种负载水平下,DynamoDB 不是瓶颈。
- 端到端延迟主要受 网络距离 和 托管服务开销 主导,而不是数据库访问时间。
- 引入 Redis 增加了额外的网络跳数和客户端开销,却没有消除请求路径中占主导的成本。
Redis 仍然有其用途,但不是最初预期的那样。它减轻了对 DynamoDB 的压力,平滑了后端负载,这对成本控制和未来扩展可能有价值。但在这些流量水平下,它并没有让请求更快。
DAX 要点
- 当规模不足时,DAX 根本帮不上忙;它很快饱和,导致延迟增加和请求被丢弃。
- 它需要仔细的容量规划和对工作流的深入理解。
最后思考
这个实验最大的教训是 在优化之前先进行测量 是必不可少的。即使缓存可以减轻后端负载,也不一定会自动降低端到端延迟。
如果工作流过于简单,缓存的好处可能不可见。然而,当你有一个耗时的操作且其结果可以被缓存时,缓存值得测试。
简而言之: 不要因为感觉对就缓存——要因为数据证明你需要它才缓存。