25 | 缓存异常(上):如何解决缓存和数据库的数据不一致问题?


Redis核心技术与实战

实践篇

25 | 缓存异常(上):如何解决缓存和数据库的数据不一致问题?

缓存和数据库的数据不一致是如何发生的?

缓存和数据库的一致性包含了两种情况:

  • 缓存中有数据,那么,缓存的数据值需要和数据库中的值相同;
  • 缓存中本身没有数据,那么,数据库中的值必须是最新值。

对于读写缓存来说,要想保证缓存和数据库中的数据一致,就要采用同步直写策略。 在业务应用中,要使用事务机制,来保证缓存和数据库的更新具有原子性,也就是说,两者要不一起更新,要不都不更新,返回错误信息,进行重试。否则,就无法实现同步直写。

对于只读缓存来说,如果有数据新增,会直接写入数据库;而有数据删改时,就需要把只读缓存中的数据删除。 这样一来,应用后续再访问这些增删改的数据时,因为缓存中没有相应的数据,就会发生缓存缺失。此时,应用再从数据库中把数据读入缓存,这样后续再访问数据时,就直接从缓存中读取。

在这里插入图片描述
1. 新增数据

如果是新增数据,数据会直接写到数据库中,不用对缓存做任何操作,此时,缓存中本身就没有新增数据,而数据库中是最新值,这种情况符合上述所说的一致性的第 2 种情况,所以,此时,缓存和数据库的数据是一致的。

2. 删改数据

删改操作如果无法保证原子性,就会出现数据不一致问题。

假设应用先删除缓存,再更新数据库,如果缓存删除成功,但是数据库更新失败,那么,应用再访问数据时,缓存中没有数据,就会发生缓存缺失。然后,应用再访问数据库,但是数据库中的值为旧值,应用访问到的就是旧值。

在这里插入图片描述

如果应用先完成了数据库的更新,但是,在删除缓存时失败了,那么,数据库中的值是新值,而缓存中的是旧值,这肯定是不一致的。这个时候,如果有其他的并发请求来访问数据,按照正常的缓存访问流程,就会先在缓存中查询,但此时,就会读到旧值。

在这里插入图片描述
在这里插入图片描述

如何解决数据不一致问题?

重试机制

具体来说,可以把要删除的缓存值或者是要更新的数据库值暂存到消息队列中(例如使用 Kafka 消息队列)。当应用没有能够成功地删除缓存值或者是更新数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或更新。

如果能够成功地删除或更新,就把这些值从消息队列中去除,以免重复操作,此时,就可以保证数据库和缓存的数据一致。否则的话,还需要再次进行重试,如果重试超过的一定次数,还是没有成功,就需要向业务层发送报错信息。

在这里插入图片描述

实际上,即使这两个操作第一次执行时都没有失败,当有大量并发请求时,应用还是有可能读到不一致的数据。

情况一:先删除缓存,再更新数据库。

假设线程 A 删除缓存值后,还没有来得及更新数据库(比如说有网络延迟),线程 B 就开始读取数据了,那么这个时候,线程 B 会发现缓存缺失,就只能去数据库读取。这会带来两个问题:

  • 线程 B 读取到了旧值;
  • 线程 B 是在缓存缺失的情况下读取的数据库,所以,它还会把旧值写入缓存,这可能会导致其他线程从缓存中读到旧值。

等到线程 B 从数据库读取完数据、更新了缓存后,线程 A 才开始更新数据库,此时,缓存中的数据是旧值,而数据库中的是最新值,两者就不一致了。

在这里插入图片描述

解决方案:

在线程 A 更新完数据库值以后,可以让它先 sleep 一小段时间,再进行一次缓存删除操作。 之所以要加上 sleep 的这段时间,就是为了让线程 B 能够先从数据库读取数据,再把缺失的数据写入缓存,然后,线程 A 再进行删除。

这样一来,其它线程读取数据时,会发现缓存缺失,所以会从数据库中读取最新值。因为这个方案会在第一次删除缓存值后,延迟一段时间再次进行删除,所以也把它叫做 “延迟双删”

情况二:先更新数据库值,再删除缓存值。

如果线程 A 删除了数据库中的值,但还没来得及删除缓存值,线程 B 就开始读取数据了,那么此时,线程 B 查询缓存时,发现缓存命中,就会直接从缓存中读取旧值。不过,在这种情况下,如果其他线程并发读缓存的请求不多,那么,就不会有很多请求读取到旧值。而且,线程 A 一般也会很快删除缓存值,这样一来,其他线程再次读取时,就会发生缓存缺失,进而从数据库中读取最新值。所以,这种情况对业务的影响较小。

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 数据库数据一致问题通常可以通过以下方法来解决: 1. 使用数据库事务:通过将一系列操作组成一个事务,可以保证这些操作要么全部成功执行,要么全部回滚,从而避免数据一致问题。 2. 引入缓存使用缓存可以提高系统的性能,但是需要考虑缓存数据库之间的一致性,可以使用缓存穿透、缓存雪崩等技术来解决。 3. 使用分布式锁:在多个线程或进程同时访问数据库时,可以使用分布式锁来保证只有一个线程或进程能够修改数据,避免数据一致问题。 4. 数据库主从同步:使用数据库主从同步可以将数据实时同步到从库,从而保证数据一致性。 5. 数据库定时同步:定时将主库的数据同步到从库,也可以保证数据一致性。 以上方法可以有效地解决数据库数据一致问题。 ### 回答2: 数据库数据一致是指在数据库存储的数据与实际应该存储的数据一致的情况。在处理数据库数据一致问题时,可以采取以下几种解决方法: 1. 数据备份与恢复:通过进行定期的数据备份,可以在发现数据库数据一致问题时恢复到之前的备份点,保证数据一致性。备份可以使用数据库自身的备份工具或第三方备份软件进行。 2. 数据一致性检查与修复:可以定期或根据需要对数据库进行一致性检查,比对数据库存储的数据与实际应该存储的数据,发现不一致数据后,通过数据修复操作进行修复。 3. 定期数据同步:对于分布式系统或跨多个数据库的应用,可以通过定期进行数据同步操作,把数据从一个数据库同步到其他数据库,以保证数据一致性。 4. 引入事务机制:事务可以保证一组操作的原子性、一致性、隔离性和持久性。在数据库操作引入事务机制,可以将一系列操作视为一个整体,如果其某一步出现错误,可以回滚到初始状态,保证数据一致性。 5. 异常处理与错误日志:在出现数据库数据一致问题时,及时捕获并记录异常,同时记录错误日志,通过查看日志了解问题发生的原因并及时采取相应措施解决问题。 6. 定位与解决数据冲突:当多个用户同时对数据库进行读写操作时,可能会发生数据冲突问题。可以通过锁机制、并发控制机制或乐观锁等方法解决数据冲突问题,保证数据一致性。 综上所述,处理数据库数据一致问题可以通过数据备份与恢复、数据一致性检查与修复、定期数据同步、引入事务机制、异常处理与错误日志、定位与解决数据冲突等方法来解决。根据实际情况选择合适的解决方法可以保证数据库数据一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久违の欢喜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值