本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
适用于电子商务应用程序的亚马逊 ElastiCache (Valkey)
电子商务应用程序受益于应用程序服务器和数据库之间的内存缓存层。Amazon ElastiCache 运行 Valkey 可为经常访问的数据(产品目录条目、库存数量、搜索结果和用户会话)提供亚毫秒的读取延迟,从而减少了数据库负载,缩短了流量高峰期间的响应时间。
集群配置
根据您的数据量、吞吐量要求和操作偏好选择集群类型。
| 集群类型 | 适用于 | 扩展 | 注意事项 |
|---|---|---|---|
Serverless |
可变的流量模式、新的应用程序、没有缓存操作专业知识的团队 |
自动 — 根据需求扩展计算和内存 |
无需容量规划。可变成本模型——您按消费量付费。 |
Node-based (已启用集群模式) |
可预测的高吞吐量工作负载,需要对分片和节点类型进行精细控制 |
手动或自动缩放分片和副本 |
需要容量规划。固定成本模式——无论利用率如何,您都要为预置容量付费。每个集群最多支持 500 个节点。 |
对于大多数刚起步的电子商务应用程序,Serverless提供了最简单的生产路径。当您拥有可预测的流量基准并且需要对集群拓扑、节点类型和扩展行为进行更多控制时,可以迁移到基于节点的集群。
| 设置 | 值 | 理由 |
|---|---|---|
Engine |
最新的稳定版本 |
使用中提供的最新稳定 Valkey 版本。 ElastiCache与 Redis OSS 命令完全兼容。提供与先前版本相比的性能改进。 |
Multi-AZ |
已启用 |
如果主节点出现故障,则自动故障转移到另一个可用区中的副本。生产电子商务工作负载所必需。 |
In-transit 加密 |
已启用 (TLS) |
加密您的应用程序和缓存集群之间的数据。处理用户会话或任何 PII 的工作负载是必需的。 |
At-rest 加密 |
已启用 |
加密磁盘上的数据(备份、交换)。合规性工作负载所必需。 |
子网组 |
私有隔离子网(2 个以上的可用区) |
无法访问互联网。只能从应用程序的安全组访问。 |
产品数据的关键设计
将缓存密钥设计为可预测、可调试且范围有限的缓存密钥,以避免跨数据类型发生冲突。
| 数据类型 | 钥匙图案 | 值类型 | 示例 |
|---|---|---|---|
产品详细信息 |
|
哈希 |
|
库存数量 |
|
字符串(整数) |
|
用户会话 |
|
哈希 |
|
搜寻结果 |
|
字符串 (JSON) |
|
类别清单 |
|
列表 |
|
主要设计最佳实践:
使用冒号作为分隔符以提高可读性和工具支持。
保持密钥短 — 长密钥会消耗内存和网络带宽。
包括数据类型前缀,以避免产品、会话和其他可能共享数字 ID 的实体之间发生冲突。
对多字段对象(产品、会话)使用哈希值,允许在不检索全部值的情况下进行部分读取和更新。
按数据类型划分的 TTL 策略
在不影响客户体验的情况下,根据数据更改的频率和过时程度来设置 TTL(生存时间)值。
| 数据类型 | TTL | 失效触发器 | 理由 |
|---|---|---|---|
产品详细信息 |
5 分钟 |
卖家编辑商品 |
商品描述和图片很少更改。足够短,可以相当快地完成编辑,而不会使每次更改都明确失效。 |
库存数量 |
30 秒 |
购买或补货 |
陈旧的库存可能会导致超卖。TTL 非常短,可确保频繁刷新计数。购买时明确宣布无效,以确保即时准确。 |
搜寻结果 |
60 秒 |
无(TTL-based 仅) |
搜索索引会定期更新。缓存减少了搜索引擎的负载。新产品在 60 秒内出现,且未明确失效。 |
用户会话 |
24 小时 |
注销或会话到期 |
会话在浏览期间持续存在。刷新每次访问的 TTL 以保持活动会话处于活动状态。注销时明确删除。 |
类别清单 |
2 分钟 |
类别 added/removed 中的产品 |
分类页面的流量很高。简短缓存大大减少了浏览期间的数据库查询。 |
Cache-aside 图案
缓存旁模式(也称为延迟加载)是电子商务应用程序最常见的缓存策略。您的应用程序首先检查缓存,并且仅在缓存未命中时才查询数据库。
读取路径(伪代码)
FUNCTION getProduct(productId): cacheKey = "product:" + productId // Step 1: Check the cache cachedValue = cache.GET(cacheKey) IF cachedValue exists: RETURN deserialize(cachedValue) // Cache hit — sub-millisecond // Step 2: Cache miss — query database product = database.query("SELECT * FROM products WHERE id = ?", productId) IF product not found: RETURN null // Step 3: Write to cache with TTL cache.SET(cacheKey, serialize(product), EXPIRE = 300) // 5 minutes RETURN product
写入路径(伪代码)
FUNCTION updateProduct(productId, updatedFields): // Step 1: Update the database (source of truth) database.update("UPDATE products SET ... WHERE id = ?", updatedFields, productId) // Step 2: Invalidate the cache (don't update it) cache.DELETE("product:" + productId) // Next read will trigger a cache miss and repopulate from database
重要
写入时务必使缓存失效(删除),而不是更新缓存。这缩短了过时读取覆盖新值的竞争条件的窗口。下一次读取将重新填充数据库中的缓存,这是事实的来源。请注意,狭义的竞争条件仍然存在——如果并发读取在写入之前从数据库中获取数据,则在删除缓存密钥之后,它可能会在缓存密钥被删除后用过时的数据重新填充缓存。对于大多数电子商务工作负载来说,较短的 TTL 可以接受。如果您需要严格的一致性,请使用分布式锁或版本化写入。
处理缓存故障
FUNCTION getProductWithFallback(productId): TRY: RETURN getProduct(productId) // Normal cache-aside path CATCH cacheConnectionError: // Cache is unavailable — fall back to database directly RETURN database.query("SELECT * FROM products WHERE id = ?", productId) // Log the error, trigger an alarm, but don't fail the request
设计应用程序时,缓存故障会降低性能(响应速度变慢),但不会中断功能。数据库充当后备。
缓存失效策略
失效可确保用户在更新后看到当前数据。根据变化的可见度来选择策略。
| 方法 | 工作原理 | 何时使用 |
|---|---|---|
写入时删除 |
应用程序在更新数据库后立即删除缓存密钥。 |
大多数写作(产品编辑、库存变更)。简单、可靠,避免了过时的数据。 |
仅限 TTL 到期 |
不要失效 — 让 TTL 自然过期。 |
可以接受短暂陈旧的数据(搜索结果、类别列表、分析)。 |
Event-driven 失效 |
后台进程监听数据库更改事件并使受影响的密钥失效。 |
写入路径和缓存位于不同服务中的系统,或者单个数据库更改会影响许多缓存密钥的系统。 |
对于同时使用亚马逊 CloudFront 作为 CDN 层的商城应用程序,协调两个层级的失效情况:删除 ElastiCache 密钥并发送缓存失效(或 CloudFront 缓存标签失效),以便用户在应用程序和边缘层都能看到更新的内容。
连接管理
-
使用连接池 -为每个缓存操作创建新的 TLS 连接会增加延迟。维护永久连接池,并在请求中重复使用它们。
-
设置连接超时 -使用较短的连接超时(1—2 秒)和较短的命令超时(100—500 毫秒)。如果缓存无法快速响应,请回退到数据库而不是阻止请求。
-
妥善处理故障转移 -发生 Multi-AZ故障转移时,与旧主服务器的连接中断。您的连接池应检测到断开的连接并自动重新连接。大多数客户端库都会处理此问题,但会验证测试中的行为。
-
使用集群的配置终端节点 -要启用集群模式,请连接到配置终端节点,而不是单个节点终端节点。配置端点会自动将请求路由到正确的分片。
需要监控的关键指标
| 指标 | Threshold | 周期 | 处理建议 |
|---|---|---|---|
CacheHitRate |
< 80% |
5 分钟 |
调查——命中率低意味着你的 TTL 可能太短、按键设计不当或工作设置超出内存。 |
EngineCPUUtilization |
>70% |
5 分钟 |
向上扩展(更大的节点)或向外扩展(更多分片)。CPU 过高表示缓存处理的命令超出了其处理效率的范围。 |
DatabaseMemoryUsagePercentage |
>80% |
5 分钟 |
驱逐的风险。增加内存(向上扩展)或减少存储的数据(缩短 TTL,减少缓存的数据类型)。 |
移出 |
>0 持续 |
1 分钟 |
缓存已满,正在删除数据以腾出空间。增加缓存失败次数。扩展内存或减少不太关键数据的 TTL。 |
CurrConnections |
>您的客户池大小的 80% |
5 分钟 |
连接池已接近耗尽。增加池大小,缩短连接保持时间,或调查应用程序代码中的连接泄漏。阈值基于应用程序配置的池大小,而不是服务器的最大值 (65,000)。 |
常见问题
我应该在何时使用无服务器与基于节点的对比?
当您的流量不可预测(新市场、季节性高峰)、想要避免容量规划或您的团队没有缓存运营专业知识时,请使用无服务器。当流量模式稳定,需要对分片进行细粒度控制,或者持续的吞吐量使基于节点的更具成本效益时,切换到基于节点的模式。
我应该使用 Valkey 还是 Redis OSS?
使用 Valkey 进行新部署。Valkey 是新 ElastiCache 集群的默认引擎,与 Redis OSS 命令和数据结构完全兼容,并接受持续开发。现有的 Redis OSS 集群可以继续运行——在方便时使用就地引擎升级迁移到 Valkey。
当缓存不可用时会发生什么?
您的应用程序应将缓存视为优化,而不是依赖关系。如果缓存不可用,则回退到直接查询数据库的方式。响应时间会更长,但应用程序仍然可以运行。 Multi-AZ 启用后,完全无法使用缓存的情况很少见,向副本的故障转移通常在 30 秒内完成。
如何估算我需要的内存?
计算:(要缓存的唯一项目的数量)×(每个项目的平均大小)×(Valkey 数据结构的开销系数为 1.2)。开销因对象大小和数据类型而异,较小的对象的开销成比例较高。例如,每个 2 KB 的 100,000 个产品,其开销为 1.2 倍 = 大约 240 MB。添加会话数据、搜索结果和库存数量。从净空开始(使用 60% 的可用内存作为目标),然后监控 DatabaseMemoryUsagePercentage 指标进行调整。