前言
本文整理了 Redis 常见的经典面试题,「处女座笔记」「吐血推荐」「建议收藏」。
文章内容包含自己的理解,面试经验,也会参照最新的一些相关文章,但是解决了内容缺失、偷换概念、答非所问和内容冗余的Bug。不敢说这篇文章时最全最好的,但是我敢保证:“应对大厂面试,这一篇就足足足足足够了”。
更多 Redis 专题请转微博:关于:Redis 基础知识,集群原理和面试资料【篇】(专题汇总)
正文
一、基础篇
1.1 为什么使用缓存 Redis?Redis 主要用来什么的?使用不当会造成什么后果?
在项目中使用 Redis,主要是从两个角度去考虑:性能,并发。
- 高性能
与 MySQL 关系型数据库不同 ,Redis的数据是存在内存中,它的读写速度非常快,每秒可以处理超过10万次读写操作,让请求能够迅速响应。需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。
- 高并发
在高并发的场景下,如果所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用 Redis 做一个缓冲操作,让请求先访问到 Redis,而不是直接访问数据库。
除了做缓存使用,Redis 还可以做分布式锁(setnx),并且支持 publish 和 subscribe 命令实现订阅和发布的功能,像 MQ 那样。除此之外,Redis支持事务、持久化、LUA 脚本、LRU 驱动事件、多种集群方案,如:主从模式,哨兵模式,Redis Cluster 集群模式...
常用应用场景:缓存,排行榜,计数器应用,共享Session,分布式锁,社交网络,消息队列,位操作...
常见的缓存问题:缓存与DB双写不一致 、缓存并发竞争、缓存击穿、缓存穿透、缓存雪崩等问题。【具体解决方案下面有讲 ↓ ↓ ↓ 】
1.2 说说 Redis 的数据类型?(基本类型 + 特殊类型)
五种基本类型:String(字符串)、Hash(哈希字典)、List(列表)、Set(集合)、zset(有序集合)。
三种特殊类型:HyperLogLogs(基数统计), Bitmaps (位图) 和 geospatial (地理位置)。
- Geospatial:Redis3.2 推出的,地理位置定位,用于存储地理位置信息,并对存储的信息进行操作。
- HyperLogLog:用来做基数统计算法的数据结构,如:统计网站的UV。
- Bitmaps :用一个比特位来映射某个元素的状态,在 Redis 中,它的底层是基于字符串类型实现的,可以把 bitmaps 成作一个以比特位为单位的数组,最大的好处就是节省空间。
此外,如果你还玩过 Redis Module,像 BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了,感兴趣的话赶紧百度科普吧。
Redis 常用命令:Redis 基本结构类型常用命令 - 菜鸟
1.3 Redis 的数据类型,在哪些场景下使用比较合适?
面试官心理:
如果面试官感觉你是比较初级的同学,或者觉得你并没有什么项目优化经验,还真的可能问这类问题。主要目的,就是看你有没有真正了解过 Redis,是不是能用合适的数据结构去优化自己的业务,是不是就只会用 String、String、String。
面试题剖析:
- String:不必多说,最简单的类型,就是普通的 set 和 get,做简单的 K-V 缓存,貌似什么数据都可以存;
- Hash:类似 Map 的一种结构,一般存储可以结构化的数据,比如 Java 对象。特别注意:Hash 结构支持每次读写的时候,直接操作 Hash 里的某个字段,千万不要把 Map 都取出来操作,最后再全部存进去,新手很容易这么干,生产上极易出现内存溢出的问题!!(我身边就真的发生过这类的生产问题)
- List:有序列表,存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的东西。可以通过 lrange 命令,读取某个闭区间内的元素,还可以基于 list 实现分页查询,这个是很棒的一个功能。基于 redis 实现简单的高性能分页,可以做类似微博那种下拉不断分页的东西,性能高,就一页一页走。List 结构还能实现类似 MQ 的广播功能,,rpush 生产消息,lpop 消费消息。
- Set:无序集合,自动去重。分布式系统中,可以基于 redis 进行全局的 set 去重。除此之外,还可以玩儿交集、并集、差集的操作,比如交集吧,可以把两个人的粉丝列表整一个交集,看看俩人的共同好友是谁。
- Sorted Set:排序的 set,去重且可以排序,写进去的时候给一个分数,自动根据分数排序,然后根据分数取任意区间内的数据,用途也是相当广泛。
1.4 如果 Redis 有大量的 key 需要设置同一时间过期,一般需要注意什么?如何解决热 key 问题?
大量的 key 过期时间设置的过于集中,到过期的时间点,Redis 可能会出现短暂的卡顿现象,更严重的情况是,可能出现雪崩现象。
所以,一般需要在时间上加一个随机值,使得过期时间分散一些,还有,可以考虑少量的热点数据设置成永不过期。
必要时,要做好服务的熔断和降级准备,防止雪崩的情况,设计的宗旨就是:坚决不可以让关系型数据库承载高并发请求。
在 Redis 中,我们把访问频率高的 key,称为热点 key。热点 key 由于请求量特别大,可能会导致主机资源不足,甚至宕机,从而影响正常的服务。
- 如何解决热key问题?
- Redis 集群扩容:增加分片副本,均衡读流量;
- 将热 key 分散到不同的服务器中,防止单台服务并发过大;
- 使用多级缓存,即:JVM 本地缓存,接入层 Nginx 缓存,减少 Redis 的读请求。
1.5 Redis 里面有1亿个key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如何将它们全部找出来?
使用 [ - keys 前缀* ] 指令可以扫出指定模式的 key 列表。
- 追问 - 1:如果这个 Redis 正在给线上的业务提供服务,那使用 keys 指令会有什么问题?
这个时候你要回答 Redis 关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令,scan 指令是基于游标的迭代器,可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。
1.6 Redis 的持久化机制有哪些?优缺点说说?你们是如何做持久化的?
Redis 是基于内存的非关系型K-V数据库,既然它是基于内存的,如果Redis服务器挂了,数据就会丢失。为了避免数据丢失了,Redis 提供了 RDB 和 AOF 两种持久化机制,即:把数据保存到磁盘。
- RDB:把内存数据以快照的形式保存到磁盘上。
RDB 持久化是 Redis 默认的持久化方式,指在指定的时间间隔内,将内存中的数据集快照写入磁盘中。执行完操作后,在指定目录下会生成一个 dump.rdb
文件,Redis 重启的时候,通过加载 dump.rdb
文件来恢复数据。
- 优点:适合大规模的数据恢复场景,如备份,全量复制等;
- 缺点:不够实时,没办法做到实时持久化/秒级持久化;
- AOF:采用日志的形式来记录每个写操作。
AOF(append only file) 持久化,采用日志的形式来记录每个写操作,追加到文件中,重启时再重新执行 AOF 文件中的命令来恢复数据,它主要解决数据持久化的实时性问题。
- 优点:弥补了RDB实时性的问题,数据的一致性和完整性更高;
- 缺点:AOF记录的内容越多,文件越大,数据恢复变慢;
- 生产环境持久化方案:
生产上通常采用【AOF + RDB】的混合模式作为持久化方案。通过 aof-use-rdb-preamble 配置参数控制,yes则表示开启,no表示禁用,默认是禁用的,可以通过 config set 修改。
bgsave 做镜像全量持久化,AOF 做增量持久化。因为 bgsave 会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。在 redis 实例重启时,优先使用 aof 来恢复内存的状态,如果没有 AOF 日志,就会使用 RDB 文件来恢复。
RDB 文件只用作后备用途,建议只在 slave 上持久化 RDB 文件,而且只要15分钟备份一次就够 了,只保留 save 900 1 这条规则。
- 追问 - 1:如果问 AOF 文件过大恢复时间过长怎么办?
&n