Redis 面试题

java

* Redis有哪些数据结构?

字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。

若是你是Redis中高级用户,还须要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub。

若是你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了。

* 使用过Redis分布式锁么,它是什么回事?

先拿setnx来争抢锁,抢到以后,再用expire给锁加一个过时时间防止锁忘记了释放。

这时候对方会告诉你说你回答得不错,而后接着问若是在setnx以后执行expire以前进程意外crash或者要重启维护了,那会怎么样?

这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你须要抓一抓本身得脑壳,故做思考片刻,好像接下来的结果是你主动思考出来的,而后回答:我记得set指令有很是复杂的参数,这个应该是能够同时把setnx和expire合成一条指令来用的!对方这时会显露笑容,内心开始默念:摁,这小子还不错。

* 假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,若是将它们所有找出来?

使用keys指令能够扫出指定模式的key列表。

对方接着追问:若是这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?

这个时候你要回答redis关键的一个特性:redis的单线程的。keys指令会致使线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可使用scan指令,scan指令能够无阻塞的提取出指定模式的key列表,可是会有必定的重复几率,在客户端作一次去重就能够了,可是总体所花费的时间会比直接用keys指令长。

* 使用过Redis作异步队列么,你是怎么用的?

通常使用list结构做为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。

若是对方追问可不能够不用sleep呢?list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。 

若是对方追问能不能生产一次消费屡次呢?使用pub/sub主题订阅者模式,能够实现1:N的消息队列。

若是对方追问pub/sub有什么缺点?在消费者下线的状况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

若是对方追问redis如何实现延时队列?我估计如今你很想把面试官一棒打死若是你手上有一根棒球棍的话,怎么问的这么详细。可是你很克制,而后神态自若的回答道:使用sortedset,拿时间戳做为score,消息内容做为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒以前的数据轮询进行处理。

到这里,面试官暗地里已经对你竖起了大拇指。可是他不知道的是此刻你却竖起了中指,在椅子背后。

* 若是有大量的key须要设置同一时间过时,通常须要注意什么?

若是大量的key过时时间设置的过于集中,到过时的那个时间点,redis可能会出现短暂的卡顿现象。通常须要在时间上加一个随机值,使得过时时间分散一些。

* Redis如何作持久化的?

bgsave作镜像全量持久化,aof作增量持久化。由于bgsave会耗费较长时间,不够实时,在停机的时候会致使大量丢失数据,因此须要aof来配合使用。在redis实例重启时,会使用bgsave持久化文件从新构建内存,再使用aof重放近期的操做指令来实现完整恢复重启以前的状态。

对方追问那若是忽然机器掉电会怎样?取决于aof日志sync属性的配置,若是不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。可是在高性能的要求下每次都sync是不现实的,通常都使用定时sync,好比1s1次,这个时候最多就会丢失1s的数据。

对方追问bgsave的原理是什么?你给出两个词汇就能够了,fork和cow。fork是指redis经过建立子进程来进行bgsave操做,cow指的是copy on write,子进程建立后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

* Pipeline有什么好处,为何要用pipeline?

能够将屡次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。使用redis-benchmark进行压测的时候能够发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。
**附: 可是注意,若是使用`Pipeline`。当节点个数扩充后,会致使长链接数目成倍数上涨。**

* Redis的同步机制了解么?

Redis可使用主从同步,从从同步。第一次同步时,主节点作一次bgsave,并同时将后续修改操做记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操做记录同步到复制节点进行重放就完成了同步过程。

* 是否使用过Redis集群,集群的原理是什么? 

Redis Sentinal着眼于高可用,在master宕机时会自动将slave提高为master,继续提供服务。

Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

 二面试

1. 使用Redis有哪些好处?

    (1) 速度快,由于数据存在内存中,相似于HashMap,HashMap的优点就是查找和操做的时间复杂度都是O(1)

    (2) 支持丰富数据类型,支持string,list,set,sorted set,hash

    (3) 支持事务,操做都是原子性,所谓的原子性就是对数据的更改要么所有执行,要么所有不执行

    (4) 丰富的特性:可用于缓存,消息,按key设置过时时间,过时后将会自动删除

2.redis相比memcached有哪些优点?

    (1) memcached全部的值均是简单的字符串,redis做为其替代者,支持更为丰富的数据类型

    (2) redis的速度比memcached快不少

    (3) redis能够持久化其数据

3. redis常见性能问题和解决方案:

1) Master最好不要作任何持久化工做,如RDB内存快照和AOF日志文件。

写内存快照时,save命令调度rdbSave函数,会阻塞主线程的工做;
AOF在重写的时候会占大量的CPU和内存资源。若是不重写AOF文件,这个持久化方式对性能的影响是最小的,可是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。

2) 若是数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

3) 为了主从复制的速度和链接的稳定性,Master和Slave最好在同一个局域网内

4) 尽可能避免在压力很大的主库上增长从库

5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...

这样的结构方便解决单点故障问题,实现Slave对Master的替换。若是Master挂了,能够马上启用Slave1作Master,其余不变。


4. MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?

redis 内存数据集大小上升到必定大小的时候,就会施行数据淘汰策略。

redis 提供 6种数据淘汰策略:

    voltile-lru:从已设置过时时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰

    volatile-ttl:从已设置过时时间的数据集(server.db[i].expires)中挑选将要过时的数据淘汰

    volatile-random:从已设置过时时间的数据集(server.db[i].expires)中任意选择数据淘汰

    allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰

    allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
    no-enviction(驱逐):禁止驱逐数据

由maxmemory-policy 参数设置淘汰策略:

    CONFIG SET maxmemory-policy volatile-lru      #淘汰有过期期的最近最好使用数据

5. redis 适合的场景

Redis最适合全部数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差异。

1) 会话缓存(Session Cache)

用Redis缓存会话比其余存储(如Memcached)的优点在于:Redis提供持久化。

2) 队列

Reids在内存存储引擎领域的一大优势是提供 list 和 set 操做,这使得Redis能做为一个很好的消息队列平台来使用。

3) 排行榜

集合(Set)和有序集合(Sorted Set)也使得这些操做变的很是简单。当要从排序集合中获取到排名最靠前的10个用户–咱们称之为“user_scores”,咱们只须要像下面同样执行便可:
固然,这是假定你是根据你用户的分数作递增的排序。若是你想返回用户及用户的分数,你须要这样执行:

    ZRANGE user_scores 0 10 WITHSCORES

排行榜(leader board)按照得分进行排序。ZADD命令能够直接实现这个功能,而ZREVRANGE命令能够用来按照得分来获取前100名的用户,ZRANK能够用来获取用户排名,很是直接并且操做容易。

这就像Reddit的排行榜,得分会随着时间变化。LPUSH和LTRIM命令结合运用,把文章添加到一个列表中。一项后台任务用来获取列表,并从新计算列表的排序,ZADD命令用来按照新的顺序填充生成列表。列表能够实现很是快速的检索,即便是负载很重的站点。

4)计数器

Redis在内存中对数字进行递增或递减的操做实现的很是好。Redis的命令都是原子性的,你能够轻松地利用INCR,DECR命令来构建计数器系统。

进行各类数据统计的用途是很是普遍的,好比想知道何时封锁一个IP地址。INCRBY命令让这些变得很容易,经过原子递增保持计数;GETSET用来重置计数器;过时属性用来确认一个关键字何时应该删除。

5) 发布/订阅

发布/订阅的使用场景确实很是多。我已看见人们在社交网络链接中使用,还可做为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来创建聊天系统!。

6) 须要精准设定过时时间
能够把有序集合(sorted set)的score值设置成过时时间的时间戳,那么就能够简单地经过过时时间排序,定时清除过时数据了,不只是清除Redis中的过时数据,你彻底能够把Redis里这个过时时间当成是对数据库中数据的索引,用Redis来找出哪些数据须要过时删除,而后再精准地从数据库中删除相应的记录。
相关文章
相关标签/搜索