高并发场景下数据库与缓存的一致性
2025-9-3
| 2025-9-3
字数 844阅读时长 3 分钟
type
status
date
slug
summary
tags
category
icon
password

高并发场景下数据库与缓存的一致性

在使用缓存的时候,难免遇到被缓存的数据需要进行更新,为了保证数据在数据库和缓存的一致性,通常有以下几种方法:

Cache Aside Pattern 旁路缓存模式

读操作:从缓存中读取数据,如果不存在则需要重建缓存,也就是先从数据库中读取然后保存到缓存中。
写操作:先修改数据库然后删除缓存
旁路模式适用于Redis+Mysql这种模式

写操作为什么不修改缓存而是直接删除?

再旁路缓存模式下:直接删除操作简单,修改数据还需要修改缓存增加了业务复杂度,同时在并发场景下多个线程进行修改容易造成缓存数据被覆盖,造成数据不一致。

写操作为什么是先修改数据库再删除缓存?

首先,如果先删除了缓存,再修改数据,在并发的情况下容易出现,旧数据还没被修改就又被读到缓存中的情况,等数据库修改完后缓存中是旧数据,数据库中又是新数据。

需要注意的点

缓存重建需要加锁,防止在高并发的情况由于缓存失效对数据库造成压力(缓存击穿)

Read-Through/Write-Through(读写穿透)

读穿透:和上面的类型,只是在缓存中读取不到数据后,是又缓存组件本身去数据库中查找数据然后回填并返回,前面的是由业务代码实现。读穿透依赖于缓存组件。
写穿透:先修改缓存后续再更新数据库,通常是使用异步的方式进行数据库的回写。
如果在某些高并发的场景下每次更新缓存都更新数据库的话,缓存的意义就不大了,而且会对数据库造成很大压力,所以一般都使用异步的方式进行更新数据

异步回写的几种方式

  • 利用定时任务定时将缓存中的数据刷回数据库
  • 阈值累计,可以等数据更新达到一定阈值后再触发刷新流程,适用于点赞这种累加数据
  • 消息队列,引入消息队列,将每次刷新的操作通过消息发送,后续数据库慢慢消费

解决双写一致性的几种方案

  • 延时双删除
  • 删除缓存重试机制
  • 监听并读取binlog异步删除缓存

各种方法该如何选择?

看数据对实时性的要求(要求高的话就选择先更新缓存的)、数据是否允许故障下的丢失(不允许就选择先更新数据库的或者使用消息队列,但是注意要保证消息的持久化)、对性能的要求(如果对高并发下的性能要求高可以选择阈值累计类型,这样可以大大降低数据库操作的数量)
 
  • Java
  • 八股
  • 思考
  • Java的编译模式即时通讯(Instant Messaging)之消息推送
    Loading...