redis面试八股文总结

1.为什么使用缓存?

mysql:关系型数据库,基于磁盘存储

redis:非关系型数据库;基于内存存储;读写速度快,极大地提高应用的响应速度和吞吐量。

2 使用缓存会带来哪些问题?

  1. 数据不一致:指缓存中的数据与数据库中的数据不一致
    ✅更新数据库后,缓存未更新:导致读取到旧数据。
    ✅缓存更新成功,数据库更新失败:缓存中有新数据,数据库中是旧数据。
    ✅并发更新:多个操作同时更新同一数据,导致数据不一致。
    2.缓存穿透:大量请求查询不存在的数据,导致请求直接打到数据库。

✅请求的key在缓存和数据库中都不存在。

✅恶意攻击者可能使用大量不存在的key进行查询。
解决方案

缓存空数据:查询返回的数据为空,仍把这个空结果进行缓存

布隆过滤器:检查一个元素是否在一个集合中,拦截不存在的数据
3.缓存击穿:某个热点key在过期瞬间,大量请求同时访问,导致请求直接打到数据库,导致瞬间压力过大
解决方案

添加互斥锁:一个线程查询未命中,获取互斥锁后查询数据库重建缓存数据,其他线程获取锁失败只能休眠一会重试

逻辑过期:
4.缓存雪崩:由于大量缓存同时过期或Redis宕机,导致数据库面临巨大访问压力
解决方案

给不同key的TTL添加随机值:尽量不让key同时过期

利用redis集群提高服务的可用性:防止宕机

给缓存业务添加降级限流策略:ngxin等当中设置限流规则

给业务添加多级缓存:预防大量key过期

3 redis为什么这么快?

  1. 内存存储:所有数据存储在内存中,内存的读写速度远快于磁盘
  2. 单线程模型:在任何时刻只有一个命令在执行,避免了线程切换和锁竞争带来的消耗。
    ⚠️:Redis6.0+:多线程只用于网络IO,命令执行仍然是单线程
    单线程运行快的原因:避免多线程带来的开销。多线程需要切换上下文,还可能有锁竞争的问题,都会消耗额外的资源。
  3. 高效的数据结构-散列表,通过key去查找value String字符串、 Hash字典、 List列表、 Set集合、 zSet有序集合
  4. I/O 多路复用 (如 epoll、kqueue、select)来同时监听多个 socket 的读写事件。当某个 socket 有事件发生时,Redis 会处理该事件,这样就能使用一个线程处理大量的并发连接。

4. redis数据结构的底层实现

  1. string

  2. list 底层是压缩列表(ziplist)

    当列表较长时,会变成双向链表(linkedlist)

  3. Hash 内容少,用ziplist 内容多,底层是哈希表(hash table)。使用拉链法避免冲突;redis obj会有两个map结构:ht0和ht1。一般只用到一个,当需要扩容和缩容的时候,才会用到另外一个。

  4. set 数据少的时候使用整数集合(intset) 数据多,使用哈希表

  5. sorted 数据少 ziplist 数据多 跳表(skip list)可参考

5.redis数据类型使用场景

  1. string字符串。
    缓存功能、计数、共享session、限速
  2. hash键值对,key是字符串,value是Map集合。比如value = {name: '沉默王二', age: 18},name 和 age 属于字段 field,沉默王二 和 18 属于值 value。
    缓存用户信息、缓存对象
  3. list字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。
    消息队列、文章列表
  4. set集合-字符串的无序集合,集合中元素唯一。
    标签(tag)、共同关注
  5. sorted set 有序集合,比 set 多了一个排序属性 score(分值)
    用户点赞统计、用户排序

6.持久化

6.1 为什么要持久化

redis是基于内存存储的,速度快但易失数据。为确保数据在突发事件中不会丢失。Redis提供了三种持久化机制:RDB、AOF和混合持久化。

6.2 RDB 二进制快照持久化

在指定的时间间隔内,将内存中的数据集快照写进磁盘。

可通过 save 和 bgsave 命令两个命令来手动触发 RDB 持久化操作
save 命令:会同步 地将 Redis 的所有数据保存到磁盘上的一个 RDB 文件中。这个操作会阻塞所有客户端请求直到 RDB文件被完全写入磁盘。

当 Redis 数据集较大时,使用 SAVE 命令会导致 Redis 服务器停止响应客户端的请求

不推荐在生产环境中使用,除非数据集非常小,或者可以接受服务暂时的不可用状态。
bgsave 命令:会在后台异步 地创建 Redis 的数据快照,并将快照保存到磁盘上的 RDB 文件中。这个命令会立即返回,Redis 服务器可以继续处理客户端请求。

在 BGSAVE 命令执行期间,Redis 会继续响应客户端的请求,对服务的可用性影响较小。快照的创建过程是由一个子进程完成的,主进程不会被阻塞。是在生产环境中执行 RDB 持久化的推荐方式。

6.3 AOF 日志持久化

当 AOF 持久化功能被启用时,Redis 服务器会将接收到的所有写命令(比如 SET, LPUSH, SADD 等修改数据的命令)追加 到 AOF 缓冲区(buffer)的末尾。
always :每次写命令都会同步到 AOF 文件,这提供了最高的数据安全性,但可能因为磁盘 I/O 的延迟而影响性能。
everysec (默认):每秒同步一次,这是一种折衷方案,提供了较好的性能和数据安全性。如果系统崩溃,最多可能丢失最后一秒的数据。
no:只会在 AOF 关闭或 Redis 关闭时执行, 或由操作系统内核触发。在这种模式下,如果发生宕机,那么丢失的数据量由操作系统内核的缓存冲洗策略决定。

6.4 混合持久化 RDB+AOF(redis4.0+)

7.redis到底是单线程还是多线程

redis 6.0版本之前的单线程是指:其网络I/O和键值对读写是由一个线程完成的

redis 6.0引入的多线程是指:网络请求过程采用了多线程,而键值对读写命令仍然是单线程处理

8. 布隆过滤器是如何解决缓存穿透的?有何优缺点?

布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于快速检查一个元素是否存在于一个集合中。布隆过滤器由一个长度为 m 的位数组和 k 个哈希函数组成。

但是布隆过滤器也有一定的缺点,因为是通过哈希函数计算的,所以存在哈希冲突的问题,可能会导致误判。

9. redis与mysql双写一致性

9.1 读取数据逻辑

1.尝试读取缓存,有数据--返回

2.没有数据--查询mysql数据库并将返回数据,同时将数据存储在redis中,设置过期时间(避免占用redis内存

9.2 写数据流程

延迟双删:删除缓存;在修改数据库;(延迟一会);删除缓存

10. redis过期键删除策略

  1. 惰性删除:当访问key时,才判断key是否过期,过期则删除
    优点:对CPU友好,用不到的key不用浪费时间检查
    缺点:对内存不友好,一个key已经过期,但一直没有使用,该key就会一直在内存中永远不释放
  2. 定期删除:每隔一段时间,对key进行检查,删除里面过期的key(从一定数量的数据库取一定量的key)
    优点:可以通过限制删除频率和时长减少对CPU影响
    缺点:难以确定频率和时长

11. redis缓存淘汰算法

  1. 先进先出FIFO:根据缓存存储时间,离当前最远的数据优先被淘汰
  2. 最近最少使用LRU:根据最近被使用的时间,离当前最远的数据优先被淘汰
  3. 最不经常使用LFU:在一段时间内,缓存数据被使用次数最少的优先淘汰

12. redis主从复制

主从复制:将一台redis服务器的数据,复制到其他的redis服务器。前者称为主节点(master),后者称为从节点(slave)。

数据的复制是单向的,只能从主节点到从节点。一个数据库可以有多个从节点,但是只能有一个主节点。

Redis主从复制分为全量复制和增量复制。

  1. 全量复制
    当从节点第一次连接主节点时,会触发全量复制。
    主节点会生成一个RDB快照文件发送给从节点,同时将期间的写命令缓存在内存中;等RDB文件发送完成后,再发送缓存中的写命令给从节点。
    从节点先清空自己的旧数据,然后加载RDB文件,再执行缓存的写命令。
  2. 增量复制
    当主从节点之间网络断开重连后,如果条件允许,主节点会将断开期间收到的写命令发送给从节点,从而保持数据一致。

过程原理

13. redis哨兵模式

主从复制存在一个问题,没法完成自动故障转移。哨兵就可以解决。

它由两部分组成:哨兵节点和数据节点

  1. 哨兵节点: 哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的 Redis 节点,不存储数据,对数据节点进行监控
  2. 数据节点: 主节点和从节点都是数据节点

哨兵功能

  • 集群监控:负责监控redis的主从进程是否正常运行
  • 消息通知:某个redis实例有故障,哨兵负责发送信息作为报警 通知给管理员
  • 故障转移:主节点挂了,自动转移到从节点上
  • 配置中心:发生故障转移,通知客户端新的主节点地址

哨兵模式实现原理

  • 监控:
    每个 Sentinel 以 1s/次 的频率向它所监控的主节点、从节点以及其他 Sentinel 实例发送 PING 命令。
  • 主观下线和客观下线
    当这些节点超过 down-after-milliseconds 没有进行有效回复,Sentinel 会将该实例标记为主观下线
    当 Sentinel 将一个主节点判断为主观下线后,它会向其他 Sentinel询问,看它们是否也认为该主节点主观下线。当足够数量的 Sentinel 在指定时间范围内都报告主节点主观下线,那么该主节点会被标记为客观下线
  • 选举领导者 Sentinel
    客观下线之后,Sentinel 通过 Raft 算法选举一个领导者 Sentinel 来进行故障转移。
  • 故障转移
    在已下线主节点的从节点中,挑选一个作为新的主节点。挑选规则:优先级高and复制偏移量大

14. redis集群(Cluster)

  • 数据分区
    采用 哈希槽(Hash Slot) 进行数据分布,无需手动分片。redis cluster 有16384个槽。
    每个键通过哈希算法(CRC16)映射到这些槽上,每个集群节点负责管理一定范围内的槽。
  • 高可用
    集群支持主从复制和主节点的 自动故障转移 (与哨兵类似),当任一节点发生故障时,集群仍然可以对外提供服务。

15. redis集群方案

主从复制、哨兵模式、集群

16.redis分布式锁

分布式锁需要满足:

  • 互斥性 - 同一时刻只有一个客户端能持有锁
  • 防死锁 - 锁必须有超时机制,避免持有者崩溃后锁无法释放
  • 安全性 - 只能由加锁者自己解锁(防误删)
  • 高可用 - Redis 集群故障时仍能正常工作

实现方案

  1. SET NX EX(推荐
bash 复制代码
SET lock_key unique_value NX EX 10
  1. SETNX + EXPIRE(不推荐
bash 复制代码
SETNX lock_key unique_value
EXPIRE lock_key 10

问题与解决

  • 锁提前过期,业务还在执行(看门狗机制,自动续期)
  • 加锁和释放锁不是同一个线程的问题(在value中存入uuid-线程唯一标识。删除锁时判断该标识,使用lua保证原子性)
  • 主从切换导致锁丢失(使用redLock解决)

17. 热key

在很短时间内被频繁访问的键。比如,热门新闻或热门商品。

解决方案:

  • 本地缓存(多级缓存)
    将热key缓存在应用服务器的本地内存中(如Guava Cache、Caffeine),减少对Redis的访问。
  • 热key拆分
    将一个热key拆分为多个key,分散到不同节点。
  • 读写分离
    主节点处理写请求
    多个从节点处理读请求,分摊读压力

18.大key

  • 大 key 指的是存储了大量数据的键,比如:单个简单的 key 存储的 value 很大,size 超过 10KB
    hash,set,zset,list 中存储过多的元素(以万为单位)
  • 大 key 会造成什么问题呢?
    客户端耗时增加,甚至超时
    对大 key 进行 IO 操作时,会严重占用带宽和 CPU,造成 Redis 集群中数据倾斜
    主动删除、被动删等,可能会导致阻塞
  • 大 Key 的检测
    使用 redis-cli --bigkeys 命令,可以统计最大 key。
    使用第三方工具,如 redis-rdb-tools 分析 RDB 文件。
  • 大 Key 的处理
    删除:使用 UNLINK 命令异步删除大 key,避免阻塞。
    拆分:将大 key 拆分为多个小 key。
    压缩:使用压缩算法压缩 value,但会增加 CPU 开销。

19. redis事务机制

redis中事务是一组命令的集合,只保证了正常情况下的原子性-要么全部执行,要么全部不执行;一般不提供回滚机制。

所有命令在执行之前都会被放入一个队列中,直到执行EXEC命令时,所有命令才会按顺序执行。

主要通过 multi、exec、discard、watch等命令来实现:

  • multi:标记一个事务的开始 ,,所有的命令都会被放入一个队列中,而不是立即执行。
  • exec:按顺序执行执行所有放入队列的命令 。不支持回滚机制,如果在事务执行过程中发生错误,已经执行的命令不会被回滚。
  • discard:取消事务,放弃执行事务块内的所有命令
  • watch:监视一个或多个 key,如果在事务执行之前这个 key 被其他命令所改动,那么事务将被打断

20.什么情况下redis哨兵模式会产生数据丢失?

  • 主从复制的延迟,比如主节点刚接收到新数据,还没来得及同步给从节点,就突然宕机了,那么这部分没同步的数据就丢了。
  • 脑裂问题,主节点和哨兵集群之间的网络断了,哨兵误以为主节点宕机,就会选举一个新主节点。这时候旧主节点可能还在运行,接收客户端的写请求,等网络恢复后,旧主节点会被降为从节点,它上面那些没同步到新主节点的数据,就会被覆盖掉,从而导致丢失。

21. redis中的管道有什么用?

Redis中的管道(Pipeline)主要用于批量执行多个命令,用来提高性能和效率。

管道可以将多个命令一次性发给服务器,然后返回多个结果。

22. 看门狗机制的原理是什么?

Redisson 的看门狗机制是一种用于自动续约分布式锁的机制,确保在持有锁的客户端处理完业务逻辑之前,锁不会过期。比如,我们平时使用分布式锁的时候,一般会设置一个锁的过期时间,那么如果锁过期的时候,业务还没执行完怎么办,于是就有了看门狗。

原理

  • 初始锁定:
    当客户端获取到锁时,会在 Redis 中设置一个键(代表锁)和一个过期时间(默认30秒)。同时,Redisson 会启动一个后台任务(看门狗),这个任务会定期检查锁的状态。
  • 自动续约:
    看门狗任务会每隔一段时间(默认是锁的过期时间的1/3,即10秒)检查锁的状态。如果锁仍然被持有(即客户端还在持有锁且没有释放),看门狗任务会将锁的过期时间重置为初始值(例如,再次设置为30秒)。这样,锁的过期时间不断被延长,直到客户端明确释放锁或者客户端挂掉。
  • 释放锁:
    当客户端完成业务逻辑后,会显式地调用unlock()方法释放锁。一旦锁被释放,看门狗任务会停止续约,锁在 Redis 中的键会被删除或自然过期。

23. 本地缓存与分布式缓存的区别?

本地缓存 cacffine/guava cache redis
速度 可能会增加额外的网络开销,导致访问速度略低于本地缓存。
存储 存储在一个节点中,多个应用实例之间无法共享缓存数据。数据随应用进程的重启而丢失。 通过将数据分片存储在多个节点上,提高了缓存的容量和可扩展性。部分数据会被复制到多个节点上,以提高数据的可靠性和可用性
容量 容量受到内存大小的限制,一旦超过容量限制,可能会导致性能下降或者数据丢失。无法动态扩展。 根据需求动态添加和删除节点,以适应数据量的变化和访问负载的增加。redis 水平扩展。

当并发巨大的时候,如果 redis 的网络和 cpu 成为了瓶颈,一般可以增加一层本地缓存来进行缓冲。也就是我们说的多级缓存。

相关推荐
Coder_Boy_1 小时前
基于SpringAI的在线考试系统-教学管理与用户管理模块联合回归测试文档
java·前端·数据库·人工智能·spring boot
阿蒙Amon1 小时前
C#每日面试题-简述反射
开发语言·面试·c#
熊文豪1 小时前
时序数据库选型指南:工业物联网时代的数据管理之道
数据库·物联网·时序数据库·iotdb
WYiQIU1 小时前
普及一下字节前端岗需要达到的强度......
前端·javascript·vue.js·面试·职场和发展
测试19981 小时前
2026最新软件测试面试八股文(含答案+文档)
自动化测试·软件测试·功能测试·测试工具·面试·职场和发展·测试用例
攻心的子乐1 小时前
sql 性能调优
数据库·sql
玩大数据的龙威2 小时前
农经权二轮延包—一键出承包地块调查表
数据库·python
砚边数影2 小时前
DL4J框架入门(三):基础配置,计算后端(CPU/GPU)选型与优化
java·数据库·人工智能·ai·金仓数据库
龚礼鹏2 小时前
图像显示框架九——Surface/SurfaceControl基础概念(基于Android15源码分析)
数据库·sql