缓存的设计
创始人
2024-04-15 05:44:17
0

文章目录

  • 1. 缓存的更新机制
    • 1.1 被动更新
    • 1.2 主动更新
      • 1.2.1 Cache Aside Pattern (更新数据库,再删除缓存)
      • 1.2.2 更新数据库,更新缓存
      • 1.2.3 先删除缓存,在更新数据库
    • 1.3 Read/Write Through Pattern
    • 1.4 Write Behind Caching Pattern
  • 2. 缓存的清理机制
    • 2.1 时效性清理
    • 2.2 数目阀值清理机制
    • 2.3 软应用清理
    • 2.4 redis 的8中内存淘汰策略
    • 2.5 缓存清理机制的总结
  • 3. 缓存问题
    • 3.1 缓存穿透

1. 缓存的更新机制

1.1 被动更新

为缓存设定过期时间,失效从数据库读取,再次写入缓存

调用方 暂存方(缓存) 数据提供方

被动:有效期到后,再次写入。

  1. 客户端 查数据,缓存中没有,从提供方获取,写入缓存(有一个过期时间t)。

  2. 在t内,所有的查询,都由缓存提供。所有的写,直接写数据库。

  3. 当 缓存数据 t 到点了,缓存 数据 变没有。后面的查询,回到了第1步。

适合:对数据准确性和实时性要求不高的场景。比如:商品 关注的人数。

1.2 主动更新

1.2.1 Cache Aside Pattern (更新数据库,再删除缓存)

这是最常用的更新机制

  • 失效: 应用程序从cache中获取数据,没获取到,则从数据库中读取数据,成功后,放到缓存中
  • 命中: 应用程序从缓存中获取数据,得到后直接返回
  • 更新: 先把数据库中的数据更新,成功后,在将缓存删除

在这里插入图片描述

有可能产生的问题

比方一个读操作,一个写操作的并发,读操作没有了删除缓存的操作,直接命中拿的是缓存中的数据,写操作更新了数据库中的数据,并删除了缓存,读操作读的就是老的数据

但是这种情况只是理论上存在,实际上很少出现,因为这种情况的产生是需要读操作慢于写操作,一般情况下,写操作都是比读操作慢,并且要加事务锁表,所以很少出现这种情况

1.2.2 更新数据库,更新缓存

一般也不采用。
请求被阻塞,
业务要求:修改了数据库,缓存的值需要通过大量时间的计算才能进行更新,影响了响应时间,直接删了缓存,比较节省计算时间,当用户再次去查询的时候,发现缓存的值不存在,用户只要经过一次复杂的计算就能对缓存的值进行更新

1.2.3 先删除缓存,在更新数据库

一般不采用,因为大概率 读比写快。

一个读请求和一个写请求的并发,当写请求进来,把缓存删了,更新数据库这步操作还没完成,读请求进来,发现没缓存,往数据库中读取,这个时候数据库的数据还是老的数据,读请求把老的数据写入了缓存,然后写请求才把数据更新到数据库,这就造成了数据库和缓存的双写一致性问题
在这里插入图片描述

解决双写一致性问题:延迟双删

延迟双删

就是在更新晚数据库之后,sleep一段时间,再次进行删除缓存的操作,能极大的保证双写一致性

在这里插入图片描述

昨天被高德一个面试问:说,你这个延时双删有这么几步操作。如果其中某一步失败了这么办?
删除缓存
更新数据库:事务,回滚就OK。
第二次删除缓存
重试删除:当你前面的操作,无法回滚时,为了保证后续数据的一致性,
(最便宜的做法)硬着头皮往前走,重试。
借用中间件:消息队列,重发消息。
系统外订阅:canal。binlog。
二次删除key,和我们的业务代码解耦。

1.3 Read/Write Through Pattern

这个是直接更缓存打交道,所有的增删改查都在缓存上进行,不会出现数据一致性的问题,但是缓存挂了的话,数据容易丢失

在这里插入图片描述

1.4 Write Behind Caching Pattern

更新数据的操作直接在缓存中进行,然后再异步对数据库进行更新,带来的好处就是数据的IO操作非常的快。带来的问题就是可能产生数据的丢失

2. 缓存的清理机制

2.1 时效性清理

就是给缓存设置一个过期时间,到期自动清理

2.2 数目阀值清理机制

判断缓存中的缓存的数量 达到一定值 ,对缓存进行清理。
阈值:根据自己的业务来定。1g,1m,1024个, 800 80%。

2.3 软应用清理

当空间不足的时候,会被回收

2.4 redis 的8中内存淘汰策略

a) 针对设置了过期时间的key做处理:

  1. volatile-ttl:在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。

  2. volatile-random:就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。

  3. volatile-lru:会使用 LRU 算法筛选设置了过期时间的键值对删除。

  4. volatile-lfu:会使用 LFU 算法筛选设置了过期时间的键值对删除
    b) 针对所有的key做处理 :

  5. allkeys-random:从所有键值对中随机选择并删除数据。

  6. allkeys-lru:使用 LRU 算法在所有数据中进行筛选删除。

  7. allkeys-lfu:使用 LFU 算法在所有数据中进行筛选删除。
    c) 不处理:

  8. noeviction:不会剔除任何数据,拒绝所有写入操作并返回客户端错误信息"(error) OOM command not allowed when used memory",此时Redis只响应读操作。

LRU 算法(Least Recently Used,最近最少使用)
淘汰很久没被访问过的数据,以最近一次访问时间作为参考。(淘汰这段时间中最旧的key)

LFU 算法(Least Frequently Used,最不经常使用)
淘汰最近一段时间被访问次数最少的数据,以次数作为参考。(淘汰这段时间使用次数最少的key)

2.5 缓存清理机制的总结

  1. 时效性清理+数目阀值: 防止:短期内,密集查询,导致缓存空间的急剧增大
  2. lru+软引用:保证热数据,最大限度的提高缓存命中率

3. 缓存问题

3.1 缓存穿透

缓存中没有值,数据库中也没有这个值

产生可能原因

1、自身业务代码或者数据出现问题;
2、一些恶意攻击、 爬虫等造成大量空命中。

问题解决

1. 缓存空对象
注意:对于不存在的空对象,一定要设置过期时间!

String get(String key) {// 从缓存中获取数据String cacheValue = cache.get(key);// 缓存为空if (StringUtils.isBlank(cacheValue)) {// 从存储中获取String storageValue = storage.get(key);cache.set(key, storageValue);// 如果存储数据为空, 需要设置一个过期时间(300秒)if (storageValue == null) {cache.expire(key, 60 * 5);}return storageValue;} else {// 缓存非空return cacheValue;}
}

2. 布隆过滤器

布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在。

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...