什么缓存

缓存就是数据交换的缓冲区,是存储数据临时地方,一般读写性能较高。

缓存作用

缓存的成本

Redis特点

与MySQL的对比

MySQL

Redis

数据结构

结构化

结构化

数据关联

关联

无关联的

查询方式

SQL查询

非SQL

事务特性

ACID

BASE

存储方式

磁盘

内存

扩展性

垂直

水平

使用场景

数据结构固定相关业务数据安全性、一致性要求较大

数据结构固定,对一致性安全性要求不高,对性能有一定要求

Redis实现缓存

Redis缓存作用模型如下

缓存更新策略

内存淘汰

超时提出

主动更新

说明

不用自己维护利用Redis内存淘汰机制,当内存不足时自动淘汰部分数据。下次查询时更新缓存

给缓存添加TTL时间,到期后自动删除缓存,下次查询时更新缓存

编写业务逻辑,再修改数据库的同时,更新缓存

一致性

一般,取决于超时时间设置

维护成本

对于低一致性的需求我们可以采用内存淘汰

对于高一致行的需要我们需要主动更新并设置超时时间

主动更新策略

解决一致性问题时,我们需要注意以下三个问题

1、在更新缓存时应该删除缓存还是直接更新缓存?

直接更新缓存:每次更新数据库时都会进行修改,当写多读少时,无效操作过多。

删除缓存:更新数据库时,让缓存失效,查询时再更新缓存。

经过两种对比下,大多数场景选择之间删除缓存。

2、如何保证缓存与数据库操作同时成功或失败

就是说,如何保证更新缓存的原子性。

单体系统中,将缓存与数据库操作放在同一个事物下。

分布式系统中,利用TCC等分布式事务方案

3、先操作数据库还是操作缓存?

这涉及到多线程并发问题接下来查看删除缓存再操作数据库可能出现的情况。正常情况下如下所示

但是如果在线程1更新数据时有其他线程开始执行查询操作,就会变成如下情况,这样会导致Redis保存的数据仍然是旧数据,从而产生数据不一致问题

那么,接下来查看先更新数据库再删除缓存可能出现的情况。正常情况下如下图所示

但也可能存在如下一种情况,假设线程1先查询缓存,但是由于缓存已经失效比如过期或是Redis中不存在,但是就在从数据库写入缓存前线程2开始执行,从而导致写入缓存的仍然是旧数据。

即使这两种情况都会产生数据不一致的问题,但是总体来说先操作数据库后删除缓存出现数据不一致的概率要低于先删除缓存再更新数据库。因为如果先删除缓存的话,是一个微秒级别的操作,而更新数据库相对来说耗时比较久。在此之间可能会存在其他线程开始查询缓存并查询数据库写入缓存的问题

但如果先更新数据库,期间即使有其他线程查询数据库并更新缓存执行最后也会被更新数据库后的删除缓存操作将旧数据删除。其次,查询数据库操作耗时短,其他线程恰好开始更新数据库的概率低。

因此,更新缓存的最佳方案如下

  1. 低一致性需求:使用Redis自带内存淘汰机制
  2. 高一致性需求:主动更新,并以超时剔除作为兜底方案

读操作:

写操作:

缓存穿透

指查询一个数据库一定不存在的数据,最终导致所有请求打在数据库上,导致数据库压力变大。模型如下

缓存空对象

模型如下

即使查不到数据,也返回一个key提交的数据,valuenull的数据给缓存,并设置一个存活时间。

优点是实现简单维护方便。

缺点是额外内存消耗,可能造成短期的不一致,如果无法忍受数据不一致情况,可以在更新数据库时主动将数据更新到缓存当中

布隆过滤器

模型如下

查询时先通过布隆过滤器判断数据是否存在,如果不存在直接拒接,存在的话才会访问Redis或数据库,布隆过滤器实际上是一个算法,将数据库中存在的数据通过哈希算法得到哈希然后转化为二进制位保存在布隆过滤器当作,当客户端请求发起时,通过判断请求的数据在布隆过滤器对应位置是0还是1。

优点是内存占用少,没有多余的key

缺点是实现复杂,存在误判。判断没有的数据一定没有判断存在但不一定真的存在,还是存在一定穿透的问题。

以上是被动解决方案我们可以主动选择防止被穿透方案

设置id格式然后进行基础格式校验,格式不对不进行查询。给用户进行权限设置

缓存雪崩

指在一个时间段,缓存集中过期失效,在失效的时间段中,所有的访问查询都由数据库来操作,产生周期性的压力波峰。模型图如下

设置不同TTL:将缓存的数据设置不同的失效时间,避免在同一时间集中失效,对于热门的数据,存活时间长一点甚至可以设置永不过期

设置Redis集群为了防止Redis宕机造成的雪崩,要建立Redis集群,从而提高Redis的高可用性

添加降级处理发现Redis出现故障时,应该进行快速失败,而不应该交给服务器处理。

添加多级缓存:浏览器、Nginx或是JVM内部进行缓存,而不是单单只在Redis中进行缓存

缓存击穿

也叫热点key问题。是指一个key非常热点,在不停扛着大并发,大并发集中对于一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求到数据库上。模型图如下

互斥

模型图如下

同一时刻只需要一个线程对数据库访问就可以了,其他线程获取不到锁就休眠一会再去Redis进行查询。

缺点:线程需要等待,会影响性能。当一个线程需要获取多个锁时可能存在死锁风险

优点:没有额外的内存消耗,保证了一致性,实现简单

逻辑过期

模型图如下

不设置TTL的过期时间,而是存储再Value中,如果逻辑时间过期了,那么由一个线程拿到互斥锁后开辟一个新线程去进行数据库查询,重建缓存。其余线程仍然使用逻辑上的旧数据。

缺点:不保证一致性,有额外的内存消耗,实现复杂

优点:性能比较好。

原文地址:https://blog.csdn.net/zmbwcx/article/details/134758410

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_40868.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注