为了提高程序的响应速度,一般会将热点数据存储于缓存中,如果没有命中,再去查询数据库磁盘数据,最后将数据更新到缓存中的常见方法。但是这种方法也会带来一个问题就是数据一致性。 本文就此问题展开讨论。
1. 使用经典主动更新策略(Cash Aside Pattern模式)
数据一致性问题的解决一般处于主动更新策略中,如果单靠缓存中的key值过期或者内存淘汰机制去被动更新,那数据的同步性会很差。
主动更新中每次数据有变化是需要先更新缓存对应的数据还是直接删掉?
答案是删掉缓存中对应的数据。原因有二,其一,每次数据库数据更新,并不一定对应这缓存中的一次查询,减少多次的对缓存的操作可以提高程序的速度。其二,高并发情况下可能会出现A线程修改完数据库还没有更新缓存的时候,B线程完成更新数据并且更新缓存,这时候A线程再去更新缓存,造成缓存数据和数据库的数据不一致。
主动更新中先更新数据库还是先删掉缓存?
答案是先更新库再去删掉缓存。
情况一: 如果先删缓存再更新数据库存在的问题。在高并发情况下就会出现:A线程删完缓存还没有更新的库的情况下->B线程查询未命中->B线程查库中旧数据->A线程再更新数据。这样就造成数据的不一致,数据同步得等到缓存失效或者下次数据更新。
情况二: 如果先更新数据库再去删除缓存也会存在问题。在高并发情况下就会出现:缓存失效->A线程查询未命中,查询旧数据->B线程更新数据库中新数据->B线程再删除缓存->A再将旧数据写入缓存。这样就造成数据的不一致,数据同步得等到缓存失效或者下次数据更新。
情况一和情况二都是在读缓存和写缓存并发操作时会出现在一定的时间段内数据不一致的问题,但是情况二出现的概率明显低于情况一。
其实这种主动更新尽量保持数据一致性的模式叫做Cash Aside Pattern模式。先更新库,再删缓存模式。
2. Cash Aside Pattern模式+ 延时双删
由于在CashAsidePattern模式中的情况二中也会存在低概率的数据一致性问题,为了能将情况二中的B线程的删除缓存能在写缓存之后,于是就出现了延时双删。
延时双删就是在更新数据库的数据之后,删除一次缓存,然后再写一个定时任务或者延时消息到时之后再删除一次缓存。使得数据不同步的时间段降到最低。