Redis

目录

1.什么是缓存穿透?怎么解决?
2.什么是缓存击穿?怎么解决?
3.什么是缓存雪崩?怎么解决?
4.redis做为缓存,mysql的数据如何与redis进行同步呢?(双写一致性)
5.Redis作为缓存,是怎么实现数据的持久化的?
6.Redis的key过期后,会马上删除吗?
7.Redis的数据淘汰策略有哪些?
8.Redis集群有哪些方案?
9.Redis是单线程的,为什么还这么快呢?
10.Redis的8种数据类型

1~5

1.什么是缓存穿透?怎么解决?

  • 缓存穿透就是查询一个一定不存在的数据,如果从缓存层查询不到,导致这个不存在的数据每次请求都要到数据库去查询,可能导致数据库挂掉。

解决方案:

缓存空字符串:

查询的数据在Redis和数据库中都查不到时缓存空字符串并设置有效期,有效期内再查询该数据就会返回一个空字符串,而不会再查询数据库

  • 优点:简单,易于维护
  • 缺点:
  1. 额外占用内存
  2. 可能存在短期的不一致(比如查询一个id,查询的时候没有,缓存了空字符串,在空字符串有效期内又添加了这个id的数据就会造成不一致)

布隆过滤器:

在客户端和Redis的中间加一层布隆过滤器,查询数据的时候先到布隆过滤器中查询,有则继续查询Redis,没有则直接结束。

在进行缓存时,要同时进行缓存预热,把数据的id存到布隆过滤器中

布隆过滤器是一个 bitmap(位图): 相当于是以(bit)位为单位的数组,数组中每个单元只能存储二进制数 0或1

布隆过滤器作用: 布隆过滤器可以用于检索一个元素是否存在一个集合中(经过某种哈希算法计算)。

如果我们要映射一个值到布隆过滤器中,需要使用多个 不同的哈希函数 生成多个哈希值,并将bit向量里位置 等于哈希值的元素设置为1。例如针对值 Id=1的数据 进行三个不同的哈希函数分别生成了哈希值 1、3、7,则布隆过滤器转变为:

布隆过滤器存在误判: 例如查询一个不存在的id=3 ,而id为3解析出的哈希值3、9、12分别在之前预热id=1和id=2时布隆过滤器对应的位置转变为了1,所以id=3其实不存在但是布隆过滤器的结果依然判定为存在

误判率:数组越大误判率越小,但占用的内存也越大

  • 优点:内存占用少,没有多于的key
  • 缺点:
  1. 实现复杂
  2. 可能会存在误判或者漏判(布隆过滤器中不存在就是真的不存在,但存在不一定真的存在)

2.什么是缓存击穿?怎么解决?

缓存击穿的意思是对于设置了过期时间的key,缓存在某个时间点过期的时候,恰好这时间点对这个Key有大量的并发请求过来,而数据库再重新缓存数据需要一定的时间,这个时间内大量的请求可能会瞬间把数据库压垮。

解决方案有两种方式:

互斥锁: 缓存中有数据直接返回,没有数据就获取互斥锁,互斥锁内查询数据库获取结果并写入缓存,最后释放锁。在该线程释放锁之前其他线程都不能获取锁且不能查询数据库,只能睡眠一段时间后重试,如果能命中缓存,则返回数据,否则尝试获取互斥锁。(可以用setnx【有值不添加,没值添加】命令实现)

  • 优点:可以保证数据的强一致性
  • 缺点:
  1. 性能不高
  2. 可能产生死锁(锁需要等)

设置key逻辑过期:

①:在设置key的时候,设置一个过期时间字段一块存入缓存中,不给当前key设置过期时间
②:当查询的时候,从redis取出数据后判断时间是否过期
③:如果过期则开通另外一个线程进行数据同步,当前线程正常返回数据,这个数据不是最新

  • 优点:性能较高
  • 缺点:不能保证数据的强一致性

3.什么是缓存雪崩?怎么解决?

缓存雪崩:

大量的key设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到数据库,数据库瞬时压力过重雪崩。(与缓存击穿的区别:雪崩是很多key,击穿是某一个key缓存。)

解决方案:

将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

4.redis做为缓存,mysql的数据如何与redis进行同步呢?

延迟双删:

对于写操作,先删除缓存中的数据,再更新数据库,最后延时删除缓存中的数据。

  • 优点:读操作不受影响
  • 缺点:不能保证强一致性(并发情况下可能会有脏数据)

读写锁:

读写锁 允许多个线程同时读 ,但 只允许一个线程写 。当有线程写时,其他线程既不能读也不能写,直到写操作完成。

读取数据:
在读取数据时,先尝试获取读锁,如果成功则从缓存读取数据,如果缓存没有数据再从数据库读取,然后释放读锁。
更新数据:
在更新数据时,先获取写锁,然后更新数据库,再更新缓存,最后释放写锁。
这样,多个读线程可以同时读取缓存中的数据,但当有写线程在更新数据时,所有的读线程和写线程都会被阻塞,保证了数据的一致性。

  • 优点:保证强一致性
  • 缺点:当有写操作时,会阻塞所有读操作,可能导致读操作的响应时间增加

如何选择

高读取频率场景: 如果系统读取操作远远多于写入操作,可以考虑使用 读写锁 方案,优化读取性能。
写入频率较高场景: 如果系统写入操作比较频繁,可以考虑使用 延迟双删 方案,降低写入时的锁竞争,提高写入效率。

5.Redis的持久化

在Redis中提供了两种数据持久化的方式:

1、RDB 2、AOF(对数据安全性要求高的可以用AOF,要求没这么高的可以用RDB, 也可以两个一起用 )

两种持久化方式有什么区别:

  • RDB是一个快照文件,它是把redis内存存储的数据写到磁盘上,当redis实例宕机恢复数据的时候,可以从RDB的快照文件中恢复数据。
  • AOF是追加文件,在redis操作写命令的时候,都会存储这个文件中,当redis实例宕机恢复数据的时候,会从这个文件中再次执行一遍命令来恢复数据

这两种方式,哪种恢复的比较快呢?

  • RDB更快,因为它是二进制文件,在保存的时候体积也是比较小的,所以它恢复的比较快,但是它有可能会丢数据
  • AOF恢复的速度慢一些,但是它丢数据的风险要小很多,在AOF文件中可以设置刷盘策略,比如设置的就是每秒批量写入一次命令

6~10

6.Redis的key过期后,会马上删除吗?

不会,Redis中有两种数据过期删除策略

  • 第一种是 惰性删除 ,就是在key过期后,不管它,等到再次get这个key的时候才会把它删除
  • 第二种是 定期删除 ,就是每隔一段时间,就会检查一些key,删除里面过期的key,然后定期删除有两种模式:
  1. SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,可以通过redis.conf的hz选项来调整这个次数
  2. FAST模式执行频率不固定,每次事件循环会尝试执行,但是两次间隔不低于2ms,每次耗时不超过1ms
  • Redis的过期删除策略是定期删除惰性删除两种策略配合使用的

7.Redis的数据淘汰策略有哪些?

在redis中提供了很多种数据淘汰策略,默认是noeviction,不删除任何数据,内存不够会直接报错,可以在redis的配置文件里设置,里面有两个非常重要的概念,一个是LRU,另外一个是LFU

  • LRU的意思就是最少最近使用,用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
  • LFU的意思是最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高

数据库有1000万数据 ,Redis只能缓存20w数据, 如何保证Redis中的数据都是热点数据 ?

  • 可以使用 allkeys-lru (挑选最近最少使用的数据淘汰)淘汰策略,留下来的都是经常访问的热点数据

Redis的内存用完了会发生什么?

  • 要看redis的数据淘汰策略是什么,如果是默认的配置,redis内存用完以后则直接报错。如果是 allkeys-lru 策略,会把最近最常访问的数据留在缓存中。

8.Redis集群有哪些方案?

在Redis中提供的集群方案总共有三种:主从复制、哨兵模式、Redis分片集群

主从复制 : 主从复制是指将一个 Redis 服务器的数据复制到其他的 Redis 服务器,其中一个为主服务器,其余的为从服务器。主服务器负责写操作,从服务器负责读操作。主从复制的好处在于,从服务器可以用来支持读操作,分担主服务器的读压力,同时也增加了数据的冗余备份。如果主服务器出现故障,可以将一个从服务器提升为新的主服务器。
哨兵模式 : 哨兵模式用于监控 Redis 主从复制中的主服务器状态。它的任务包括监控主服务器的健康状况,当主服务器出现故障时自动将从服务器升级为新的主服务器,以及管理客户端与 Redis 服务器的连接。哨兵模式可以用来实现 Redis 的高可用性,确保系统在主服务器故障时能够快速切换到从服务器。
Redis分片集群 : Redis 分片集群用于解决单个 Redis 服务器的性能瓶颈问题。它将数据分成多个分片存储在不同的 Redis 节点上,每个节点只负责一部分数据。客户端根据分片规则将数据分配到不同的节点上。分片集群可以水平扩展,通过增加节点来增加系统的容量和性能。

这些架构模式可以根据业务需求进行选择和配置。主从复制和哨兵模式适合需要高可用性的场景,分片集群适合需要高性能和大规模存储的场景。

9.Redis是单线程的,为什么还这么快呢?

  • C语言编写的
  • 基于内存存储
  • Redis之父Antirez(全名Salvatore Sanfilippo)很强,写的代码很优雅
  • 采用单线程,避免不必要的上下文切换可竞争条件
  • 使用 I/O多路复用模型 ,非阻塞IO,比如:bgsave 和 bgrewriteaof 都是在后台执行操作,不影响主线程的正常使用,不会产生阻塞

I/O多路复用模型?

I/O多路复用是指利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。 目前的I/O多路复用都是采用的epoll模式实现,它会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不需要挨个遍历Socket来判断是否就绪,提升了性能。其中Redis的网络模型就是使用I/O多路复用结合事件的处理器来应对多个Socket请求,比如,提供了连接应答处理器、命令回复处理器,命令请求处理器;在Redis6.0之后,为了提升更好的性能,在命令回复处理器使用了多线程来处理回复事件,在命令请求处理器中,将命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程。

10.Redis的8种数据类型

一共是八种,String、Hash、Set、List、Zset、Hyperloglog、Geo、Streams

  • HyperLogLog:它是一种用于基数(cardinality)估算的数据结构,主要用于对大数据集合的去重计数。在需要统计一个集合中不同元素的数量时,HyperLogLog 提供了一种高效的方法,可以使用固定的内存来估算元素的数量,而不需要存储每个元素本身。
  • Geo:Redis 的地理位置功能允许你将地理位置信息(经度和纬度)与字符串键关联起来,这样你就可以进行各种地理位置相关的操作,比如查找附近的位置、计算距离等。这对于需要处理地理位置数据的应用,如地图服务或位置分析,非常有用。
  • Streams:Redis Streams 是一种新的数据类型,用于处理实时数据流。它类似于一个日志数据结构,你可以往其中不断添加新的消息,然后按照时间顺序逐个读取这些消息。Streams 可以用于构建实时消息队列、日志收集、事件处理等场景,非常适合需要处理实时事件数据的应用。
end
Redis

评论区

暂无评论