预见猿份
主题
首页面试题在线工具关于我们老苗一对一私教学员评价
实战项目
项目前置基础创新WMS项目Java微服务框架与实战云岚到家项目闪聚支付项目学成在线项目青橙电商项目JVM原理与实战调优分布式事务专题Java高频面试题MySQL从入门到精通Java数据结构与算法老苗一对一私教学员评价blog
blog
  • Java工程师高频面试题

    • 课程介绍
    • Java基础常见面试题
    • Java并发编程面试题
    • 数据库常见面试题
    • Redis 常见面试题
    • Java 框架常见面试题
    • Linux NG ES MQ SEATA 常见面试题
    • Java常见算法面试题
    • Java AI相关面试题
    • Java 工程师面试最常考的 80 道高频题
    • Java面试实录







----- 到底线了 -----

×

欢迎来到预见猿份,本站项目均为站长原创,学习中有问题可直接提交给站长老苗解决(微信:mrt_0607)。

苗润土老师,20余年一线项目经验,2014年加入黑马,星辰wms、云岚到家、学成在线项目作者,历任高级讲师、教学主管及课程研究员。 b站老苗

Redis 常见面试题 ​

Redis现在做为最流行的缓存数据库,使用的场景也是越来越多,重要性也是不言而喻

首先我们要先对Redis有个总体认识

Redis命令速查:https://yjoffer.com/tools/redis-cheatsheet.html

Redis系统学习: 基础知识:https://yjoffer.com/project_preposition/redis/redis.html

高级知识:https://yjoffer.com/springcloud/chapter9/chapter9.html

为什么用

Redis本身在执行的时候是单线程,所以没有并发安全问题

Redis数据存储在内存中,速度非常快

不可避免地缺陷

由于数据在内存中,所以会有数据丢失的风险

不是关系型数据库,所以只能存一些弱关系数据

1.原理相关(难度★★★★) ​

Redis的数据结构以及对应的使用场景 ​

结构底层场景
StringSDS简单动态字符串缓存、计数器(incr by)、分布式锁(setnx)、bitmap(布隆过滤器、签到)
List双向链表+压缩列表消息队列、栈
Hash哈希表对象存储,列表对象
Set数组+哈希表去重、社交关系(粉丝、关注、收藏)
Zset跳表+压缩列表排行榜

缓存三剑客 ​

比较简单,所以这里简单描述一下,具体原理同学们自行查阅

缓存雪崩

现象:是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。 解决:给不同的Key的TTL添加随机值。对Redis做哨兵集群

缓存击穿

现象:给某一个key设置了过期时间,当key过期的时候,恰好这时间点对这个key有大量的并发请求过来,这些并发的请求可能会瞬间把DB压垮 解决:互斥锁(强一致、性能差)或者逻辑过期(高可用、性能好)

缓存穿透

现象:查询一个不存在的数据,mysql查询不到数据也不会直接写入缓存,就会导致每次请求都查数据库 解决:缓存空数据,查询返回的数据为空,仍把这个空结果进行缓存或者布隆过滤器

Redis和Mysql中的数据怎么保证一致性 ​

首先这个问题没有完美的解决方案,只能说结合你们具体的业务选择一个最优的方案

如果要强一致性,那就必然牺牲性能,但是问题是我们用缓存就是为了它的高性能,如果要求强一致,那最好别用缓存。

所以理论上来说你用缓存就必然能接受一部分的不一致,我们只要做到最终一致即可

首先介绍双写一致性 当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致 想做到双写一致有大概四种做法

  1. 先写Redis,再写DB
  2. 先写DB,再写Redis
  3. 先删Redis,再写DB
  4. 先写DB,再删Redis

这四种做法正常情况下都是ok的,但是如果是高并发的场景,每个都会有问题,具体问题我这里只举一个例子,剩下的同学们自行推演即可 例如做法1,如果写完redis之后,写数据库失败,就会造成两边数据不一致,则会出现问题 这里面相对来说出现问题概率最低的就是先写DB,再删Redis。 首先删缓存肯定比写缓存来的要更简单一些 其次如果写数据库成功后,再删redis失败的概率较低,并且A线程删了缓存,B线程查缓存之间再有并发导致不一致的问题概率比先删Redis再操作DB来的要低得多 这里我们介绍其他几种方案 延迟双删 思路:先删缓存,然后更新数据库,然后暂停一段时间,到了之后再次删除一次缓存。这样在删缓存和更新数据库的这段时间内如果有新的查询请求,也会因为再次删除而更新到数据库 但是,如果在延迟期间,又有新的写入操作,就会导致数据还是不一致,但是我们日常的业务大多是高并发读,偶尔写,所以这种能覆盖较大的场景,并且性能较好。 延迟双删只是能带来一部分一致性的提升,并不能保证强一致。所以相对来说比较鸡肋 如果要追求强一致性,那只能加锁,等数据库处理完毕在释放锁,保证强一致,但是性能会受到较大影响 其他还可以使用消息队列的方式和使用canal来做到最终一致性。这里不再详细介绍

Redis的持久化机制 ​

具体分为RDB和AOF RDB是快照,AOF存储的是命令记录 所以相对来说RDB文件更小,恢复速度更快。而AOF文件更大,恢复速度更慢。 但是RDB的执行一次比较耗时,而AOF是记录每条增删改的命令,所以更快一些 下面介绍一下RDB和AOF的配置方式 将两个配置都打开,就是RDB和AOF一起使用

图片展示了Redis内部触发RDB的机制,可在redis.conf文件中找到,格式为“# 900秒内,如果至少有1个key被修改,则执行bgsave”。具体配置为“save 900 1”“save 300 10”“save 60 10000”。该图片与上文介绍Redis的持久化机制相关,上文提到RDB执行耗时,此图则说明了Redis触发RDB的条件,即在指定时间内至少有1个key被修改时,会执行bgsave操作,以实现数据持久化。

图片展示了Redis中AOF(Append Only File)的配置方式。上方说明AOF默认关闭,需修改redis.conf配置文件开启,示例配置包括开启AOF功能、设置AOF文件名称等。下方介绍AOF命令记录频率配置,可选“always”(每次写命令立即记录)、“everysec”(每秒将缓冲区数据写入文件,为默认)、“no”(不记录,由操作系统决定何时写入)。这些配置与上下文介绍的AOF配置相关,是对AOF开启及命令记录频率配置的详细说明。

Redis的数据删除策略 ​

惰性删除:设置该key过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key 定期删除:每隔一段时间,我们就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查,并删除其中的过期key)。 定期清理有两种模式: SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,以通过修改配置文件redis.conf 的hz 选项来调整这个次数 FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms Redis的过期删除策略:惰性删除 + 定期删除两种策略进行配合使用

Redis的内存淘汰机制 ​

数据的淘汰策略:当Redis中的内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉,这种数据的删除规则被称之为内存的淘汰策略。 Redis支持8种不同策略来选择要删除的key:

  • noeviction: 不淘汰任何key,但是内存满时不允许写入新数据,默认就是这种策略。
  • volatile-ttl: 对设置了TTL的key,比较key的剩余TTL值,TTL越小越先被淘汰
  • allkeys-random:对全体key ,随机进行淘汰。
  • volatile-random:对设置了TTL的key ,随机进行淘汰。
  • allkeys-lru: 对全体key,基于LRU算法进行淘汰
  • volatile-lru: 对设置了TTL的key,基于LRU算法进行淘汰
  • allkeys-lfu: 对全体key,基于LFU算法进行淘汰
  • volatile-lfu: 对设置了TTL的key,基于LFU算法进行淘汰 LRU(Least Recently Used)最近最少使用。用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。 LFU(Least Frequently Used)最少频率使用。会统计每个key的访问频率,值越小淘汰优先级越高。

追问:那你们采取什么策略呢? ​

结合你们项目选择合适的策略

  1. 优先使用 allkeys-lru 策略。充分利用LRU算法的优势,把最近最常访问的数据留在缓存中。如果业务有明显的冷热数据区分,建议使用。
  2. 如果业务中数据访问频率差别不大,没有明显冷热数据区分,建议使用 allkeys-random,随机选择淘汰。
  3. 如果业务中有置顶的需求,可以使用 volatile-lru 策略,同时置顶数据不设置过期时间,这些数据就一直不被删除,会淘汰其他设置过期时间的数据。
  4. 如果业务中有短时高频访问的数据,可以使用allkeys-lfu 或 volatile-lfu 策略。

Redis的分布式锁如何实现 ​

Redis实现分布式锁主要利用Redis的setnx命令。setnx是SET if not exists**(如果不存在,则 SET)的简写。 举例,set lock value nx ex 10能设置成功,则获取锁成功 del lock就是释放锁 但是这种简单的分布式锁有很多问题,比如不可重入,超时误删等一系列问题,所以我们会采用redisson提供的分布式锁,具体原理大家自行搜索,面试官会追问,这里我只做简单介绍**

  • redisson底层基于redis的setnx命令进行改进,使用lua脚本保证命令的原子性
  • 利用hash结构,记录线程标示和重入次数
  • 利用watchDog看门狗延续锁的时间
  • 控制了锁重试等待
  • 使用RedLock红锁解决主从数据一致性问题,但是性能很差
  • 如果业务需要强一致性,建议使用zookeeper实现的分布式锁

Redis是单线程为什么还这么快 ​

Redis是纯内存操作,执行速度非常快 采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题 使用I/O多路复用模型,非阻塞IO

什么是I/O多路复用模型 ​

是指利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。目前的I/O多路复用都是采用的epoll模式实现,它会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不需要挨个遍历Socket来判断是否就绪,提升了性能。

2.运维部署(难度★★★) ​

Redis的集群有哪些方案? ​

  • 主从复制
  • 哨兵集群
  • 分片集群

介绍一下怎么实现主从复制 ​

主从复制原理大家自行搜索

单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。 一般都是一主多从,主节点负责写数据,从节点负责读数据 追问:能说一下,主从同步数据的流程全量同步:

  1. 从节点请求主节点同步数据(replication id、 offset )
  2. 主节点判断是否是第一次请求,是第一次就与从节点同步版本信息(replication id和offset)
  3. 主节点执行bgsave,生成rdb文件后,发送给从节点去执行
  4. 在rdb生成执行期间,主节点会以命令的方式记录到缓冲区(一个日志文件)
  5. 把生成之后的命令日志文件发送给从节点进行同步 增量同步:
  6. 从节点请求主节点同步数据,主节点判断不是第一次请求,不是第一次就获取从节点的offset值
  7. 主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步

如何保证你们Redis的高可用 ​

哨兵原理大家自行搜索

首先可以搭建主从集群,再加上Redis的哨兵模式 哨兵模式可以实现主从集群的自动故障恢复、其中包含对主从服务的监控、自动故障恢复等。 如果Master故障,Sentinel会将一个slave提升为master,当故障示例恢复后,也会以新的master为主。

你们的Redis使用的是单点还是集群,那种集群? ​

我们使用的是主从(1主1从)加哨兵。一般单节点不超过10G内存,如果内存不足可以给不同服务拆分不同的Redis主从节点,尽量不采用分片。因为集群维护起来很麻烦,并且也没法使用lua脚本和事务 追问:那你们集群脑裂了怎么解决呢脑裂是由于master和slave处于不同的网络分区,使得哨兵没有监控到master的心跳,然后通过选举选出slave变为master,这样就存在两个master,就像大脑分裂一样。会导致客户端还在向老的master发数据,新的master还无法同步。 如果想解决可以在redis中进行设置 第一设置最少slave节点个数,比如至少要有一个salve节点才允许同步 第二可以设置主从数据复制和同步的延迟时间,答不到要求就拒绝,也可以避免数据丢失

Redis中的分片集群了解过吗 ​

分片集群解决的是海量数据的存储问题,集群中会有多个master,每个master保存的数据是不同的,这样就能增大整体集群的并发能力,同时每个master之间通过ping检测彼此健康状态,就类似哨兵了。并且Redis的分片集群引入了哈希槽的概念,有16384个槽,每个master节点都绑定一定范围的槽,利用CRC16校验后并对节点数进行取模操作,来决定放哪个槽

3.场景题(难度★★★★★) ​

现在数据库1000万数据,Redis只能存20万,怎么办? ​

优先存储热点数据 怎么确定热点数据? 使用allkeys-lru淘汰策略,留下来的就都是经常访问的热点数据

Redis里的大Key如何处理? ​

什么是大Key ​

通常我们会将含有较大数据或含有大量成员、列表数的Key称之为大Key 举例说明:(但是具体的数值大小需要结合实际业务和场景)

  • 一个STRING类型的Key,它的值为5MB(数据过大)
  • 一个LIST类型的Key,它的列表数量为20000个(列表数量过多)
  • 一个ZSET类型的Key,它的成员数量为10000个(成员数量过多)
  • 一个HASH格式的Key,它的成员数量虽然只有1000个但这些成员的value总大小为100MB(成员体积过大)
大Key带来的问题 ​
  • 查询速度变慢
  • Redis内存不断变大导致OOM
如何寻找大Key ​

通过Redis官方客户端redis-cli的bigkeys参数发现大Key

大Key的处理方式 ​
  • 对大Key进行拆分,比如Hash成员过多,根据实际业务再继续拆分成多个Key。或者拆分到不同的分片集群
  • String中数据量过大,采用合适的压缩方式或其他数据结构
如何删除大Key ​

直接del删除的话,可能会导致主线程阻塞,一般采用unlink命令异步删除

Redis中的热点Key问题 ​

什么是热点Key问题 热点 key 问题是指在 Redis 中某些特定的 key 被频繁访问,可能会导致 Redis 服务器负载过高,影响系统的性能和稳定性

  1. 找到热点Key
  • 在应用程序中添加代码来统计对不同 key 的访问频率。可以使用一个哈希表来记录每个 key 的访问次数,并定期(如每分钟)更新和分析这些统计信息。
  • 可以使用一些开源的 APM(Application Performance Monitoring,应用性能监控)工具,这些工具可以监控应用程序对 Redis 的访问,并识别出热点 key。
  1. 处理热点 key 的方法
  • 限流降级,最简单朴素的办法
  • 多级缓存,也就是对热点key再加一层本地缓存,缓解redis的压力
  • 主从集群,使用多个从节点来分散redis单节点的压力
  • 优化数据结构和算法,例如,可以使用更高效的数据结构(如哈希表、跳表等)来存储数据,或者优化查询算法,减少查询时间。

Redis如果内存满了会出现什么 ​

主要看数据淘汰策略是什么?如果是默认的配置(noeviction),会直接报错

你们Redis挂了怎么办 ​

结合实际情况,先确定自己公司的Redis是自己搭建还是买的云服务厂商现成的,参考下面问题 如果是自己搭建,那就集合持久化机制(RDB\AOF)和哨兵机制来综合回答,意思就是有做防单点故障的策略 如果使用云服务厂商提供的,那就不用太担心

你们Redis用了多少台 ​

两种答案 1.我们直接使用的阿里云提供的Redis(主从版、单机版、集群版),所以不担心它的高可用问题 2.基于项目实际情况选择使用哨兵还是主从,具体参考 微服务课程中讲的Redis面试题

图片展示的是阿里云Redis的配置页面。页面中显示Redis版本为社区版,兼容Redis 5.0,架构类型为标准版,分片数为未启用集群,节点类型为双副本,实例规格为4 GB主从版。页面还提供了更多关于Redis社区版和Tair(Redis企业版)的特性对比、Redis 6.0及7.0的购买链接、标准版架构详情、云原生部署模式的购买链接,以及实例规格查询链接。该图片与文档中关于Redis配置的内容相关,可帮助用户了解阿里云Redis的配置选项。

← 数据库常见面试题Java 框架常见面试题 →








如果发现文档内容有错误或排版错乱,请及时联系站长老苗修改,不胜感激。联系方式
关于我们 | 隐私政策 | 豫ICP备2026003386号-4 | 豫公网安备41010202004008号
目录

本页无章节