Redis面试题

249 阅读11分钟

Redis面试题

1、Redis的使用场景?
(1)缓存数据,方便其他进程获取
(2)常规计数,因为redis的操作是原子性的,不会出现线程安全问题
(3)分布式锁,redis的set命令有个NX的参数,可以实现key不存在时才插入。可以插入成功,说明加锁成功

2、Redis有哪些常见数据类型?
(1)字符串类型
(2)list类型
(3)hash类型
(4)set类型
(5)zset类型
(6)特殊类型:bitmaps等

3、Redis除了作为缓存,还有别的用处吗?
Redis还可以做消息队列。主要是通过发布、订阅和list数据类型这些功能来实现队列的功能。一些客户端订阅某一频道,另一些客户端在这个频道上发布消息,订阅的客户 端可以获得这些消息。

4、Redis和Memcached的区别?
(1)Redis支持多种数据类型,而Memcached只支持hash
(2)Redis支持数据复制和持久化,Memcached不支持
(3)Redis的功能比Memcached多,例如发布/订阅等
(4)Redis的语言兼容性没有Memcached好
(5)Redis在存储小数据性能比Memcached好,存储大数据Memcached好

5、Redis为什么快?
(1)Redis的数据是存在内存中的,所以操作快
(2)Redis有多种数据类型存储数据,这些数据结构提高了操作效率
(3)Redis在处理网络io时,使用的是多线程处理
(4)Redis在执行命令时是单线程,避免了多线程抢夺资源的情况

6、Redis中的zset的score相同时,怎么排序?
按照元素的插入顺序排序

7、Redis的过期数据删除策略?
(1)定期删除:每隔一段时间,从设置了过期时间的数据中抽查部分数据,如果过期就删除,这样会导致没有抽查到的过期数据没有删除,所以还需要惰性删除
(2)惰性删除:操作某一数据时,如果检查到此数据过期了,就删除

8、Redis的内存淘汰策略?
(1)noeviction:内存满时,不再写入数据,返回报错
(2)random:随机删除一些数据,不过有不同的作用范围。volatile-random是从设置了过期时间的数据中删除, allkeys-random是从所有数据中删除
(3)volatile-ttl:按照过期时间的顺序,删除过期数据,优先删除快过期的数据
(4)lru:利用lru算法删除数据,不过有不同的作用范围。volatile-lru是从设置了过期时间的数据中删除,allkeys-lru是从所有数据中删除
(5)lfu:利用lfu算法删除数据,作用范围与lru相同

9、lru和lfu的区别?
(1)lru是最近被访问的数据被保留。例如设置一个时间段,在这个时间段内被访问过的数据保留下来
(2)lfu是频繁被访问的数据被保留。例如设置一个访问频率阈值,超过这个阈值的被保留

10、Redis的持久化方式?
(1)RDB方式:RDB是根据配置文件中的save配置,生成数据快照存到磁盘上。优点是:生成的文件小,恢复起来快。 缺点是:如果在备份间隔时间内,如果服务器挂掉,丢失的是这段时间的数据。
(2)AOF方式:AOF是将执行命令记录存到磁盘上。优点是:落盘数据的时间间隔短,如果发生数据丢失不会太多。缺点是:AOF方式存储的数据会越来越大,恢复起来也消耗性能。而且在低版本,AOF文件中有很多重复操作和无效操作。
(3)在4.0版本之后,支持重写,即在AOF文件的开头是RDB信息,后面是增量操作信息。
(4)Redis在进行落盘时,依靠子进程去完成。Redis会调用系统fork命令,创建子进程,子进程进行数据落盘。此时,Redis父进程依然可以对客户端做出响应。但在此阶段,客户端增删改数据时,会触发写时复制操作,子进程是无法感知父进程修改的数据的。所以子进程落盘的数据是子进程创建成功时的数据。

11、缓存击穿、缓存穿透和缓存雪崩?
(1)缓存击穿:热点数据过期了,此时大量请求落到数据库上,导致数据库奔溃。
解决办法:热点数据永不过期;设置分布式锁,当数据过期了,只能有一个请求访问数据,并且将热点数据写到Redis中
(2)缓存穿透:要访问的数据不在Redis中也不在数据库中,导致大量请求访问数据库
解决办法:在Redis中设置空值,这些空值设置较短的过期时间,如果在设置空值前,瞬间有大量请求的话,由于Redis是串行执行命令,设置空值会放在这些请求的后面执行,所以这些请求还是会落到数据库上,所以可以加一把锁,让这些请求先竞争锁,竞争到锁的请求才能访问数据库,然后设置空值,如此其他请求就不会访问数据库了;使用布隆过滤器判断数据是否存在。
(3)缓存雪崩:大量的热点数据在某段时间内过期了
解决办法:热点数据的过期时间尽可能的均匀分布。设置分布式锁。

12、如何保证缓存和数据库一致性?
(1)延迟双删:首先删除缓存中的数据,然后更新数据库,延迟几秒后再删除缓存
原因:线程A更新数据,线程B读取数据。线程B在线程A更新数据库之前读取 到旧数据。此时线程B会将旧数据写到缓存中,所以线程A要延迟几秒,等线程B 写完后再删除。这个方法性能好,维护成本低。
(2)利用消息队列:将数据发送到RocketMQ,然后消费者消费消息更新到缓存和数据库。
(3)监听binlog日志:使用canal,监听binlog日志,数据库数据发生修改,binlog日志文件会发生变化,获得变化数据后,更新缓存。canal模拟了数据库的从机,数据库在主从复制时,会把binlog日志发送给canal,canal进行缓存更新。

13、Redis是单线程还是多线程?
Redis的工作线程是单线程的。在6.x高版本,Redis的io线程是多线程的。

14、Redis的主从一致性?
(1)Redis是弱一致性,采用的是异步方式,主机将数据发送给从机就不管了。
(2)Redis在主从同步时,有两种方式,全量同步和增量同步
(3)在Redis集群刚搭建完成,从机连上主机时,向主机发送psync命令开始全量同步。这个过程中,主机会创建一个子进程,子进程向从机发送数据。如果此时主机有增删改的命令,会存入replication buffer中。等从机的RDB文件加载完成,主机再将buffer中的命令发送给从机,保证数据一致。待同步完成后,主从机保持一个长连接,主机通过此连接将后续的增删改操作同步给从机
(4)如果从机在某段时间与主机断开连接后又连上,此时主从机会进行一次同步。在从机断开连接的这段时间内,主机会将增删改的命令存入环形缓存replication backlog buffer。此缓存如果已经存满,会覆盖之前的命令。所以,当从机连接上主机时,如果环形缓存已满,就需要进行全量同步,否则增量同步。

15、Redis当做分布式锁的问题?
单机模式下:
(1)必须使用原子命令进行加锁,而且需要给锁设置过期时间。命令是:setnx key value ex outtime 设置过期时间是因为如果加锁的进程挂了,锁没有过期时间,这个锁就没法被释放了。
(2)在释放锁的时候,需要先获取锁,然后判断是否是当前进程加的锁,如果是,才释放。因为有可能在进程加完锁执行业务代码时,redis挂了,此时其他进程加上锁了,如果当前进程执行完业务去释放锁不做判断,会把其他进程加的锁释放掉。并且,还有一点需要注意,释放锁的流程是先获取锁做判断,然后删除锁,这个过程要保证原子性,生产环境一般使用lua脚本实现。
(3)以上方案还存在一个问题:如果业务执行时间比锁过期时间要长怎么办?在业务还没执行完,锁就被释放了。解决方案是另起一个线程,在业务执行过程中,不断的延长锁的过期时间。
(4)以上方案是单机模式下,单机模式下有一个常见的问题,就是redis挂了,锁信息全没了。此时,可以使用redis集群方案。如果使用的主从集群,依然存在一个问题,就是进程在主机上加了锁,还没有同步到从机时,主机挂掉了。所以,一般集群不使用主从模式,而是多主的模式
集群模式下:
(5)假设集群中有5台redis,都是主机。在加锁时,按照一定的顺序,给每台redis加锁,当加锁成功的redis数量过半时,也就是3台时,加锁成功。如此一来,其他进程加锁也需要数量过半,加锁不会成功。
(6)这种方案有个问题,就是其中一个已经加锁的redis挂掉了,被重启了,锁信息没了,其他进程就可以加锁成功了。这个问题的解决方案也很简单,就是延迟重启redis,目的是让加锁的业务跑完,让redis中的锁都被释放掉,再重启就没事了。
(7)以上的方案还有一个问题,就是进程在运行过程中,可能发生FullGC,导致STW,此时如果需要延长锁的过期时间,由于STW了,没有延长,导致锁过期被删除了,其他进程加锁成功了。这个问题是非常非常小的概率事件,一般不会遇见,而且,在生产环境中,大部分公司不会使用redis集群模式来作为分布式锁(这种模式叫做红锁)。
生产环境下:
(8)在生产环境下,一般还是使用单机redis,但是有单机redis挂掉以及STW的问题。其实,redis实际上很稳定,很少会挂掉。
(9)如果非要解决这个问题,可以加上一台mysql,进程在加锁时,mysql中也存一份。当redis挂掉或者STW导致锁信息没了,此时,其他进程加锁成功,并且将mysql中的锁信息做了修改。之前加锁的进程执行完业务代码后,要删除锁信息,发现mysql中的锁不是自己加的锁,此时,此进程将之前执行的业务都回滚。

16、Redis集群?
(1)Redis集群中一般会有多个主机,数据分片会分散存储在不同的主机上,这些主机都可以进行读写操作。
(2)Redis集群中的每个节点上都保存了集群完整的拓扑信息。包括每个节点的ID、IP地址、端口、负责的哈希槽范围等。
(3)Redis集群一共有16384(2^14)个哈希槽。每个主机都拥有一部分哈希槽。查询和新增数据时,根据key值和哈希算法求出哈希值,再对16384求余数。看余数落在哪个哈希槽区间内,就去对应的主机上操作。

17、如何增加一台redis从机
(1)在从机的配置文件中设置配置项:replicaof 主机IP 主机Port。然后启动从机
(2)在任意主机上执行命令:CLUSTER MEET 从机IP 从机Port。让集群知道有新从机
(3)在从机上执行命令:CLUSTER REPLICATE 主机IP。设置从机数据同步的主机
如果集群中只有一个主节点,执行步骤(1)就可以添加新的从机。如果集群中有多个主节点,以上三个步骤都要执行,新的从机才能添加到集群中。