Redis 面试题全解析
前言
在《Redis 实战场景解析》这个 Chat 发表之后,很多订阅的同学都建议再集中写一篇关于 Redis 面试相关的 Chat。基于这个建议,我就开始梳理总结面试题目相关的内容,到今天已经梳理完毕,现在分享给大家。
概述
在这里我将所掌握的 Redis 的面试题目进行详细的梳理,结合平时工作遇到的问题以及面试题库收集的内容给大家进行分享。
本文将 Redis 知识方向分为六大块进行梳理:
通过本文的学习,相信对大家未来的面试以及知识点的掌握都会有所助益。
一、Redis 概念理解
1. 什么是 Redis?
Redis 全称为:Remote Dictionary Server(远程数据服务),是一个基于内存且支持持久化的高性能 key-value 数据库。
具备一下几个基本特征:
2. Redis 的特点有哪些?
3. Memcache 与 Redis 的区别都有哪些?
4. Redis 相比 Memcached 有哪些优势?
5. 如何实现本地缓存?请描述一下你知道的方式
6. Redis 通讯协议是什么?有什么特点?
Redis 的通信协议是 Redis Serialization Protocol,简称 RESP。
有如下特性:
二、Redis 数据结构与指令
1. Redis 支持的数据类型
2. Redis 常用的命令有哪些?
转存失败重新上传取消
3. 一个字符串类型的值能存储最大容量是多少?
512M
4. Redis 各个数据类型最大存储量分别是多少?
5. 请介绍一下 Redis 的数据类型 SortedSet(zset)以及底层实现机制?
zset 有顺序,不能重复。在业务场景下,适合做排行榜之类的事情。
底层实现机制:
SortedSet 的实现方式可能有两种:ziplist 或者 skiplist。
当有序集合对象同时满足以下两个条件时,对象使用 ziplist 编码:
6. Redis 事务相关命令有哪些?
7. 什么是 Redis 事务?原理是什么?
Redis 中的事务是一组命令的集合,是 Redis 的最小执行单位,一个事务要么都执行,要么都不执行。
Reids 事务保证一个事务内的命令依次执行,而不会被其他命令插入。
Redis 事务的原理是先将属于一个事务的命令发送给 Redis,然后依次执行这些命令。
8. Redis 事务的注意点有哪些?
9. Redis 为什么不支持回滚?
Redis 事务不支持回滚,如果遇到问题,会继续执行余下的命令。 这一点和关系型数据库不太一致。这样处理的原因有:
10. 请介绍一下 Redis 的 Pipeline(管道),以及使用场景
Redis 客户端与服务端通信模型使用的 TCP 协议进行连接, 那么在单个指令的执行过程中,都会存在“交互往返”的时间。
Redis 提供了批量操作命令,例如 mget、mset 等,能够一定程度上节省这类时间,但大部分命令还是不支持批量操作。
适用场景:有批量的数据写入 Redis,并且这些数据允许一定比例的写入失败,那么这种场景就可以适用 Pipeline。失败的数据后期进行补偿即可。
11. 请说明一下 Redis 的批量命令与 Pipeline 有什么不同?
12. 请介绍一下 Redis 的发布订阅功能
Redis 提供了基于“发布/订阅”模式的消息机制,消息发布者和订阅者不能直接通信,客户端发布消息的时候指定发送的频道,然后订阅了该频道的用户可以接收到该消息。具体指令如下:
13. Redis 的链表数据结构的特征有哪些?
14. 请介绍一下 Redis 的 String 类型底层实现?
Redis 底层实现了简单动态字符串的类型(SSD),来表示 String 类型。 没有直接使用 C 语言定义的字符串类型。
struct sdshdr{ //记录 buf 数组中已使用字节的数量 //等于 SDS 保存字符串的长度 int len; //记录 buf 数组中未使用字节的数量 int free; //字节数组,用于保存字符串 char buf[]; }
15. Redis 的 String 类型使用 SSD 方式实现的好处?
16. 设置键的生存时间和过期时间有哪些命令?
三、Redis 高并发处理策略
1. 为什么 Redis 需要把所有数据放到内存中?
追求更快的读写速度,并异步方式持久化存储到磁盘。 如果不将数据放到内存中,磁盘的 I/O 速度会严重影响 Redis 的性能。
2. Redis 是单线程的吗?
是。
这里的单线程指的是 Redis 网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。
3. Redis 为什么设计成单线程的?
4. 什么是缓存穿透?怎么解决?
缓存穿透是指缓存中查询一个不存在的数据,需要去数据库中获取。
如果数据库也查不到结果,将不会同步到缓存,导致这个不存在数据每次请求都要到数据库查询,失去了缓存的意义。
解决方法有两个:
1. 布隆过滤(Bloom filter)
将所有查询的参数都存储到一个 bitmap 中,在查询缓存之前,先再找个 bitmap 里面进行验证。
如果 bitmap 中存在,则进行底层缓存的数据查询; 如果 bitmap 中不存在查询参数,则进行拦截,不再进行缓存的数据查询。
适用范围:可以用来实现数据字典,进行数据的判重,或者集合求交集
2. 缓存空对象
如果查询返回的数据为空,仍然把这个空结果进行缓存。那么再次用相同 key 获取数据的时候,即使不存在的数据,缓存也可以直接返回空值,避免重复访问 DB。
缓存空对象有两个不足之处:
5. 什么是缓存雪崩? 怎么解决?
在集中的一段时间内,有大量的缓存失效,导致大量的访问没有命中缓存,从而将所有查询进行数据库访问,导致数据库的压力增大,从而造成了缓存雪崩。
比如,如果要做一个促销活动,我们将商品信息都刷新到缓存, 过期时间统一为 30 分钟。那么在 30 分钟之后,这批商品将全部过期。这时候这批商品的访问查询,都落到了数据库,对于数据库而言,这一刻的压力会非常大。从而造成系统整体性风险。
解决方案:
方法 1:分散失效时间
分析缓存数据的特点,尽量将热点缓存的失效时间均匀分布。 比如说将相同类型的缓存的失效时间设置成一个在一定区间内的随机值。从而有效的分散失效时间。
方法 2:DB 访问限制
对数据的访问进行限流性质的操作。比如说对数据库访问进行加锁的处理或者限流相关的处理。
方法 3:多级缓存设计
一级缓存为基础缓存,缓存失效时间设置一个较长时间, 二级缓存为应用缓存,失效时间正常设置,一般会比较短。 当二级缓存失效的时候,再从一级缓存里面获取。
6. 缓存的更新策略有几种?分别有什么注意事项?
缓存的更新策略包含:
策略一:先更新数据库,再更新缓存
1. 这种策略会导致线程安全问题
例如:线程 1 更新了数据库,线程 2 也更新数据库, 这时候由于某种原因,线程 2 首先更新了缓存,线程 1 后续更新。 这样就导致了脏数据的问题。 因为目前数据库中存储的线程 2 更新后的数据,而缓存存储的是线程1更新的老数据。
2. 更新缓存的复杂度相对较高
数据写入数据库之后,一般存入缓存的数据都要经过一系列的加工计算,然后写入缓存。 这时候更新缓存相比较于直接删除缓存要比较复杂。
策略二:先删除缓存,再更新数据库
这种策略可能导致数据不一致的问题。线程 1 写数据删除缓存;这时候有线程 2 查询该缓存,发现不存在,则去访问数据库,得到旧值放入缓存;线程 1 更新数据库。这时候就出现了数据不一致的问题。 如果缓存没有过期时间,这个脏数据一直存在。
解决方案:在写数据库成功之后, 再次淘汰缓存一次。
策略三:先更新数据库,再删除缓存
可能会造成比较短暂的数据不一致。在更新完成数据库, 还没有删除缓存的时刻,如果有缓存数据访问, 就会造成数据不一致的情形。 但这种如果数据同步机制比较科学,一般都会比较快, 不一致的影响比较小。
7. 请介绍几个可能导致 Redis 阻塞的原因
内部原因:
外部原因:
8. 怎么去发现 Redis 阻塞异常情况?
1. 通过应用服务监控发现
当 Redis 阻塞的时候,线上应用服务应该会感知发现。比如说发现 Redis 链接超时等。这种就需要应用服务增加对于异常的统计,并针对 Redis 相关的异常,进行报警。
2. 通过 Redis 自身监控系统
借助 Redis 监控系统发现阻塞问题,当监控系统发现各个监控指标存在异常的时候,发送报警。 指标有:CPU/内存/磁盘等, 慢查询,命令耗时增加等。
四、Redis 集群结构以及设计理念
1. Redis 集群架构模式有哪几种?
2. Redis 集群最大节点个数是多少?
16384 个
3. Redis 集群的主从复制模型是怎样的?
Redis 中的主从复制,也就是 Master-Slave 模型,多个 Redis 实例间的数据同步以及 Redis 集群中数据同步会使用主从复制。
主从复制主要是数据同步, 数据同步分为全量同步和增量同步。
全量同步:
全量同步一般发生在 Slave 机器初始化阶段, 这时候 Slave 需要将 Master 上的所有数据都进行同步复制。
大概步骤如下所示:
转存失败重新上传取消
增量更新:
Slave 节点初始化完成之后,开始正常工作,Master 节点进行的写操作都会同步到 Slave 节点上面。Master 节点每执行一个写命令都会向从服务器发送相同的写命令,从服务器接收到命令,并执行。
4. 请介绍一下 Redis 集群实现方案
1. Redis Cluster 集群方案(服务端 Sharding 技术)
Redis Cluster 是 3.0 版本开始正式提供的服务器 Sharding 技术。引入 slot(槽)的概念,整个集群共有 16384 个槽。根据 key 进行散列(CRC16 后 16384 取模),分配到其中一个槽当中。
2. Redis Sharding 集群(客户端 Sharding 技术)
Redis Sharding 出现先与 Redis Cluster 方案,他是多 Redis 实例集群方案。
客户端 Sharding 方式,该向哪个 Redis 节点操作数据,由客户端来进行控制。服务端 Redis 还是一个个相对独立的 Redis 实例节点,没有做任何变动。节点选择可采用的方法:一致性 hash 算法或者虚拟节点算法。
转存失败重新上传取消
3. Twemproxy 中间件实现
Twemproxy 就是一种中间件 Sharding 分片的技术,处于客户端和服务器的中间,将客户端发来的请求,进行一定的处理后(如 Sharding),再转发给后端真正的 Redis 服务器。
也就是说,客户端不直接访问 Redis 服务器,而是通过 Twemproxy 代理中间件间接访问。
5. Redis 集群会有写操作丢失吗?为什么?
Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作。
6. Redis 慢查询是什么?通过什么配置?
所谓慢查询就是指,系统执行命令之后,计算统计每条指令执行的时间,如果执行时间超过设置的阈值,就说明该命令为慢指令。
Redis 慢查询配置参数为:
7. Redis 的慢查询修复经验有哪些?怎么修复的?
8. 如何优化 Redis 服务的性能?
9. Redis 的主从复制模式有什么优缺点?
10. Redis sentinel(哨兵)模式优缺点有哪些?
11. 如何设置 Redis 的最大连接数?查看 Redis 的最大连接数?查看 Redis 的当前连接数?
12. 介绍一些 Redis 常用的安全设置?
1. 网络安全
除了信任的客户端发出的请求以外,其他所有请求都拒绝。对于暴露到外网的服务,使用防火墙阻止外部访问 Redis 端口。
2. 身份验证
Redis 提供了简单的身份验证功能,在 redis.conf 文件中进行配置生效。客户端可以通过发送(AUTH 密码)命令进行身份认证。
3. 禁用特定的命令集
Redis 可以选择禁止使用某些命令,这样即使是正常的客户端也无法使用这些命令集合。
五、Redis 缓存管理与持久化机制
1. Redis 持久化机制有哪些?
Redis 提供两种方式进行持久化。
2. Redis 持久化机制 AOF 和 RDB 有哪些不同之处?
两者的区别:RDB 持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是 fork 一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
转存失败重新上传取消
AOF 持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。
转存失败重新上传取消
3. 请介绍一下 RDB 持久化机制的优缺点
优点
缺点
4. 请介绍一下 AOF 持久化机制的优缺点
优点
缺点:
5. 如果 AOF 文件的数据出现异常, Redis 服务怎么处理?
如果 AOF 文件出现异常, Redis 在重启的时候将会拒绝加载 AOF 文件,从而保证数据的一致性。
这时候,可以试着对 AOF 文件进行修复:redis-check-aof -fix。
6. 常见的淘汰算法有哪些?
FIFO:First In First Out
先进先出。判断被存储的时间,离目前最远的数据优先被淘汰。
LRU:Least Recently Used
最近最少使用。判断最近被使用的时间,目前最远的数据优先被淘汰。
LFU:Least Frequently Used
最不经常使用。在一段时间内,数据被使用次数最少的,优先被淘汰。
7. Redis 淘汰策略有哪些?
Redis 可以看作是一个内存数据库,通过 Maxmemory 指令配置 Redis 的数据集使用指定量的内存。设置 Maxmemory 为 0,则表示无限制。
当内存使用达到 Maxmemory 极限时,需要使用某种淘汰算法来决定清理掉哪些数据,以保证新数据的存入。
Redis 的缓存淘汰策略有:
8. Redis 缓存失效策略有哪些?
策略有:定时删除策略,惰性删除策略,定期删除策略。
定时删除策略
在设置 key 的过期时间的同时,为该 key 创建一个定时器,让定时器在 key 的过期时间来临时,对 key 进行删除。
惰性删除策略
key 过期的时候不删除,每次从数据库获取 key 的时候去检查是否过期,若过期,则删除,返回 null。
定期删除策略
每隔一段时间执行一次删除(在 redis.conf 配置文件设置 hz,1s 刷新的频率)过期 key 操作。
Redis 一般采用:惰性策略 + 定期策略两个相结合。
9. Redis 如何做内存优化?
10. 什么是 bigkey? 有什么影响?
bigkey 是指存储 value 占用内存空间非常大的 key。例如一个 String 类型的 value 占用了 100MB 空间。
bigkey 的影响主要体现在:
11. 怎么发现 bigkey?
redis-cli-bigkeys 命令可以统计 bigkey 的分布。
生产环境下执行 debug object key 查看 serializedlength 属性,表示 key 对应的 value 序列化之后的字节数。
12. Redis 的内存消耗分类有哪些?内存统计使用什么命令?
Redis的内存消耗分为:
13. 简单介绍一下 Redis 的内存管理方式有哪些?
Redis 内存管理方式主要方向上有两个:
14. 如何设置 Redis 的内存上限?有什么作用?
Maxmemory 参数可以限制最大可用内存。
15. Redis 报内存不足怎么处理?
六、Redis 应用场景设计
1. Redis 适用场景有哪些?
适用场景:
不适场景:
2. Redis 常用的业务场景有哪些?
3. Redis 支持的 Java 客户端有哪些? 简单说明一下特点。
官方推荐的有三种:Jedis、Redisson 和 lettuce。
Jedis:
4. 请简单描述一下 Jedis 的基本使用方法?
Jedis jedis = new Jedis("127.0.0.1", 6379,500,500); jedis.set("hello", "world”); String value = jedis.get("hello”);
上面代码就是一个简单的 Redis 数据存储操作。
初始化 Jedis 需要四个参数:
Jedis(final String host, final int port, final int connectionTimeout, final int soTimeout)
5. Jedis 连接池链接方法有什么优点?
上一个题目介绍了 Jedis 的直连方式, 每次操作 Redis 都会创建一个新的 TCP 连接,使用完之后就会断开。很明显消耗了不必要的资源。
为了减少这方面的消耗, Jedis 提供了连接池的链接方式:JedisPool。每次连接 Redis 只需要池子中拿,用完了归还就可以了。
6. 什么是分布式锁?有什么作用?
分布式锁是控制分布式系统之间同步访问共享资源的一种方式。 在单机或者单进程环境下,多线程并发的情况下,使用锁来保证一个代码块在同一时间内只能由一个线程执行。比如 Java 的 Synchronized 关键字和 Reentrantlock 类。
多进程或者分布式集群环境下,如何保证不同节点的线程同步执行呢? 这就是分布式锁。
7. 分布式锁可以通过什么来实现?
1. Memcached 分布式锁
Memcached 提供了原子性操作命令 add,才能 add 成功,线程获取到锁。key 已存在的情况下,则 add 失败,获取锁也失败。
2. Redis 分布式锁
Redis 的 setnx 命令为原子性操作命令。只有在 key 不存在的情况下,才能 set 成功。和 Memcached 的 add 方法比较类似。
3. ZooKeeper 分布式锁
利用 ZooKeeper 的顺序临时节点,来实现分布式锁和等待队列。
4. Chubby 实现分布式锁
Chubby 底层利用了 Paxos 一致性算法,实现粗粒度分布式锁服务。
8. 介绍一下分布式锁实现需要注意的事项?
分布式锁实现要保证几个基本点。
9. Redis 怎么实现分布式锁?
简单方案:
最简单的方法是使用 setnx 命令。释放锁的最简单方式是执行 del 指令。
问题:
锁超时:如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资源将会永远被锁住(死锁),别的线程再也别想进来。
优化方案:
setnx 没办法设置超时时间,如果利用 expire 来设置超时时间,那么这两步操作不是原子性操作。
利用 set 指令增加了可选参数方式来替代 setnx。set 指令可以设置超时时间。
10. 缓存命中率表示什么?
缓存命中率 = 缓存中获取数据次数/获取数据总次数
通常来说,缓存命中率越高,缓存的收益越高,应用的性能也就越好。
11. 怎么提高缓存命中率?
通常的手段有:
12. 请介绍一下 Spring 注解缓存
Spring 3.1 版本之后,加入了注解缓存操作技术,对缓存使用进行了具体的定义操作,添加了部分自定义的 annotation,能够非常便捷的获取缓存对象以及释放缓存对象。
常用的注解:
13. 设计一下在交易网站首页展示当天最热门售卖商品的前五十名商品列表?
这个题目很明显可以看出来,考察 Redis 的实际技术选型。 从题目中我们可以看到几个信息:
那我们可以就可以使用 Redis 来存储这个热门商品的榜单列表, 使用 Redis 的 zset 来进行存储。
然后就可以获取有序的产品售卖排行榜。
总结
上面是针对 Redis 面试题目的总结。希望对大家有所帮助。缓存也是大型网站性能优化以及稳定性保证的重要手段。之前也写过一些文章,在这里推荐给大家: