读(查询)操作一致性
当读操作请求打到缓存上时,如果缓存里面存在数据,那么直接返回即可。如果缓存里面没有数据,那么就查询数据库,如果数据库里面有数据,那么我们通过程序,将数据库里面的数据同步到redis即可。
写(插入、更新)操作一致性
当写操作请求打到缓存+数据库架构时,由于操作缓存和数据库并非原子性,可能会执行到中间环节,就会出现数据非最终一致性了。
插入操作:
先插入数据库,再插入缓存:如果插入数据库报错,那么直接程序事务回滚就不会执行插入缓存。如果插入数据库成功,那么再插入缓存时。如果失败,那么只是下次查询时缓存命中失败,然后查询数据库时,将数据更新到缓存即可。
更新操作:
- 先删除缓存,再更新数据库:
当线程1删除缓存成功还没有更新数据库,而线程2进来读取数据库,并将旧数据更新到缓存。而线程1 更新了数据库的数据为新数据。就出现缓存旧数据和数据库的新数据,数据不一致的尴尬。而我看到网上的延时双删策略:线程1删除缓存 - 线程2读数据库旧数据-线程2更新旧数据到缓存 -线程1更新数据库-线程1延时删除缓存。这个操作在延时期间都是一直出现缓存和数据库不一致,这根本没有解决问题,所以这个方案不采用。 - 先更新数据库,再删除缓存:
数据库更新成功,缓存删除失败:当数据库已经更新成功,缓存删除失败,那么我们提供补偿机制:利用消息队列,将需要删除的key发送到消息队列,让应用自己去消费消息,如果消费失败,就重试多次。