发生数据不一致的原因
数据读取
在使用缓存时,数据的读取流程一般如下:
数据更新
-
先操作数据库,再操作缓存
-
先操作缓存,再操作数据库
问题:先操作数据库再删除缓存,在最终结果上可保证数据的最终一致性,但是极限情况会导致删除缓存失败,这时可选择删除重试(如将删除失败的KEY放入MQ的队列中,通过监听MQ队列,对缓存再次进行删除)。在先进行缓存删除时,可保证下一个读线程会去查询数据库,并缓存数据。但当写操作未完成时,读取到的数据依旧是老数据。
缓存不一致
原因:
- 两个线程对
同一数据
进行读、写操作
。 - 在写操作时出现网络延迟或业务代码执行慢等情况,导致虽然在写操作第一步做了旧数据缓存删除操作,但是在读线程进行数据读取时,将数据库中的老数据重新写入到了缓存中,这时数据库的写操作才完成。
- 因为在数据库写操作完成前,读线程已经将老数据重新写入缓存,所以导致在缓存过期前查询到的缓存数据和数据库数据不一致。
解决方案
延迟双删(数据最终一致性 AP)
延迟双删即在进行数据更新操作时,先对缓存进行删除操作,在对数据更新完成后,根据业务评估一个延迟时间,对缓存再次进行删除,以保证下次查询数据缓存的数据为最新的数据。
为什么第二次缓存操作要延迟删除:
在进行更新操作的过程中,在第一次进行缓存删除操作后,在缓存更新完成前可能有其他的读数据请求进入,导致被缓存的数据依旧是老数据,要读取到新数据需要等缓存数据过期。
如:在更新数据库操作完成的同时,有一读线程也已经完成了数据库数据的读取,此时两个线程都还剩下对缓存的操作,如果写线程中的删除操作在读线程的写入缓存操作之前,就会导致缓存的依旧是老数据。所以使用延迟删除的策略,以保证一个读线程缓存的老数据能够被清除,新的读线程能读取或缓存的新数据。
使用读写锁(数据强一致性 CP)
在对同一数据进行操作时,使用相同的KEY作为读写锁的KEY。多个读操作可同时进行,但是存在写操作时,读操作必须等待写操作完成后才能继续读。
使用缓存目的在于提升系统的性能及访问速度,所以在使用第二种方式时需要考虑该数据在系统中是否需要牺牲一定的性能做到读写的强一致性。