业务背景
在数据库的上层引入缓存,可以提高服务性能。但是由于一些原因,会出现缓存和数据库中的数据不一致。
- 并发操作缓存,旧数据覆盖了新的缓存
- 服务异常宕机,未及时更新缓存
一致性?
- 强一致性:数据更新实时生效,性能较低
- 弱一致性:数据更新延迟生效,性能较高
Cache-Aside Pattern
也叫边缘缓存模式;
另外有个 Read/Write Through,和上述的区别是增加了 Cache Provider,屏蔽了程序与数据库之间的交互细节。
问:写请求为什么是删除缓存,而不是更新呢?
当更新数据库和更新缓存最终顺序不一致,就会更新脏数据到缓存中。
问:写请求为什么是先更新数据,而不是先删除缓存呢?
当 A 的请求处在 B 删除缓存和更新数据库两个操作的中间,就会写入脏数据到缓存中。
延时双删
Cache Aside Pattern
也不能完全保证一致性;
当更新数据库和删除缓存,刚好在查询数据写入到缓存的中间,那么由于数据库已经更新,写入缓存的就是脏数据。
出现的概率较低。通常查询耗时都比更新耗时短,而且还要考虑缓存命中率。
业界给出的方案是延时双删策略,尽可能保证一致性(延时时长)。
可以异步延时删除缓存提高性能(延时队列)
binlog(MySQL)
如果数据库用的MySQL
,那么可以基于binlog
机制异步删除缓存。阿里的开源组件canal非常适合这个场景,采集数据的变化发送到消息队列中,无业务代码侵入。
总结
- 强一致性会损耗性能,通常采用最终一致性
- 用重试应对失败场景,通常会基于消息队列做异步重试
- 少即是多,非必要情况下不需要应用增加系统复杂度