吐血整理!42道Redis面试专题带答案详解

1,025 阅读14分钟

redis面试专题 

1、redis 和memcached什么区别?为什么高并发下有时单线程的redis 比多线程的memcached效率要高?

**区别: **

  1. mc可缓存图片和视频。rd 支持除k/v更多的数据结构

  2. rd可以使用虚拟内存,rd 可持久化和aof灾难恢复,rd 通过主从支持数 据备份; 

  3. rd可以做消息队列。 原因:mc多线程模型引入了缓存一致性和锁,加锁带来了性能损耗。 

2、redis 主从复制如何实现的?redis的集群模式如何实现?redis的key 是如何寻址的? 

主从复制实现:主节点将自己内存中的数据做一份快照,将快照发给从节 点,从节点将数据恢复到内存中。之后再每次增加新数据的时候,主节点 以类似于mysql的二进制日志方式将语句发送给从节点,从节点拿到主节 点发送过来的语句进行重放。 

分片方式: 

-客户端分片

-基于代理的分片

●Twemproxy

●codis -路由查询分片 

●Redis-cluster

3、使用redis如何设计分布式锁?说一下实现思路?使用 zk可以吗?如何 实现?这两种有什么区别? 

Redis

  1. 线程A setnx(上锁的对象,超时时的时间戳t1),如果返回true,获得锁。

  2. 线程B用get获取t1,与当前时间戳比较,判断是是否超时,没超时false,
    若超时执行第3步;

  3. 计算新的超时时间t2,使用getset命令返回t3(该值可能其他线程已经修改过,如果t1==t3,获得锁,如果t1!=t3说明锁被其他线程获取了。

  4. 获取锁后,处理完业务逻辑,再去判断锁是否超时,如果没超时删除锁,如果已超时,不用处理(防止删除其他线程的锁)。

zk

  1. 客户端对某个方法加锁时,在zk.上的与该方法对应的指定节点的目录 下,生成一个唯一的瞬时有序节点node1;

  2. 客户端获取该路径下所有已经创建的子节点,如果发现自己创建的 node1的序号是最小的,就认为这个客户端获得了锁。

  3. 如果发现node1不是最小的,则监听比自己创建节点序号小的最大的节点,进入等待。

  4. 获取锁后,处理完逻辑,删除自己创建的node1即可。区别:zk性能差 一些,开销大,实现简单。 

4、知道redis的持久化吗?底层如何实现的?有什么优点缺点? 

RDB(Redis DataBase: 在不同的时间点将redis的数据生成的快照同步到磁 盘等介质上):内存到硬盘的快照,定期更新。缺点:耗时,耗性能(fork+io操 作),易丢失数据。 

**AOF(Append Only File:**将redis所执行过的所有指令都记录下来,在下次 redis重启时,只需要执行指令就可以了):写日志。缺点:体积大,恢复速度慢。 

5、redis 过期策略都有哪些?LRU算法知道吗?写一下java代码实现? 

过期策略

定时过期(一key一定时器),惰性过期:只有使用key时才判断key是否已 过期,过期则清除。定期过期:前两者折中。 

LRU 算法实现

  1. 通过双向链表来实现,新数据插入到链表头部;

  2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;

  3. 当链表满的时候,将链表尾部的数据丢弃。
    LinkedHashMap:HashMap和双向链表合二为- -即是LinkedHashMap。HashMap是无序的,LinkedHashMap 通过维护一个额外的双向链表保证了迭代顺序。该迭代顺序可以是插入顺序(默认),也可以是访问顺序。

6、缓存穿透、缓存击穿、缓存雪崩解决方案?

缓存穿透

指查询一个一定不存在的数据,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到DB去查询,可能导致DB挂掉。

解决方案:

1.查询返回的数据为空,仍把这个空结果进行缓存,但过期时间会比较短;

2.布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免了对DB的查询。

缓存击穿

对于设置了过期时间的key,缓存在某个时间点过期的时候,怡好这时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把DB压垮。

解决方案:
1.使用互斥锁:当缓存失效时,不立即去load db,先使用如Redis的setnx去设置一个互斥锁,当操作成功返回时再进行load db的操作并回设缓存,否则重试get缓存的方法。
2.永远不过期:物理不过期,但逻辑过期(后台异步线程去刷新)。

缓存雪崩

设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB, DB瞬时压力过重雪崩。与缓存击穿的区别:雪崩是很多key,击穿是某一个key缓存。

解决方案:

将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如 1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

7、缓存与数据库不一致怎么办

假设采用的主存分离,读写分离的数据库, 

如果一个线程A先删除缓存数据,然后将数据写入到主库当中,这个时候,主库和从库同步没有完成,线程B从缓存当中读取数据失败,从从 库当中读取到旧数据,然后更新至缓存,这个时候, 缓存当中的就是旧的数据。 

发生上述不一致的原因在于,主从库数据不一致问题,加入了缓存之后, 主从不一致的时间被拉长了 处理思路:在从库有数据更新之后,将缓存当中的数据也同时进行更新,即当从库发生了数据更新之后,向缓存发出删除,淘汰这段时间写入的旧数据。

8、主从数据库不一致如何解决 

场景描述,对于主从库,读写分离,如果主从库更新同步有时差就会导致主从库数据的不一致

  1. 忽略这个数据不一致, 在数据一 致性要求不高的业务下,未必需要时 时一致性 

  2. 强制读主库,使用一个高可用的主库,数据库读写都在主库,添加一 个缓存,提升数据读取的性能。 

  3. 选择性读主库,添加一个缓存,用来记录必须读主库的数据,将哪个 库,哪个表,哪个主键,作为缓存的key,设置缓存失效的时间为主从库同 步的时间,如果缓存当中有这个数据,直接读取主库,如果缓存当中没有 这个主键,就到对应的从库中读取。

9、Redis 常见的性能问题和解决方案 

  1. master 最好不要做持久化工作,如RDB内存快照和AOF日志文件 

  2. 如果数据比较重要,某个slave开启AOF备份,策略设置成每秒同步一次

  3. 为了主从复制的速度和连接的稳定性, master和Slave最好在一个局域网内 

  4. 尽量避免在压力大得主库上增加从库 

  5. 主从复制不要采用网状结构,尽量是线性结构,Master<- Slave1<---Slave2....

10、Redis 的数据淘汰策略有哪些 

voltil-lru从已经设置过期时间的数据集中挑选最近最少使用的数据淘汰 

voltile-tt从已经设置过期时间的数据库集当中挑选将要过期的数据 

voltile-random从已经设置过期时间的数据集任意选择淘汰数据

allkeys-lru 从数据集中挑选最近最少使用的数据淘汰 

allkeys-random从数据集中任意选择淘汰的数据no-eviction禁止驱逐数据 

11、Redis 当中有哪些数据结构 

字符串String、 字典Hash、列表List、集合Set、有序集合SortedSet。 如果是高级用户,那么还会有,如果你是Redis中高级用户,还需要加上 下面几种数据结构HyperLogLog、Geo、 Pub/Sub。 

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

使用keys指令可以扫出指定模式的key列表。 

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

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

13、使用Redis做过异步队列吗,是如何实现的 

使用list类型保存数据信息,rpush 生产消息,lpop 消费消息,当lpop没 有消息时,可以sleep一段时间,然后再检查有没有信息,如果不想 sleep的话,可以使用blpop,在没有信息的时候,会一直阻塞,直到信息 的到来。redis 可以通过pub/sub主题订阅模式实现一个生产者,多个消 费者,当然也存在一定的缺点,当消费者下线时,生产的消息会失。 

14、Redis 如何实现延时队列 

使用sortedset,使用时间戳做score,消息内容作为key,调用zadd来生产 消息,消费者使用zrangbyscore获取n秒之前的数据做轮询处理。

15、Redis相比memcached有哪些优势? 

  1. memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 

  2. redis的速度比memcached快很多

  3. redis可以持久化其数据 

16、Redis支持哪几种数据类型? 

String、List、 Set、 Sorted Set、hashes 

17、Redis主要消耗什么物理资源? 

内存。 

18、Redis 的全称是什么? 

Remote Dictionary Server。 

19、Redis 有哪几种数据淘汰策略? 

noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被 使用的命(大部分的写入指令,但DEL和几个例外) 

allkeys-lru:尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。 

volatile-lru:尝试回收最少使用的键(L RU),但仅限于在过期集合的键,使得 新添加的数据有空间存放。 

allkeys-random:回收随机的键使得新添加的数据有空间存放。 

volatile-random:回收随机的键使得新添加的数据有空间存放,但仅限于在 过期集合的键

volatile-tt:回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使 得新添加的数据有空间存放。 

20、Redis 官方为什么不提供Windows版本? 

因为目前Linux版本已经相当稳定,而且用户量很大,无需开发windows 版本,反而会带来兼容性等问题。

21、一个字符串类型的值能存储最大容量是多少? 

512M 

22、为什么Redis需要把所有数据放到内存中? 

Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。 

所以redis具有快速和数据持久化的特征。如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。 

在内存越来越便宜的今天,redis将会越来越受欢迎。如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。 

23、Redis集群方案应该怎么做?都有哪些方案? 

  1. codis。 目前用的最多的集群方案,基本和twemproxy一致的效果,但它支持在节点数量改变情况下,旧节点数据可恢复到新hash节点。 

  2. redis cluster3.0自带的集群,特点在于他的分布式算法不是一致性 hash,而是hash槽的概念, 以及自身支持节点设置从节点。具体看官方文档介绍。

  3. 在业务代码层实现,起几个毫无关联的redis实例,在代码层,对key 进行hash计算,然后去对应的redis 实例操作数据。这种方式对hash层代码 要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的 自动脚本恢复,实例的监控,等等。 

24、Redis集群方案什么情况下会导致整个集群不可用? 

有A, B, C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5 501-1 1000这个范围的槽而不可用。 

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

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

26、Redis 支持的Java客户端都有哪些?官方推荐用哪个? 

Redisson、Jedis、 lettuce 等等,官方推荐使用Redisson。 

27、Redis 和Redisson有什么关系? 

Redisson是-个高级的分布式协调Redis客服端,能帮助用户在分布式环 境中轻松实现一些Java的对象(Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, List Multimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteL ock, Atomi cL _ong, CountDownL atch, Publish/ Subscribe, HyperLogL og)。 

28、Jedis与Redisson对比有什么优缺点? 

Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis 命 令的支持; 

Redisson实现了分布式和可扩展的Java数据结构,和Jedis相比,功能 较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis 特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者 能够将精力更集中地放在处理业务逻辑上。 

29、Redis如何设置密码及验证密码? 

设置密码:config set requirepass 123456 

授权密码:auth 123456

30、说说Redis哈希槽的概念? 

Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis 集群有 16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。 

31、Redis集群的主从复制模型是怎样的? 

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用, 所以集群使用了主从复制模型,每个节点都会有N-1个复制品. 

32、Redis 集群会有写操作丢失吗?为什么? 

Redis并不能保证数据的强一致性,这意味这在实际中集群在特定的条件 下可能会丢失写操作。 

33、Redis 集群之间是如何复制的? 

异步复制 

34、Redis 集群最大节点个数是多少?

 16384个。 

35、Redis 集群如何选择数据库? 

Redis集群目前无法做数据库选择,默认在0数据库。 

36、怎么测试Redis的连通性? 

ping 

37、Redis中的管道有什么用? 

一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读 取该答复。 

这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多POP3 协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。 

38、怎么理解Redis事务? 

事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执 行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。 

39、Redis 事务相关的命令有哪几个?

 MULTI、EXEC、DISCARD、WATCH 

40、Redis key的过期时间和永久有效分别怎么设置? 

EXPIRE和PERSIST命令。 

41、Redis 如何做内存优化? 

尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。 比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏, 邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散 列表里面。 

42、Redis 回收进程如何工作的? 

一个客户端运行了新的命令,添加了新的数据。 

Redi检查内存使用情况,如果大于maxmemory的限制,则根据设定好的 策略进行回收。 

一个新的命令被执行,等等。 

所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收 回到边界以下。 如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一 个新的键),不用多久内存限制就会被这个内存使用量超越。 

-end-

  • 创作不易, 非常欢迎大家的点赞、评论和关注
  • 你的点赞、评论以及关注
  • 是对我最大的支持和鼓励!