将DynamoDB属性项写入ElastiCache/AWS MemoryDB实现快速查询的设计咨询
结论先行
这个方案是可行的,属于DynamoDB应对非主键属性全量查询场景的常规优化手段,比硬做并行扫描的性价比高很多,但落地时要踩准几个关键点,不然很容易出一致性或者性能问题。
为什么这个思路成立
你碰到的本质是DynamoDB的访问模型限制:只要查询条件没命中主键、也没提前建全局二级索引(GSI),就只能走全表扫描,哪怕开并行扫描,大表下不仅延迟波动大,还会吃掉巨量读容量单位(RCU),流量上来之后成本非常难看。
用写透(准确说用DynamoDB Streams做变更捕获的写后同步更稳妥)把同一属性值对应的条目存在Redis Set里,查询的时候直接从缓存拉,完全绕开扫描逻辑,延迟能稳定在毫秒级,思路是完全对的。
落地要注意的几个核心问题
- 先选适配业务的缓存产品
- 要是这个查询不是核心链路、能接受缓存集群故障时短暂回源扫描的冷启动成本,选ElastiCache for Redis就够,成本低、运维简单,绝大多数场景都够用。
- 要是这个查询是核心业务路径、不能接受缓存丢数据导致的回源压力,直接上MemoryDB,数据持久化、多可用区容灾能力更稳,不用做复杂的缓存预热,只是成本会比ElastiCache高不少。
- 别在业务代码里做同步双写
很多人做写透的时候会在写DynamoDB的逻辑后面紧跟着写缓存,看似强一致,实际只要缓存写失败、或者代码执行到一半抛错,就会出数据库和缓存数据不一致的问题,还会把缓存的可用性和主业务写入链路绑死,缓存抖一下整个写接口就挂。
正确的做法是开DynamoDB Streams捕获所有数据增删改事件,用独立的消费者异步更新对应Redis Set的内容,主写链路完全不感知缓存逻辑,既不影响写入性能,也能靠Streams的至少一次投递保证数据最终一致,实现成本还低。 - 提前规避大Key问题
如果某个属性值对应的条目量特别大(比如单值对应几十万甚至上百万条记录),别把整个Set存成单个Redis Key,也别直接用SMEMBERS拉全量,很容易把Redis单线程打满。这种场景下Set里只存条目主键就行,查询的时候用SSCAN分批迭代取主键,再用DynamoDB的BatchGetItem批量拉取完整条目数据;如果数据量实在太大,也可以按固定规则把大Set拆成多个小Key,分散访问压力。 - 别省一致性校验的逻辑
哪怕Streams的可靠性再高,也有极小概率出现事件消费失败、重复消费导致的缓存脏数据。建议每天低峰期跑个轻量校验任务,抽样或者全量对比缓存Set和DynamoDB里的实际数据,及时补漏、清脏数据,避免缓存和实际数据差太多导致业务异常。 - 提前算好成本账
如果要查询的属性基数极高(比如每个属性值只对应一两条数据,总共有上亿个不同属性值),缓存的内存成本会涨得非常快。这时候可以算下直接给DynamoDB建对应GSI的成本,如果GSI的长期使用成本比缓存低、查询延迟也能接受,直接建GSI反而更省心,不用额外维护一套同步链路。
内容的提问来源于stack exchange,提问作者Shivam Thakur
相关产品推荐
相关产品推荐

