Redis 高频面试题整理

Redis/缓存系统
231
0
0
2024-01-06
标签   Redis

1.Redis 的缓存穿透、缓存击穿、缓存雪崩

一、缓存穿透

  1. 什么是缓存穿透 缓存穿透是指在使用缓存系统时,特定的查询在缓存和数据库中都找不到结果,导致每次查询都要访问数据库,从而增加数据库的压力,降低系统的性能。 当一个查询请求经过缓存系统时,缓存先检查是否有缓存的结果,如果有则直接返回给客户端,如果没有则查询数据库并将结果存入缓存后返回。但是,如果查询的数据在数据库中不存在,那么每次查询都会通过缓存系统直接访问数据库,导致数据库无效查询增加,浪费了系统资源。
  2. 常见的缓存穿透情况
  • 查询不存在的数据:当用户查询一个不存在的数据,例如某个不存在的用户ID,由于缓存中没有缓存该数据,每次查询都会失败并直接访问数据库。
  • 恶意查询:如果攻击者故意发送大量不存在的请求,试图绕过缓存,并导致大量无效的数据库查询请求。
  1. 缓存穿透会带来的问题
  • 增加数据库负载:由于缓存穿透导致大量无效的数据库查询操作,增加了数据库的负载,可能导致数据库性能下降。
  • 击穿缓存:如果缓存中缓存了查询结果为空的键,恶意攻击者可以通过大量请求这些不存在的键,使缓存中的该键过期,从而导致后续请求都直接访问数据库,形成缓存击穿
  1. 解决缓存穿透问题可以采取的方法
  • 布隆过滤器(Bloom Filter):在查询前先通过布隆过滤器快速判断查询的数据是否存在,若不存在则不再访问缓存和数据库,减轻数据库压力。
  • 空结果缓存:在缓存中存储空结果的键,可以避免缓存穿透,防止恶意攻击。
  • 延迟双写:在查询到数据库不存在该数据时,在缓存中也写入一个空结果的占位符,设置较短的过期时间,以防止并发大量请求穿透缓存直接访问数据库。
  • 异步更新缓存:当发现缓存和数据库中都不存在某个查询结果时,可以使用异步更新缓存的方式,先返回空结果给用户,然后通过后台任务去查询数据库并更新缓存,提高查询的响应速度和系统的并发能力。
  1. 总结 综上所述,缓存穿透是一种常见的缓存问题,采取适当的预防措施可以避免对数据库造成不必要的压力,并提高系统的性能和稳定性。

二、缓存击穿

  1. 什么是缓存击穿 缓存击穿是指在使用缓存系统时,一个热门的、经常被访问的数据缓存过期或失效时,大量并发请求同时涌入,直接访问数据库,导致数据库负载剧增,造成系统性能下降甚至崩溃的情况。
  2. 常见的缓存击穿情况
  • 高并发热点数据:某个数据非常热门,并且被大量并发请求频繁访问。如果该数据的缓存过期或者被意外清空,大量的请求会直接访问数据库,导致数据库压力激增。
  • 突发请求:在某个时间点突然出现大量请求访问某个数据,而该数据的缓存恰好在此时失效,导致大量请求绕过缓存直接访问数据库。
  1. 缓存击穿会带来的问题
  • 增加数据库负载:大量并发请求同时访问数据库,导致数据库性能下降,甚至崩溃。
  • 响应时间延长:绕过缓存直接访问数据库,数据库响应时间增加,造成请求的响应时间延长。
  1. 解决缓存击穿问题可以采取的方法
  • 加锁或互斥机制:在缓存失效时,只允许一个请求访问数据库,并将结果缓存,其他请求等待并从缓存中获取数据。
  • 热点数据永远不过期:对于热点数据,可以将其缓存时间设置为永不过期,或者设置一个合理的较长过期时间,确保不会频繁去访问数据库。
  • 异步更新缓存:当某个热点数据的缓存过期时,可以使用异步任务来更新缓存,先返回旧的缓存结果给请求,然后在后台异步更新缓存。
  • 限流和降级:对于突发的大量请求,可以采取限流策略,限制并发访问的请求数量,或者通过降级策略返回预设的默认值,避免数据库负载过大。
  • 前置缓存:在缓存层之前添加一个前置缓存(如CDN等),将请求分摊到多个缓存节点,减轻热点数据的单一缓存节点压力。
  1. 总结 综上所述,缓存击穿是一种常见的缓存问题,通过合理的缓存策略、并发控制和异步更新缓存等手段可以有效避免和应对缓存击穿问题,提高系统的性能和稳定性。

三、缓存雪崩

  1. 什么是缓存雪崩 缓存雪崩是指在使用缓存系统时,大量缓存失效或过期,导致原本应该由缓存提供的数据,都需要从数据库中重新加载,从而引发数据库压力剧增、性能下降,甚至系统崩溃的现象。
  2. 常见的缓存雪崩情况
  • 缓存批量失效:多个缓存键的过期时间或失效时间几乎同时到达,导致大量缓存同时失效。
  • 重启或故障:缓存系统出现重启、宕机或故障,导致缓存中的所有数据一时无法访问,请求直接访问数据库。
  • 数据库压力:当缓存失效后,大量请求同时涌入数据库,因为数据库无法承受如此大的压力而导致性能下降。
  1. 缓存雪崩会带来的问题
  • 数据库压力过大:大量请求直接访问数据库,导致数据库处理能力不足,出现性能问题,甚至引发数据库崩溃。
  • 响应时间延长:由于缓存失效,请求需要直接访问数据库,导致响应时间延长。
  1. 解决缓存雪崩问题可以采取的方法 设置随机过期时间:为了避免大量缓存同时失效,可以为不同的缓存设置稍有差异的过期时间,分散缓存过期的可能性。
  • 二级缓存机制:使用多级缓存,将数据同时存储到多个缓存层,一级缓存失效时可以从二级缓存中获取数据,避免所有缓存同时失效。
  • 并发重建缓存:在缓存失效的时候,通过加锁或者分布式锁的方式,只允许一个请求去加载数据并重新构建缓存,其他请求等待并从缓存中获取数据。
  • 缓存预热:在系统低峰期,提前加载热门的缓存数据,避免在高峰期同时加载大量缓存数据。
  • 容灾备份:设置多个缓存节点,保证缓存的高可用性,一旦某个缓存节点发生故障,可以快速切换到其他节点。
  • 异步更新缓存:对于热点数据,可以使用异步任务来更新缓存,避免大量的请求同时涌入数据库。
  1. 总结 综上所述,缓存雪崩是一种常见的缓存问题,在系统设计和缓存策略上采取合理的措施可以有效预防和处理缓存雪崩,提高系统的可用性和稳定性。

四、Redis问题

Redis的缓存穿透、缓存击穿和缓存雪崩都是与缓存相关的常见问题,它们有一些共同点,并可以采用类似的解决方法:

  1. 共同点: 都会导致大量请求直接访问数据库,增加数据库负载和降低系统性能。 都与缓存失效或过期相关,导致缓存无法提供预期的数据。
  2. 解决方法: 设置合理的缓存策略:包括设置适当的缓存过期时间、根据业务情况决定是否使用永不过期的策略,避免缓存同时失效或过期导致的问题。
  • 使用布隆过滤器(Bloom Filter):在查询前使用布隆过滤器快速判断查询的数据是否存在,避免无效的数据库查询操作。
  • 多级缓存机制:使用多级缓存,将数据同时存储到多个缓存层,一级缓存失效时可以从其他级别的缓存获取数据,避免所有缓存同时失效。
  • 并发控制机制:通过加锁或互斥机制控制并发访问数据库的请求数量,防止缓存失效时大量请求同时涌入数据库。
  • 异步更新缓存:针对热点数据,使用异步任务来
https://blog.csdn.net/qq_48595067/article/details/131710868

2.redis大key问题

所谓的bigkey就是存储本身的key值空间太大,或者hash,list,set等存储中value值过多。

主要包括:

  • 单个简单的key存储的value很大
  • hash, set,zset,list 中存储过多的元素
  • 一个集群存储了上亿的key

bigkey会带来一些问题,如:

  • 读写bigkey会导致超时严重,甚至阻塞服务。
  • 大key相关的删除或者自动过期时,会出现qps突降或者突升的情况;极端情况下,会造成主从复制异常,Redis服务阻塞无法响应请求。

BigKey 问题怎么定位

  • 使用 redis 自带的命令 redis-cli --bigkeys 在线扫描大 key,显示的信息不详细,并且这个命令不是阻塞的,所以不影响 redis 的正常使用。
  • 使用第三方工具 redis-rdb-tools,使用过程中会先使用 bgsave 命令 dump 一个 rdb 镜像,然后对这个镜像进行分析,因为 bgsave 是 redis 中的一个子线程进行生成镜像的,并不影响 redis 对外提供服务。
  • debug object 方法

总结

  • 对于 BigKey 的问题的原因:也就是 Redis 键值对中对应的 value 比较大。
  • 对于 BigKey 问题的发现:可以通过第三方工具或者自带的命令进行扫描发现。
  • 对于 BigKey 问题的解决方案:通过拆分,压缩,清理无效数据等方法对这些大 value 进行处理即可。

3.redis热key问题

热点Key带来的问题

  • Redis节点负载过高:当某些key被频繁访问时,会导致Redis节点负载过高,从而影响Redis的性能和稳定性。
  • Redis集群负载不均:当某些key被频繁访问时,会导致所在节点负载过重,而其他节点负载较轻,从而使Redis集群负载不均衡。
  • Redis集群性能下降:当某些key的访问频率特别高时,会导致Redis节点的CPU、内存、网络等资源负载过重,从而影响Redis的性能,甚至导致Redis宕机。
  • 数据不一致:当某些key成为热点key时,如果数据量较大或者更新频率较快,可能会导致数据不一致的问题,比如缓存中的数据和数据库中的数据不一致,不同节点的数据不一致。
  • 缓存击穿:当某些key的访问频率特别高时,如果这些key的数据过期或被删除,而恰好有大量的请求同时访问这个key,会导致这些请求直接访问后端数据库,从而造成缓存击穿的问题。

如何检测热点Key

Redis提供了一些监控工具,如 Redis monitorredis-stat,可以用来监控Redis实例的运行状态。通过这些工具,我们可以观察到访问频率较高的Key,以及它们对Redis性能的影响。

  • Redis monitor: 使用redis-climonitor命令,可以实时查看Redis实例的命令执行情况。通过分析输出的日志信息,可以找到访问频率较高的Key。
  • redis-stat: redis-stat是一个实时监控Redis实例的工具,它可以展示包括命令执行次数、内存使用情况等指标。通过观察这些指标,可以发现热点Key对Redis性能的影响。
https://zhuanlan.zhihu.com/p/624724087

4.Redis过期键删除策略

  • 定时删除:在设置键的过期时间时,创建一个定时器,当到达键过期时间时通过定时器去删除键。
  • 惰性删除:惰性删除并不是当到达过期时间时去删除,而是每次获取键时,会判断是否过期,如果过期则删除,并返回空;没过期,就返回键值。
  • 定期删除:每隔一段时间,就对数据库中的键进行检查,如果过期则删除。至于要删除多少什么时候删除,则是通过具体程序决定。
https://www.cnblogs.com/better-farther-world2099/articles/16159375.html
https://blog.csdn.net/weixin_39992884/article/details/128407952

5.Redis缓存淘汰策略

Redis共提供了8中缓存淘汰策略,其中 volatile-lfu 和 allkeys-lfu 是 Redis 4.0 版本新增的。

  • noeviction:不进行淘汰数据。一旦缓存被写满,再有写请求进来,Redis就不再提供服务,而是直接返回错误。Redis 用作缓存时,实际的数据集通常都是大于缓存容量的,总会有新的数据要写入缓存,这个策略本身不淘汰数据,也就不会腾出新的缓存空间,我们不把它用在 Redis 缓存中。
  • volatile-ttl:在设置了过期时间的键值对中,移除即将过期的键值对。
  • volatile-random:在设置了过期时间的键值对中,随机移除某个键值对。
  • volatile-lru:在设置了过期时间的键值对中,移除最近最少使用的键值对。
  • volatile-lfu:在设置了过期时间的键值对中,移除最近最不频繁使用的键值对
  • allkeys-random:在所有键值对中,随机移除某个key。
  • allkeys-lru:在所有的键值对中,移除最近最少使用的键值对。
  • allkeys-lfu:在所有的键值对中,移除最近最不频繁使用的键值对
https://www.swvq.com/boutique/detail/tanfkkig
https://cloud.tencent.com/developer/article/1557689?from=15425

6.Redis集群方式

主从复制

哨兵模式

Cluster 集群模式(Redis官方)

自研型

https://www.cnblogs.com/sfzlstudy/p/16615233.html

Redis 集群没有使用一致性 hash,而是引入了虚拟槽分区的算法。会把Redis 集群分成16384 个槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽。集群的每个节点负责一部分hash槽。

  • 客户端分片 jedis
  • 代理分片 Twemproxy

为什么只有16384个槽 (2^14)

https://www.cnblogs.com/rjzheng/p/11430592.html
https://blog.csdn.net/weixin_36755535/article/details/126789580
https://blog.csdn.net/weixin_51095543/article/details/125287604
crc16()一共可以有:2^16-1=65535

主要原因是集群间的redis进行ping/pon通讯消息时,如果使用65535则消息头达8k,而使用16384 则只有2k

65535 / 8 (8bit/byte)/1024(1k)=7.99 Kbytes  
16384 / 8 (8bit/byte)/1024(1k)=2 Kbytes
https://blog.csdn.net/qq_41960367/article/details/127975998

7.Redis RDB与AOF

redis提供两种方式进行持久化

  • RDB(Redis DataBase)持久化,原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化
  • AOF(Append Only File)持久化,原理是将Reids的操作日志以追加的方式写入文件

二者的区别

  • RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程就是有一个fork子进程,先将数据集写入到临时文件中,写入成功后,再替换之前的文件,用二进制压缩存储。
  • AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

二者优缺点

  • RDB的优缺点: 优点:RDB持久化文件,速度比较快,而且存储的是一个二进制文件,传输起来很方便。 缺点:RDB无法保证数据的绝对安全,有时候就是1s也会有很大的数据丢失。
  • AOF的优缺点: 优点:AOF相对RDB更加安全,一般不会有数据的丢失或者很少,官方推荐同时开启AOF和RDB。 缺点:AOF持久化的速度,相对于RDB较慢,存储的是一个文本文件,到了后期文件会比较大,传输困难。

常用配置

  • RDB持久化配置

Redis会将数据集的快照dump到dump.rdb文件中。此外,也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,搜索save,可以看到下面的配置信息:

save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。 save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。 save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。
  • AOF持久化配置

在Redis的配置文件中存在三种同步方式,它们分别是:

appendfsync always #每次有数据修改发生时都会写入AOF文件。 appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。 appendfsync no #从不同步。高效但是数据不会被持久化。

8. redis的使用场景

  • 缓存 缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。
  • 数据共享;分布式会话 集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。
  • 分布式锁 在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多。
  • 全局ID
  • 计数器 什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。
  • 限流
  • 消息系统:消息队列 list 消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。
  • 社交网络:好友关系、用户关注 set / 点赞、签到、打卡 set 点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。
  • 排行榜 zset 很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。
  • 商品标签、人的标签等 set

9. redis的数据类型

  • 六种基础数据结构:动态字符串,链表,字典,跳跃表,整数集合和压缩列表
  • 十种数据类型
string(字符串)
hash(哈希)
list(列表)
set(集合)
zset(有序集合)
stream(流)
geospatial(地理)
bitmap(位图)
bitfield(位域)
hyperloglog(基数统计)

https://www.cnblogs.com/reim/p/17377883.html
https://blog.csdn.net/qq_35549286/article/details/126639070
https://www.cnblogs.com/reim/p/17377883.html

10. 缓存数据一致性

https://zhuanlan.zhihu.com/p/457375259
https://www.cnblogs.com/longe-blog/p/15638220.html
https://blog.csdn.net/qq_22156459/article/details/125496995
https://www.cnblogs.com/zhtzyh2012/p/15038151.html