内容提要
本文介绍缓存一致性的概念、原因及解决方案。缓存因TTL过期、写入竞争和多实例并发而漂移,导致数据陈旧。经典模式如cache-aside、write-through各有权衡,事件驱动失效(如Redis键空间通知和CDC)能实时同步。Redis Data Integration(RDI)通过CDC自动同步数据库变更到Redis,减少自定义代码,确保数据新鲜度。
延伸解读
一致性不是非黑即白,而是漂移窗口
文章强调缓存一致性并非绝对状态,而是数据在缓存与数据库之间漂移的时间窗口。任何缓存策略都在缩小、限制或选择这个窗口。理解这一点有助于根据业务容忍度设定合理的TTL和同步机制,避免过度追求强一致而牺牲性能。
经典模式各有取舍,需按需选择
cache-aside灵活但存在多实例竞争风险;write-through保证读己之写但增加写延迟和内存浪费;write-behind写快但一致性弱且可能丢数据。选择时应根据写密集程度和数据重要性权衡,例如订单余额适合write-through,而分析事件可用write-behind。
事件驱动同步是补充,而非替代
TTL和CDC等事件驱动机制常结合使用:事件驱动负责主要新鲜度,TTL作为兜底。但需注意pub/sub的丢失风险、CDC的至少一次投递带来的重复处理,以及Uber案例中暴露的读己之写问题。构建此类系统需投入大量工程精力处理排序、去重和重放。
Q&A
什么是缓存一致性?为什么它很重要?
缓存一致性是指缓存中的值与源数据库保持一致的程度。它很重要,因为如果缓存与数据库不一致,就会提供错误的价格、过期的权限或虚假的库存,影响用户体验和业务准确性。
缓存为什么会发生数据漂移?
缓存漂移主要由三个原因导致:TTL过期窗口、写入顺序竞争和多实例并发。TTL过期窗口是指缓存条目在TTL到期后仍可能被读取;写入顺序竞争是指并发更新导致缓存中保存了旧值;多实例并发是指多个应用实例在缓存填充时相互干扰,导致缓存与数据库不一致。
cache-aside模式和write-through模式各有什么优缺点?
cache-aside模式由应用直接管理缓存,灵活但无法保证一致性,首次请求延迟高,且容易出现多实例竞争问题。write-through模式在写入时同步更新缓存和数据库,提供读己之写一致性,但每次写入都要等待两个系统,部分失败会导致不一致,且可能缓存冷数据。
什么是Redis键空间通知?它如何帮助缓存同步?
Redis键空间通知是Redis提供的一种发布/订阅机制,客户端可以订阅键变化事件,当键被修改时收到通知。这允许一个应用实例在另一个实例修改键时立即失效本地缓存,从而实现实时同步。但它是即发即弃的,客户端断开重连会错过事件,需要额外的补偿机制。
什么是变更数据捕获(CDC)?它如何用于缓存一致性?
变更数据捕获(CDC)是一种读取数据库事务日志并捕获数据变更的技术。工具如Debezium可以将数据库的变更转换为事件,消费者可以实时失效或刷新缓存,从而保持缓存与数据库同步。CDC提供至少一次交付,但消费者需要处理重复事件。
Redis Data Integration(RDI)如何帮助解决缓存一致性问题?
RDI是Redis的变更数据捕获系统,它自动跟踪源数据库的变更并应用到Redis,先进行全量快照,然后流式传输变更。它减少了自定义代码,支持在配置文件中定义映射,提供至少一次交付并保持变更顺序,从而帮助防止数据陈旧。
如何选择适合的缓存一致性策略?
选择策略时,应考虑数据可容忍的陈旧程度和写入负载。一般指导原则是:如果数据可以容忍一定延迟,可以使用cache-aside;如果需要强一致性,可以使用write-through;对于外部数据变更,使用事件驱动失效或CDC。同时,应根据数据变化速度调整TTL长度,并考虑分层使用多种机制。