高并发场景下,到底先更新缓存还是先更新数据库?

简介: 高并发场景下,到底先更新缓存还是先更新数据库?

在大型系统中,为了减少数据库压力通常会引入缓存机制,一旦引入缓存又很容易造成缓存和数据库数据不一致,导致用户看到的是旧数据。

为了减少数据不一致的情况,更新缓存和数据库的机制显得尤为重要,接下来带领大家踩踩坑。

 

(1)读请求常见流程

应用首先会判断缓存是否有该数据,缓存命中直接返回数据,缓存未命中即缓存穿透到数据库,从数据库查询数据然后回写到缓存中,最后返回数据给客户端。

 

(2)写请求常见流程

首先更新数据库,然后从缓存中删除该数据。

看了写请求的图之后,有些同学可能要问了:为什么要删除缓存,直接更新不就行了?这里涉及到几个坑,我们一步一步踩下去。

 

Cache aside踩坑

Cache aside策略如果用错就会遇到深坑,下面我们来逐个踩。

踩坑一:先更新数据库,再更新缓存

如果同时有两个写请求需要更新数据,每个写请求都先更新数据库再更新缓存,在并发场景可能会出现数据不一致的情况

 


如上图的执行过程:

(1)写请求1更新数据库,将 age 字段更新为18;

(2)写请求2更新数据库,将 age 字段更新为20;

(3)写请求2更新缓存,缓存 age 设置为20;

(4)写请求1更新缓存,缓存 age 设置为18;

执行完预期结果是数据库 age 为20,缓存 age 为20,结果缓存 age为18,这就造成了缓存数据不是最新的,出现了脏数据。

 

踩坑二:先删缓存,再更新数据库

如果写请求的处理流程是先删缓存再更新数据库,在一个读请求和一个写请求并发场景下可能会出现数据不一致情况。

 

如上图的执行过程:

(1)写请求删除缓存数据;

(2)读请求查询缓存未击中(Hit Miss),紧接着查询数据库,将返回的数据回写到缓存中;

(3)写请求更新数据库。

整个流程下来发现数据库中age为20,缓存中age为18,缓存和数据库数据不一致,缓存出现了脏数据。

 

踩坑三:先更新数据库,再删除缓存

在实际的系统中针对写请求还是推荐先更新数据库再删除缓存,但是在理论上还是存在问题,以下面这个例子说明

 

如上图的执行过程:

(1)读请求先查询缓存,缓存未击中,查询数据库返回数据;

(2)写请求更新数据库,删除缓存;

(3)读请求回写缓存;

整个流程操作下来发现数据库age为20缓存age为18,即数据库与缓存不一致,导致应用程序从缓存中读到的数据都为旧数据。

但我们仔细想一下,上述问题发生的概率其实非常低,因为通常数据库更新操作比内存操作耗时多出几个数量级,上图中最后一步回写缓存(set age 18)速度非常快,通常会在更新数据库之前完成。


如果这种极端场景出现了怎么办?我们得想一个兜底的办法:缓存数据设置过期时间。通常在系统中是可以允许少量的数据短时间不一致的场景出现。

Read through

在 Cache Aside 更新模式中,应用代码需要维护两个数据源头:一个是缓存,一个是数据库。而在 Read-Through 策略下,应用程序无需管理缓存和数据库,只需要将数据库的同步委托给缓存提供程序 Cache Provider 即可。所有数据交互都是通过抽象缓存层完成的。

如上图,应用程序只需要与Cache Provider交互,不用关心是从缓存取还是数据库。

在进行大量读取时,Read-Through 可以减少数据源上的负载,也对缓存服务的故障具备一定的弹性。如果缓存服务挂了,则缓存提供程序仍然可以通过直接转到数据源来进行操作。


Read-Through 适用于多次请求相同数据的场景,这与 Cache-Aside 策略非常相似,但是二者还是存在一些差别,这里再次强调一下:

  • 在 Cache-Aside 中,应用程序负责从数据源中获取数据并更新到缓存。
  • 在 Read-Through 中,此逻辑通常是由独立的缓存提供程序(Cache Provider)支持。

 

Write through

Write-Through 策略下,当发生数据更新(Write)时,缓存提供程序 Cache Provider 负责更新底层数据源和缓存。

缓存与数据源保持一致,并且写入时始终通过抽象缓存层到达数据源。

Cache Provider类似一个代理的作用。

Write behind

Write behind在一些地方也被称为Write back, 简单理解就是:应用程序更新数据时只更新缓存, Cache Provider每隔一段时间将数据刷新到数据库中。说白了就是延迟写入

如上图,应用程序更新两个数据,Cache Provider 会立即写入缓存中,但是隔一段时间才会批量写入数据库中。

这种方式有优点也有缺点:

  • 优点是数据写入速度非常快,适用于频繁写的场景。
  • 缺点是缓存和数据库不是强一致性,对一致性要求高的系统慎用。

总结一下

学了这么多,相信大家对缓存更新的策略都已经有了清晰的认识。最后稍稍总结一下。

缓存更新的策略主要分为三种:

  • Cache aside
  • Read/Write through
  • Write behind

Cache aside 通常会先更新数据库,然后再删除缓存,为了兜底通常还会将数据设置缓存时间。


Read/Write through 一般是由一个 Cache Provider 对外提供读写操作,应用程序不用感知操作的是缓存还是数据库。


Write behind简单理解就是延迟写入,Cache Provider 每隔一段时间会批量输入数据库,优点是应用程序写入速度非常快。

相关文章
|
1月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
68 6
|
7天前
|
缓存 关系型数据库 MySQL
高并发架构系列:数据库主从同步的 3 种方案
本文详解高并发场景下数据库主从同步的三种解决方案:数据主从同步、数据库半同步复制、数据库中间件同步和缓存记录写key同步,旨在帮助解决数据一致性问题。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
高并发架构系列:数据库主从同步的 3 种方案
|
2天前
|
缓存 NoSQL 数据库
运用云数据库 Tair 构建缓存为应用提速,完成任务得苹果音响、充电套装等好礼!
本活动将带大家了解云数据库 Tair(兼容 Redis),通过体验构建缓存以提速应用,完成任务,即可领取罗马仕安卓充电套装,限量1000个,先到先得。邀请好友共同参与活动,还可赢取苹果 HomePod mini、小米蓝牙耳机等精美好礼!
|
7天前
|
缓存 NoSQL 中间件
redis高并发缓存中间件总结!
本文档详细介绍了高并发缓存中间件Redis的原理、高级操作及其在电商架构中的应用。通过阿里云的角度,分析了Redis与架构的关系,并展示了无Redis和使用Redis缓存的架构图。文档还涵盖了Redis的基本特性、应用场景、安装部署步骤、配置文件详解、启动和关闭方法、systemctl管理脚本的生成以及日志警告处理等内容。适合初学者和有一定经验的技术人员参考学习。
63 7
|
16天前
|
存储 缓存 数据库
缓存技术有哪些应用场景呢
【10月更文挑战第19天】缓存技术有哪些应用场景呢
|
21天前
|
缓存 弹性计算 NoSQL
新一期陪跑班开课啦!阿里云专家手把手带你体验高并发下利用云数据库缓存实现极速响应
新一期陪跑班开课啦!阿里云专家手把手带你体验高并发下利用云数据库缓存实现极速响应
|
1月前
|
存储 缓存 NoSQL
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
54 4
|
1月前
|
缓存 NoSQL Ubuntu
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
53 3
|
5月前
|
缓存 NoSQL Java
Java高并发实战:利用线程池和Redis实现高效数据入库
Java高并发实战:利用线程池和Redis实现高效数据入库
478 0
|
3月前
|
监控 算法 Java
企业应用面临高并发等挑战,优化Java后台系统性能至关重要
随着互联网技术的发展,企业应用面临高并发等挑战,优化Java后台系统性能至关重要。本文提供三大技巧:1)优化JVM,如选用合适版本(如OpenJDK 11)、调整参数(如使用G1垃圾收集器)及监控性能;2)优化代码与算法,减少对象创建、合理使用集合及采用高效算法(如快速排序);3)数据库优化,包括索引、查询及分页策略改进,全面提升系统效能。
46 0

热门文章

最新文章

  • 1
    Java面试题:解释Java NIO与BIO的区别,以及NIO的优势和应用场景。如何在高并发应用中实现NIO?
    68
  • 2
    Java面试题:设计一个线程安全的单例模式,并解释其内存占用和垃圾回收机制;使用生产者消费者模式实现一个并发安全的队列;设计一个支持高并发的分布式锁
    65
  • 3
    Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
    57
  • 4
    Java面试题:结合建造者模式与内存优化,设计一个可扩展的高性能对象创建框架?利用多线程工具类与并发框架,实现一个高并发的分布式任务调度系统?设计一个高性能的实时事件通知系统
    52
  • 5
    Java面试题:假设你正在开发一个Java后端服务,该服务需要处理高并发的用户请求,并且对内存使用效率有严格的要求,在多线程环境下,如何确保共享资源的线程安全?
    67
  • 6
    在Java中实现高并发的数据访问控制
    40
  • 7
    使用Java构建一个高并发的网络服务
    27
  • 8
    微服务06----Eureka注册中心,微服务的两大服务,订单服务和用户服务,订单服务需要远程调用我们的用,户服务,消费者,如果环境改变,硬编码问题就会随之产生,为了应对高并发,我们可能会部署成一个集
    36
  • 9
    如何设计一个秒杀系统,(高并发高可用分布式集群)
    123
  • 10
    探索Java分布式锁:在高并发环境下的同步访问实现与优化
    169