在高并发访问的情况下,很可能会导致数据不一致,那<如何保证数据的一致性>这个问题已经属于老生长谈的问题了。
是先更新数据库,再更新缓存 ?
还是先更新缓存,再更新数据库?
还是先更新数据库,再删除缓存?
还是先删除缓存,再更新数据库?
什么是延迟双删?
什么是双检加锁策略?
等等。
对于一个常规系统来说,如何保证其数据一致性是不得不解决的问题。
我们按照上面列出的疑问流程,一个一个说一下缓存的问题及如何解决。
首先先说结论:这种缓存策略是有问题的
我们以订单系统为例。可以看一下:
上面这种情况,会让数据库和缓存里面数据不一致。读取redis的脏数据。
首先先说结论:这种缓存策略也是有问题的
我们以订单系统为例。可以看一下:多个请求的情况,A和B代表2个不同请求
上面这种情况,会让数据库和缓存里面数据不一致。
请注意:这种是肯定不行的。因为我们应用一般是将数据库做为最终的准确数据。而不是缓存。
首先先说结论:这种缓存策略也是有问题的
我们以订单系统为例。可以看一下:多个请求的情况,A和B代表2个不同请求
上面这种情况,缓存库存还是为10000,导致数据库和缓存里面数据不一致。
首先说结论: 这种情况可以接受。但还需要有其他补偿措施,防止删除缓存失败等情况。
这种情况大概率是可以接受的,但也会存在部分问题。比如:假如缓存删除失败或者来不及,导致请求再次访问redis时缓存命中,读取到的是缓存旧值。
总体来说,上面四种方案都不是特别完美。能接受的也就是先更新数据库。再删除缓存这种方案。但对于好的系统来说,这种方案也是不可接受的。所以基于此。业界也提出了解决方案:延迟双删、异步同步等
延时双删策略的实现步骤如下:
这种策略的关键在于延迟删除的时间设置。这个时间必须大于将数据库旧数据写入Redis的时间,通常是几百毫秒到几秒不等,具体时间取决于业务需求。
但基于开发者来说,这个基于业务需求得到的延迟删除的具体时间,一般情况下开发者很难评估。
但对于一般的项目来说,其实也足够。毕竟要触发异常情况的概率挺低。
所谓binlog的异步缓存同步。实际也是延迟双删的扩展。他只是将延迟删除缓存变更为了异步通过数据库binlog同步来删除缓存。这样就很好的处理了延迟双删中删除时间设置不太好解决。
核心原理:在数据写入 MySQL 数据库后,通过Canal读取 MySQL 的 binlog(二进制日志)日志来获取数据的相关操作信息并同步给客户端,客户端根据需求异步地删除对应的缓存数据。这样可以在缓存删除失败或者延迟时,通过读取 binlog 重新进行缓存删除操作。
关于Canal相关的文章可以查看:Canal 实战 : 异步实践缓存最终一致性
这里将操作的数据写入消息队列的核心原因是:防止一些特殊原因导致删除缓存失败,起一个重试的机制。
其次。对于Canal同步binlog日志,这里也是需要使用消息队列来消费相关的日志的。需要注意。
总体来说,缓存是不可能实时的一致性的。我们只能以 最终一致性目标 来进行业务梳理。
大部分业务情况下。我们采用的同步策略都是:延迟双删 + 异步同步进行缓存的 最终一致性处理。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。