Redis vs DynamoDB vs DAX:我对 AWS 缓存性能进行了基准测试(结果出乎意料)

发布: (2026年2月2日 GMT+8 16:00)
11 分钟阅读
原文: Dev.to

Source: Dev.to

抱歉,我需要您提供要翻译的具体文本内容。请将文章的正文粘贴在这里,我会按照要求将其翻译成简体中文,并保留原始的格式、Markdown 语法以及代码块和 URL。谢谢!

对 DynamoDB 读取进行内存缓存基准测试

在许多后端系统中,用户数据几乎在每一次请求时都会被获取。一个常见的假设是,加入内存缓存能够提升任何系统的读取性能。

为了验证这一假设,我在无服务器架构下对三种访问 DynamoDB 中用户数据的方法进行了基准测试:

方法描述
BaselineAWS Lambda + DynamoDB(无缓存)
Cache‑asideLambda → Redis → DynamoDB
DAXLambda → DynamoDB Accelerator(DAX) → DynamoDB

目标是判断一家初创公司的 CTO 是否应该在缓存服务上投入。我原本预期缓存方案能够轻松超越基线,但即使在 200 请求/秒(12 000 请求/分钟)的负载下,这一假设也未能成立。

实验设置

所有三个测试的架构尽可能保持一致——使用 eu‑central‑1 AWS 区域中最便宜的可用选项。

1. 基线(DDB + Lambda)

组件配置
LambdaPython 3.12,256 MiB 内存,10 秒超时
DynamoDB按请求计费模式
访问模式直接从 DynamoDB 读取(无缓存)
延迟最高(无缓存)

2. DAX(DynamoDB Accelerator)

组件配置
LambdaPython 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)

组件配置
LambdaPython 3.12,256 MiB 内存,10 秒超时
Redis 集群cache.t4g.micro(单节点,无自动故障转移),部署在 VPC 隔离子网中
缓存 TTL30 秒(可通过 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 Patternp95 Latency (ms)Avg Latency (ms)Dropped IterationsNotes
Lambda + DynamoDB(基准)~63~480快速、稳定、无瓶颈
Redis(热身运行)~68~6622缓存未命中 + 写回成本
Redis(稳态)~63~480与基准相匹配,无延迟提升
DAX(单个小节点)~1040~95719缓存饱和,无法使用

解释

  • 基准 – 在 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~4813稳定,线性扩展
Redis(热运行)~64~5240负载下缓存填充
Redis(稳态)~70~5879略逊于基线
DAX(单个小节点)~1050~9685 399集群饱和

解释

  • 基线 – 即使在 200 RPS 时,Lambda + DynamoDB 仍保持约 63 ms 的 p95 延迟,验证了其可扩展性。
  • Redis – 再次显示出两个阶段。热身运行产生未命中延迟;稳态运行略慢于基线,可能是由于额外的网络跳数以及负载下偶发的缓存未命中。
  • DAX – 单个小节点完全饱和,导致延迟极高并出现数千次迭代丢失。

结论(200 RPS)

基线仍是性能最佳、最简洁的方案。Redis 在此负载下并未提供延迟优势,而尺寸不足的 DAX 集群会显著恶化性能。

总体要点

  1. Baseline Lambda + DynamoDB 往往已足够 – 按需计费和自动扩展即使在 200 RPS 时也能保持低延迟。
  2. Cache‑aside Redis 可以减轻 DynamoDB 的读取压力,但会增加网络跳数;除非读写比例极高或对延迟有更严格的 SLA,否则可能并不会提升响应时间。
  3. DAX 并非即插即用的加速器 – 必须做好容量规划;节点规模不足会成为瓶颈。
  4. 只有在以下情况下缓存才有意义
    • 读写比例极高(例如 > 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 optimizationscaling optimization 是不同的问题。

结论与经验教训

两组 50 RPS 和 200 RPS 基准测试的结果得出了一个明确且有些违背直觉的结论:对于此工作负载,使用 DynamoDB 按需模式的 Lambda 已经足够快,添加缓存并未提升用户可感知的延迟。

  • 在两种负载水平下,DynamoDB 不是瓶颈。
  • 端到端延迟主要受 网络距离托管服务开销 主导,而不是数据库访问时间。
  • 引入 Redis 增加了额外的网络跳数和客户端开销,却没有消除请求路径中占主导的成本。

Redis 仍然有其用途,但不是最初预期的那样。它减轻了对 DynamoDB 的压力,平滑了后端负载,这对成本控制和未来扩展可能有价值。但在这些流量水平下,它并没有让请求更快。

DAX 要点

  • 当规模不足时,DAX 根本帮不上忙;它很快饱和,导致延迟增加和请求被丢弃。
  • 它需要仔细的容量规划和对工作流的深入理解。

最后思考

这个实验最大的教训是 在优化之前先进行测量 是必不可少的。即使缓存可以减轻后端负载,也不一定会自动降低端到端延迟。

如果工作流过于简单,缓存的好处可能不可见。然而,当你有一个耗时的操作且其结果可以被缓存时,缓存值得测试。

简而言之: 不要因为感觉对就缓存——要因为数据证明你需要它才缓存。

Back to Blog

相关文章

阅读更多 »