redis保证和数据库事务一致 redis和mysql数据同步原理


前言 由于缓存的高并发和高性能已经在各种项目中被广泛使用,在读取缓存这方面基本都是一致的,大概都是按照下图的流程进行操作:
但是在更新缓存方面,是更新完数据库再更新缓存还是直接删除缓存呢?又或者是先删除缓存再更新数据库?在这一点上就值得探讨了 。
一致性方案 在实际项目开发中需要保证数据库和缓存中的数据一致,否则人家充值了100块,不断刷新却还是显示0.01元,岂不是尴尬?从理论上来说,为缓存设置过期时间是最终保证数据一致性的解决方案,采用这种方案的话,所有的写操作都是以数据库为准,如果数据库写入成功但是缓存更新失败,只要缓存到过期时间之后后面读缓存时自然会在数据库中读取新的值然后更新缓存 。接下来探讨的思路主要的方向是在不依赖为缓存设置过期时间的前提下如何保证数据一致性 。这里主要探讨三种方案:

①先更新数据库,再更新缓存
②先删除缓存,再更新数据库
③先更新数据库,再删除缓存
先更新数据库再更新缓存 这种方案是普遍被反对的(在我的认知范围中~),为啥呢?为啥这种方案就被反对呢?原因主要有两方面,请听我细细道来:
首先从数据安全方面考虑,如果同时有请求A和请求B同时进行操作,A先更新了数据库的一条数据,随后B马上有更新了该条数据,但是可能因为网络延迟等原因,B却比A先更新了缓存,就会出现一种什么情况呢?缓存中的数据并不最新的B更新过的数据,就导致了数据不一致的情况 。
其次从业务场景方面考虑,如果是一个写数据库较多而读数据库较少的业务,如果采用这种方案就会导致数据还没读缓存就会被频繁更新,白白浪费性能 。
综合以上两方面的考虑,这种方案果断pass 。下面的两种方案就是争议较大的两种方案了,到底是先删缓存再更新数据库还是先更新数据库再删除缓存?
先删缓存再更新数据库 如果同时有一个请求A进行更新操作,请求B进行查询操作,就可能会出现A请求进行写操作前会删除缓存,B请求刚好此时进来发现缓存是空的,B请求就会查询数据库,如果此时A请求的写操作还未完成,B请求查询到的就还是旧的值,还是会将旧的值写入缓存,A请求将新的值写入数据库,此时就会导致数据不一致的问题,如果不采用给缓存设置过期时间的策略,该数据永远都是脏数据 。
解决这种情况可以采用延时双删的策略,就是在更新数据库之前先删除缓存,然后对数据库进行写入操作,数据库更新完成之后再次进行删除缓存的操作,目的是删除读请求可能造成的缓存脏数据,第二次删除缓存之前可以休眠几秒,具体时间开发者可以评估一下自己项目读数据业务逻辑的耗时,然后在该耗时基础上加几百ms即可,这么做的目的就是确保读请求结束写请求可以删除读请求造成的脏数据 。如果MySQL采用的是读写分离的架构,可能由于主从延时的原因造成数据不一致,可以在写操作完成之后根据主从延时时间休眠一下然后再进行删除缓存的操作 。延时双删的伪代码如下:

推荐阅读