基础
1 为什么用redis
传统的关系型数据库如Mysql已经不能适用所有的场景了,比如秒杀的库存扣减,APP首页的访问流量高峰等等,都很容易把数据库打崩,所以引入了缓存中间件,选择了Redis
为啥Redis那么快?
Redis是采用基于内存的单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是可以达到10万+的QPS(每秒内查询次数)。
完全基于内存
数据结构简单
采用单线程
使用多路I/O复用模型,非阻塞IO
使用底层模型不同,Redis直接自己构建了VM 机制
Redis有哪些数据结构?
String、Hash、List、Set、SortedSet
三种特殊的结构:
HyperLogLog、Geo、Pub/Sub
如果你还想加分,那你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML
如果有大量的key需要设置同一时间过期,一般需要注意什么?
如果大量的key过期时间设置的过于集中,到过期的那个时间点,Redis可能会出现短暂的卡顿现象。严重的话会出现缓存雪崩。
解决:一般需要在时间上加一个随机值,使得过期时间分散一些
使用过setnx命令吗,它一般用在什么地方
它的意思是只有在key不存在的时候才设置,可以利用它来实现锁的效果。
Redis的同步机制了解么?
Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave
,并同时将后续修改操作记录到内存buffer,待完成后将RDB文件全量同步到复制节点,复制节点接受完成后将RDB镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过AOF日志同步即可,有点类似数据库的binlog。
是否使用过Redis集群,集群的高可用怎么保证,集群的原理是什么?
Redis Sentinal
着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。Redis Cluster
着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。
使用过Redis分布式锁么,它是什么回事?
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
Redis异步队列,怎么做
一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
追问:可不可以不用sleep?
list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。
再追问:能不能生产一次消费多次呢?
使用pub/sub主题订阅者模式,可以实现 1:N 的消息队列。
还追问:对方继续追问 pub/su b有什么缺点?
在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如RocketMQ等。
终极追问:Redis如何实现延时队列?
使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。
(ps:这时要注意,不要自己把自己坑了,每次的回答,后面都要能接上)
Redis是怎么持久化的?服务主从数据怎么交互的?
RDB做镜像全量持久化,AOF做增量持久化。
因为RDB耗时长,不够实时,在停机的时候会导致大量丢失数据,所以需要AOF来配合使用。可以把AOF理解为每次操作的日志。
不过Redis本身的机制是 AOF持久化开启且存在AOF文件时,优先加载AOF文件;AOF关闭或者AOF文件不存在时,加载RDB文件;加载AOF/RDB文件城后,Redis启动成功;
追问:如果突然机器掉电会怎样?
取决于AOF日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据。
追问RDB的原理是什么?
你给出两个词汇就可以了,fork
和cow
fork是指redis通过创建子进程来进行RDB操作;cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。
ps:回答这个问题的时候,如果还能说出AOF和RDB的优缺点就更好
Pipeline有什么好处,为什么要用pipeline?
可以将多次IO往返的时间缩减为一次,前提是pipeline
执行的指令之间没有因果相关性。使用redis-benchmark
进行压测的时候可以发现影响redis的QPS
峰值的一个重要因素是pipeline批次指令的数目。
setnx之后执行expire之前进程意外停止,那会怎么样?
set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用。
灵活性的面试图
假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来
使用keys指令可以扫出指定模式的key列表。
追问:
如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长
``
``
redis 支持持久化