首页 > 数据库 >Redis-6-三种缓存读写策略

Redis-6-三种缓存读写策略

时间:2024-06-09 13:54:39浏览次数:23  
标签:缓存 删除 Redis 读写 db 更新 线程 数据

2.1 旁路缓存

Cache Aside Pattern(旁路缓存)适合读请求比较多的场景

Cache Aside Pattern 中服务端需要同时维系 db 和 cache,并且是以 db 的结果为准。

2.1.1 写

  • 先更新db
  • 直接删除缓存

2.1.2 读

  • 先读缓存
    • 有,则从缓存返回。
    • 没有,从db中读取返回。
  • 再将读取的数据写入缓存

2.1.3 常见问题

1.写,写DB后咋是删缓存不是更新缓存?

写N次,只有最后一次数据的有效,前面写的都会被覆盖。

读不到的时候自然会重建缓存,我们直接删除了,等读的时候重建即可。

2.写,可不可以先删除缓存,再更新DB?

不可以。

前面已经讲了,我们更新的时候,db更新没问题,但是缓存呢不做更新,直接删除。

现在的问题就是,更新db和删除缓存这两个操作的先后问题。

假设我们数据库中有个值name=yang,我们准备更新成yang37

2.1 (×)先删除缓存,再更新db。

这个情况,主要是考虑并发场景,在删除缓存 -> 更新db期间,db中的始终是旧数据。

如果线程2发生了读取请求,会导致数据不一致。

  • 线程1:尝试更新name从yang到yang37
  • 线程2:尝试读取name的值

image-20240609123026058

最终我们可以看到,缓存中的数据还是旧数据yang,而db中是正确的yang37,数据不一致

问题的根源在哪里,在于你线程2读取缓存是很快的,缓存中没值,必然触发缓存的重建。

  • 线程1的db更新完了,那就皆大欢喜,即左边线程1整个期间没有并发问题。
  • 线程1的db没更新完,db中的必定是旧数据,重建的缓存值也必定成旧数据,导致出问题。

注意图最下面的两个框框。最重要的是,在缓存有效期内,你缓存的一直是脏数据,如果这个缓存没过期时间,那么缓存中的数据始终有问题。

这个问题出现的概率大吗?即左边删除缓存 -> 更新db的期间能不能包裹住右边边。

image-20240609133539141

实际上,db查询数据比更新数据快,这个情况很容易出现。

2.2 (√) 先更新db,再删除缓存。

接着上面的,来看下先更新db的。

image-20240609125453219

嗯,这里,如果更新db -> 删除缓存期间有读取请求,我们的线程2还是会读取到脏数据。

但是,咱们最终缓存中的数据不存在,下次查询会触发重建。

先删除缓存再更新db的方式,逻辑上就存在问题了,咱们这个影响程度小的多。

咱们只是在这期间有短暂的不一致问题,不会导致最终状态下的数据不一致。

但是,还是可能有缓存最终不一致的情况,就是刚好缓存失效了,例如下图。

image-20240609131314236

这里的问题点是什么,线程2的更新缓存操作覆盖了线程1的更新db+删除缓存的操作。

它必须要完整的包裹住线程1的更新操作和删除操作。

  • 如果线程1更新操作在线程2查询db的操作之前,那么此时查询到的数据已经被更新了,重建的缓存值刚好是正确的。
  • 如果线程1的删除操作发生在线程2的更新缓存之后,那么此时缓存中的数据已经被删除了,下次重建会成为正确的值,也符合我们的预期。

我们注意下哈,先决条件是线程2从db查到旧数据之后,线程1开始更新db了。

然后,必须完完整整的包裹住这整个操作,必须得下面这样。

image-20240609132053259

即,哪怕我像下面这样两种情况,它也不会有问题,必须满足上面包裹住的场景,才可能有问题。

image-20240609132534799 image-20240609132659946

实际上,db查询数据比更新数据快,所以这个更新db+删除缓存的时间很难比查询db+更新缓存的时间长

别忘了我们还有并发+缓存失效的背景,这所有因素组合在一起才可能有这个数据不一致的情况,所以出现问题的概率是很低的。

你说,咱们方案1中过期时间的场景都还没讨论呢。哈哈,其实不用讨论了,你想啊,方案1还没说过期就有很大隐患了,还不要说咱们现在这里的讨论的方案2+过期的场景。

综上呢,咱们的正确方案是:先更新db,再删除缓存。

2.2 读写穿透

2.3 异步缓存写入

标签:缓存,删除,Redis,读写,db,更新,线程,数据
From: https://www.cnblogs.com/yang37/p/18239521

相关文章

  • Apache POI(使用Java读写Excel表格数据)
    1.ApachePOI简介ApachePOI是一个开源的Java库,用于操作MicrosoftOffice格式的文件。它支持各种Office文档的读写功能,包括Word文档、Excel电子表格、PowerPoint演示文稿、Outlook电子邮件等。ApachePOI提供了一组API,使得Java开发者能够轻松地在Java应用程序中处理Office文件......
  • Redis集群和高可用性:保障Redis服务的稳定性
    I.引言A.对Redis的简单介绍和其在现代Web应用中的角色 Redis(REmoteDIctionaryServer)是一个开源的、基于内存的键值数据库,它支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。由于Redis的高性能和丰富的数据类型,使其在现代Web应用中广泛使用。例如,它可以用......
  • bin下的bpl 与 redist下的bpl 区别
    由于我们是host+bpl开发,需要在delphi的安装目录寻找,我们需要的带的包,搜索发现很多包有2份,bin目录下有一份,redist目录下还有一份,通过下图可以看到这2份的大小是一致的,那么他们是一模一样的吗;我把他们复制出来,用在线MD5来看他们的MD5,发现这2份是一样的!......
  • redis命令实践 详细教程
    Redis是一个高性能的键值对数据库,支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。以下是一份详细的Redis命令实践教程,包括常用命令和示例。1.连接Redis服务器使用redis-cli工具连接到Redis服务器:redis-cli-h<hostname>-p<port>-a<password>-h:指定Redis......
  • redis常用命令详细带例子
    Redis是一个功能丰富的键值对数据库,支持多种数据结构和操作。以下是一些常用Redis命令的示例,以及如何在实践中使用它们。基本操作PingRedis服务器PING例子:检查Redis服务器是否响应。redis-cliPING设置键值对SETkeyvalue例子:将字符串"World"与键"greeting"关联。re......
  • Redis常见命令
    连接Redis服务器在使用Redis之前,首先需要使用redis-cli工具连接到Redis服务器。redis-cli是Redis的命令行界面工具。redis-cli-h<hostname>-p<port>-a<password>-h:指定Redis服务器的主机名或IP地址。-p:指定Redis服务器的端口,默认为6379。-a:指定Redis服务器的密码,如......
  • redis命令实践常用命令详细带例子 中文注释
    面是一些常用Redis命令的实践,包括中文注释和示例。连接Redis服务器在使用Redis命令之前,首先需要连接到Redis服务器。这通常通过Redis客户端工具如redis-cli完成。redis-cli基本操作PING-检查Redis服务器是否运行。PING例子:检查服务器是否响应。redis-cliPING......
  • redis命令实践 详细教程
    Redis是一个高性能的键值对数据库,支持多种数据结构,如字符串、哈希、列表、集合、有序集合等。以下是一份详细的Redis命令实践教程,包括常用命令和示例。1.连接Redis服务器使用redis-cli工具连接到Redis服务器:redis-cli-h<hostname>-p<port>-a<password>-h:指定Redis......
  • Redis常见命令
    连接Redis服务器在使用Redis之前,首先需要使用redis-cli工具连接到Redis服务器。redis-cli是Redis的命令行界面工具。redis-cli-h<hostname>-p<port>-a<password>-h:指定Redis服务器的主机名或IP地址。-p:指定Redis服务器的端口,默认为6379。-a:指定Redis服务器的密码,如......
  • Springboot 开发 -- Redis实现分布式Session
    一、引言在微服务架构和分布式系统中,会话管理(SessionManagement)成为了一个挑战。传统的基于Servlet容器的会话管理方式在分布式环境下无法有效工作,因为用户请求可能会被分发到不同的服务器上,导致会话数据无法共享。为了解决这个问题,SpringSession提供了一种基于外部存储(......