文章目录常用的一致性策略Cache Aside旁路缓存read through或write throughwrite back写请求先写缓存还是先写数据库写缓存还是删除缓存怎么操作才能保证缓存和数据库的一致性先更新缓存再更新数据库先更新数据库再更新缓存先删除缓存再更新数据库延迟双删先更新数据库再删除缓存说明常用的一致性策略Cache Aside旁路缓存定义读请求先从缓存中去读读不到再从数据库中读然后写入缓存特点业务代码既要操作缓存又要操作数据库以数据库的数据为主缓存只是暂时存储数据而已。read through或write through设计思想不直接操作数据库只操作缓存然后让缓存自身去操作数据库。定义read through指每次读都要读缓存如果有就返回数据没有缓存自身从数据库中读数据然后写入缓存write through指写数据的时候直接写缓存缓存自身去更新数据库。也就是说我们只需操作缓存即可剩余操作由缓存中间件自身去完成。write back定义只操作缓存然后让缓存自身去操作数据库。与上面不同之处是写回是批量的、异步的去写数据库。适合写多读少的场景。但是由于是异步写入数据库所以有数据丢失的风险。写请求先写缓存还是先写数据库写缓存还是删除缓存怎么操作才能保证缓存和数据库的一致性先更新缓存再更新数据库可以看到此时缓存值为B数据库值为A出现缓存和数据库不一致。因为更新缓存和数据库的操作不是原子性的所以会出现并发问题。先更新数据库再更新缓存可以看到此时缓存值为A数据库值为B也出现缓存和数据库不一致。先删除缓存再更新数据库这个方法也会出现缓存和数据库不一致的情况延迟双删先删除缓存再更新数据库让线程等待一会儿然后再删数据库。为什么要等一会再删这是要让另外一个线程能在等一会的这个时间去完成读数据库并写缓存这个操作然后给它删了。那么问题来了要延迟多久等多久这要考虑当时的网络情况怎么样服务器的负载和数据库的负载等情况没有一个标准的时间。先更新数据库再删除缓存这个方法也会出现不一致的情况但是概率非常小因为必须满足两个条件刚好是这个 key 刚好过期然后刚好又要更新数据请求2刚更新完数据然后删除缓存之后请求1才写入缓存。也就是说写缓存的速度要慢于更新数据库删除缓存的速度这个概率是非常低的。所以先更新数据库再删除缓存在绝大多数情况下都是可行的。那么问题来了如果更新数据库成功删除缓存失败了怎么解决呢把删除缓存的操作放到 MQ 中MQ 去异步地删除缓存。如果删除失败了那就重试。监听数据库的bin log更新数据库成功会产生一条bin log因此就可以监听这个bin log然后删除缓存。同样地如果删除失败了那就重试。这个方法的优点是不入侵业务代码比使用 MQ 的方案好。但是实际上公司的 MySQL 都是主从部署读写分离的主库只能写从库只能读然后主库更新的数据需要花一点时间同步给从库。所以当请求1先更新了这个数据库然后异步地删除了缓存但是写的是主库从库还没写从库需要等待主库同步数据过来那从库还没等到主库传来的数据此时又来了一个请求读了从库的旧数据然后写入了缓存缓存和数据库又出现不一致了但是这种概率也是非常低的如果非要解决这个问题那可以在主库更新之后的一段时间之内让其他请求强制去读主。综上所述要想保证缓存和数据库的完全一致性几乎是完全不可能的现有的手段只能尽可能地去保证缓存和数据库在绝大多数的情况下是一致的然后给数据设置一个过期时间。即便在非常极端的情况下不一致了也能让这个脏数据过期失效。说明本文参考程序员回家养猪博主的视频进行总结和编写。