1、命中:程序先从缓存中读取数据,如果命中直接返回。
2、失效:程序先从缓存中读取数据,如果没有命中,则从数据库中读取,成功之后将数据放入缓存。
3、更新:程序先更新数据库,再删除缓存。
更新:
1、先更新缓存,再更新数据库
2、先更新数据库,再更新缓存(线程A更新了数据库 count=1,线程B抢占到了CPU资源更新数据库count=2,再更新缓存count=2,这个时候线程A再次获取到CPU资源做最后的更新,将缓存中的数据更新为1。这样就会导致数据库与缓存数据不一致的情况) (双写模式会出现脏数据,缓存过期后,又能从数据库中得到最新值)
3、先删除缓存,再更新数据库(线程A删除缓存count=1,线程B访问count没拿到缓存,发现不存,从数据库读取到旧值count=1,线程A更新数据库为2,线程B将数据写入到缓存中为1)。
4、先更新数据库,再删除缓存(概率很小,出问题:先前缓存刚好失效,请求A查数据库得到旧值count=1,请求B更新数据库,写入到数据中count=2,请求B删除缓存,请求A写入缓存A=1)。
第4个可以搭配延迟删除来解决问题。 请求B更新数据库以后,让线程睡一段时间过后,再删除缓存。
Mysql读写分离(主从架构模式)
canal订阅mysql的binlog日志,将主mysql的最新数据实时覆盖redis原始的值。
高可用的话,就引入消息队列。
项目:缓存数据一致性!!!
1、双写模式(先写数据库、再写缓存 )如果不管数据不一致问题, 但是会出现暂时性脏数据问题(脏数据问题,但是在数据稳定后,缓存过期以后,又能得到最新的正确数据。(1、加分布式锁,2、允许短暂性的不一致,设置key的过期时间))
2、失效模式(先写数据库、再删缓存)
总结:无论是双写模式还是失效模式,都会导致缓存不一致问题。即使多个实例同时更新会出问题。
系统一致性解决方案:
1、缓存的所有数据都有过期时间,即使数据有脏数据 下一次查询也能主动更新
2、读写数据的时候,加上分布式的读写锁。经常写、经常读肯定有影响。
3、如果遇到实时性、一致性要求高的数据,应该立即查询数据库,即使慢点。
4、不应该过渡设计,增加复杂度。