前言
Redis作为最流行的数据库之一,在找工作的过程中,对于 Redis 技术知识的掌握已经成为必须的技能。今天跟小伙伴们分享一下, 十道 Redis 最常问面试题!
1. 使用 Redis 有哪些好处?
【参考答案】
- 速度快,因为数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是 O(1)。
- 支持丰富数据类型,支持 string,list,set,Zset,hash 等。
- 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行。
- 丰富的特性:可用于缓存,消息,按 key 设置过期时间,过期后将会自动删除。
2. Redis 是单进程单线程的?
【参考答案】
Redis 是单进程单线程的,redis 利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。
3. Redis 常见性能问题和解决方案有哪些?
【参考答案】
- Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度 rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务;
- 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次;
- 为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网;
- 尽量避免在压力很大的主库上增加从库;
4. 为什么redis 需要把所有数据放到内存中?
【参考答案】
Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以 redis 具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘 I/O 速度为严重影响 redis 的性能。在内存越来越便宜的今天,redis 将会越来越受欢迎。如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。
5. Redis 最适合的场景?
【参考答案】
1、会话缓存(Session Cache)
最常用的一种使用 Redis 的情景是会话缓存(session cache)。用 Redis 缓存会话比其他存储(如 Memcached)的优势在于:Redis 提供持久化。
2、全页缓存(FPC)
除基本的会话 token 之外,Redis 还提供很简便的 FPC 平台。回到一致性问题,即使重启了 Redis 实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似 PHP 本地 FPC。能帮助你以最快速度加载你曾浏览过的页面。
3、队列
Reids 在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得 Redis能作为一个很好的消息队列平台来使用。Redis 作为队列使用的操作,就类似于本地程序语言(如 Python)对 list 的 push/pop 操作。
4,排行榜/计数器
Redis 在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis 只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的 10个用户,我们只需要像下面一样执行即可: 当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: ZRANGE user_scores 0 10 WITHSCORES。
5、发布/订阅
最后(但肯定不是最不重要的)是 Redis 的发布/订阅功能。发布/订阅的使用场景确实非常多。在社交网络中甚至可以用 Redis 的发布/订阅功能来建立聊天系统!
6. 假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?
【参考答案】
使用 keys 指令可以扫出指定模式的 key 列表。
对方接着追问:如果这个 redis 正在给线上的业务提供服务,那使用 keys 指令会有什么问题?
这个时候你要回答 redis 关键的一个特性:redis 的单线程的。keys 指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。
7. 如果有大量的 key 需要设置同一时间过期,一般需要注意什么?
【参考答案】
如果大量的 key 过期时间设置的过于集中,到过期的那个时间点,redis 可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。
8. Redis是单线程为啥那么快?
【参考答案】
1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
4、使用多路I/O复用模型,非阻塞IO;
5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;
9. Redis 支持哪些数据类型,以及每种数据类型的使用场景?
【参考答案】
redis 作为 key-vaule 存储系统,其 value 共支持五种数据类型:
(1) String,redis 中的 String 类型和其他很多编程语言中的语义类似,value 可以是 String 也可以是数字。 一般做一些复杂的计数功能的缓存,比如说微博数,粉丝数等;
(2) Hash,也可以称为 hashes, 是一个 string 类型的 key 和 value 的映射表,特别适合用于存储对象,。比如我们可以 hash 数据结构来存储用户信息,商品信息等等。内部可以用 hashtable 和 ziplist 两种承载方式来实现;
(3) List,list 是 redis 最重要的数据结构之一,可以做简单的消息队列的功能,比如论坛点赞人列表、微博粉丝列表等;另外还可以利用 lrange 命令,可以从某个元素开始读取多少个元素,实现简单的高性能分页,类似微博那种下拉不断分页的东西,性能极佳,用户体验好;
(4) Set,set 类似 List,但是它是一个无序集合,且其中的元素不重复。可以做全局去重的功能,比如说是否给帖子点赞数;也可以判断某个元素是否在 set,比如说判断是否给某个回复点赞。另外还可以利用交集、并集、差集等操作来支撑更多的业务场景,比如说找出两个微博 ID 的共同好友等;
(5) Sorted Set,sorted set 相比 set 增加了一个权重参数 score,使得集合中的元素能够按 score 进行有序排列,比如说可以用于取排行榜 top N 的用户。
10. 说一说 redis 的过期策略以及内存淘汰机制?
【参考答案】
- redis 的过期策略
- 定期删除策略。用一个定时器来负责检查 key,过期则删除 key,注意这里并不是检查所有的 key 而是随机抽取进行检查。定期策略虽然让内存及时释放,但也会额外消耗 CPU 资源,通常 CPU 应该将时间尽量用于处理业务请求,而不是删除 key。
- 惰性删除策略。在你获取某个 key 的时候,redis 会检查一下,这个 key 如果设置了过期时间那么是否过期了,如果过期则删除该 key。
-
内存淘汰机制
如果定期删除没删除 key,然后也没及时去请求 key,即惰性删除也没生效,持续下去 redis 的内存会越来越高,当超过 redis 设置的内存最大使用量时,就会进行内存数据淘汰。redis 有 6 种淘汰策略:
| 策略 | 描 |
|---|---|
| volatile-lru | 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰 |
| volatile-ttl | 从已设置过期时间的数据集中挑选将要过期的数据淘汰 |
| volatile-random | 从已设置过期时间的数据集中任意选择数据淘汰 |
| allkeys-lru | 从所有数据集中挑选最近最少使用的数据淘汰 |
| allkeys-random | 从所有数据集中任意选择数据进行淘汰 |
| noeviction | 当内存不足以容纳新写入数据时,新写入操作会报错。很少使用 |
注意:这里的 6 种机制,前缀 volatile 和 allkeys 用于区分淘汰数据的数据集是从已设置过期时间的数据集还是从全部数据集中选取,后面的 lru、ttl 以及 random 是三种不同的淘汰策略,再加上一种 no-enviction 永不回收的策略。其中最常使用的是 volatile-lru/allkeys-lru。
总结
Redis 考察问题的方式可以很灵活,一般有经验的面试官更愿意将题目上和实际场景结合起来。