深入Redis学习教程之知识汇总和常见面试题型及答案

作者 : IT 大叔 本文共4094个字,预计阅读时间需要11分钟 发布时间: 2020-10-26

1.Redis有哪些数据结构
字符串String、字典Hash、列表List、集合Set、有序集合Zset。

除此之外还有:
HyperLogLog,Pub/Sub发布订阅,布隆过滤器,Bitmap位图,Geo等
(要能说出他们的使用场景和特点原理才行)

String类型可以用于:普通的kv缓存,计数器(incr/decr),分布式锁(setex/setnx/watch/事务),限流(incr/setex)

hash类型可以用于缓存mysql中的行数据或者对象数据,一个hash key就mysql表中的一行数据。

List类型可以用于:消息队列(lpush/brpop),分页,还有类似粉丝列表,文章列表(将文章id存到列表中,文章内容标题作者存到hash中)

Set类型可以用于:求交集并集差集,去重(利用不重复性),抽奖(无序性)

Zset类型可以用于:排行榜,延时队列

Bitmap类型:实现大数据量的统计(能够节省大量内存)

HyperLogLog类型:实质还是字符串,可以以极小的空间完成独立数据的统计。

BloomFilter类型:实质还是一个位图类型,可用于在一个大数据集中准确的找到一个小数据集,具体应用有去重,防止缓存穿透。

pub/sub类型:由一个生产者发布消息,多个消费者订阅频道后可以接受到消息,用于消息广播。

2.如果有大量的key需要设置同一时间过期,一般需要注意什么?
可能会出现缓存雪崩的问题(即大量key在同一时刻失效,数据请求在这一刻全打在DB上导致数据库崩溃)。可以通过给每一个key设置的过期时间加一个随机数分散过期时间来解决。

3.如何实现Redis分布式锁?
在修改数据前,使用setnx拿到锁,再用expire给锁加上过期时间防止死锁。在修改数据后用delete释放锁。
为了防止setnx和expire不是一个原子操作而造成的可能发生的死锁,可以使用一个可以同时结合setnx和expire的指令,像python的redis客户端就提供了一个接口:redis.set(key,value,ex=expire,nx=True)的命令保证setnx和expire是一个原子操作。

4.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来?
使用 keys 前缀*
但是keys命令是一个长指令,而redis在执行命令上是一个单线程,这就会阻塞其他客户端命令的执行导致慢查询。
此时可以使用scan指令无阻塞的提取出指定模式的key列表。

5.如何使用redis做消息队列?
使用list类型,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。如果希望在没有消息是不使用sleep进行阻塞,可以用blpop命令。

如果希望生产一次消费多次,可以用pub/sub发布订阅,可以实现 1:N 的消息队列。但是缺点是:在消费者下线的情况下,生产的消息会丢失。

6.如何用redis实现延时队列?
首先什么是延时队列,就是具有延时功能的消息队列。典型的应用场景就是:30分钟内没有付款的订单自动取消。
如果用redis来实现,可以使用zset类型。以订单自动取消为例,将订单数据存在hash结构中,同时订单的id和下单时间放到zset中,其中id作为zset的value,下单时间作为zset的score。

消费者用zrangebyscore指令获取30分钟之前的订单数据轮询(使用定时任务一分钟执行一次轮询)进行处理。

7.Redis是怎么持久化的?
两种方式:rdb快照 和 aof日志
RDB会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要AOF来配合使用。

8.RDB的原理是什么?
你给出两个词汇就可以了,fork和cow。fork是指redis通过创建子进程来进行RDB操作,cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

回答这个问题的时候,如果你还能说出AOF和RDB的优缺点,我觉得我是面试官在这个问题上我会给你点赞,两者其实区别还是很大的,而且涉及到Redis集群的数据同步问题等等。

9.Pipeline有什么好处,为什么要用pipeline?
可以将多次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。

10.是否使用过Redis集群,集群的高可用怎么保证,集群的原理是什么?
Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。
Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

11.Redis的同步机制了解么(主从复制的过程)?
Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将RDB文件全量同步到复制节点,复制节点接受完成后将RDB镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过AOF日志同步即可,有点类似数据库的binlog。

12.为啥Redis那么快?
a.完全基于内存,绝大部分请求是纯粹的内存操作
b.采用单线程,避免了上下文切换,也避免线程间的切换而消耗CPU,不存在加锁和释放锁的操作。
c.使用多路I/O复用模型,非阻塞IO

追问:啥是上下文切换?
我的理解是,多线程并发运行的时候每一个线程都有自己的一段时间片,当一个线程运行完自己时间片内的时间是就会将CPU让给下一个线程运行。此时CPU会将上一个线程的工作环境和进度状态保存下来,从寄存器写入到内存中。等这个线程重新拿到CPU开始工作的时候(从就绪状态回到运行状态),CPU会从内存中读取他上一次工作的进度和环境(也就是上下文环境),这样才能从上一次断开的地方继续工作。

举个通俗的例子就是:我要看10本书,看了一本书的一半的时候,用书签标记一下读到了哪里,然后我就去看另一本书去了。下次就直接从这本书的书签处继续往下读。

13.redis是单线程的,我们现在服务器都是多核的,那不是很浪费?
可以在单机上部署多个redis节点。例如redis集群,主从复制。

14.redis的内存淘汰机制
Redis的过期策略,是有定期删除+惰性删除两种。

定期好理解,默认每隔一段时间(100秒)就随机抽一些设置了过期时间的key,去检查是否过期,过期了就删了。

为啥不扫描全部设置了过期时间的key呢?
假如Redis里面所有的key都有过期时间,都扫描一遍?那太恐怖了,而且我们线上基本上也都是会设置一定的过期时间的。全扫描跟你去查数据库不带where条件不走索引全表扫描一样,100s一次,Redis累都累死了。

如果一直没随机到很多key,里面不就存在大量的无效key了?
此时就用到了惰性删除:
即当用户查询到某个key的时候,redis会查看这个key是否过期。过期则不返回给用户,直接删掉。

当内存溢出时,redis会根据maxmemory-policy设定的策略对key进行删除直到空出足够的空间。

15.有没有考虑过多个服务器同时(并发)请求redis带来的数据问题?
以秒杀超卖为例,ABC三个服务器同时抢一个库存量只有1的商品,可能3个用户都拿到库存为1(例如redis的命令队列中3个get命令在3个decr命令之前的情况),于是都减库存,导致库存变为-2。
面对这种情况,我们可以使用redis分布式锁,控制用户有序的依次请求这个key,例如A先拿到锁的话,他就可以先将库存-1,然后B再拿到锁,查询库存为0于是抢购失败。

总结:只需设置锁使得多个系统顺序访问,同一时间只有一个用户请求到redis即可,当然get查询和decr减库存都得在锁的保护之内,使其成为一个原子操作,不然锁就是去了意义。

16.你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?
我们知道,读数据的时候,基本流程是缓存有就读缓存,缓存没有就读DB,然后顺便写入缓存。

但是如果是写数据呢?请注意,我们说的写数据大多数场景不是说用户修改数据,而是后台人员修改数据。例如管理员在后台修改商品价格,更新文章内容等等,此时管理员是直接写入到mysql,但是redis的数据还没有更新。

此时有两种策略:
最简单的就是等缓存的有效期过期,下次用户访问到Db是生成新的缓存。如果怕并发量大,把Db打崩,你可以在key即将失效时,在夜晚的时候用定时任务更新缓存。

另一种方式是先更新数据库,再删除缓存。
为什么是删除缓存,而不是更新缓存?因为我要等用户访问它的时候让他自动更新。对于频繁修改但很少读取的数据,这种做法可以大幅降低开销。

所以你要考虑一点:这个缓存到底会不会被频繁访问到?

其实删除缓存,而不是更新缓存,就是一个懒加载的思想,不要每次都重新做复杂的计算,不管它会不会用到,而是让它到需要被使用的时候再重新计算。

17.redis和memcached的区别
从数据结构上讲:
Redis 相比 Memcached 来说,拥有更多的数据结构,能支持更丰富的数据操作。

从集群来讲:
Redis 原生支持集群模式,而 Memcached 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据(得由客户端实现分片算法)。

从性能来讲:
Redis 只使用单核,而 Memcached 可以使用多核,所以平均每一个核上 Redis 在存储小数据时比 Memcached 性能更高。而在 100k 以上的数据中,Memcached 性能要高于 Redis,虽然 Redis 最近也在存储大数据的性能上进行优化,但是比起 Remcached,还是稍有逊色。

redis是单线程,避免了线程的切换上下文切换,锁的性能消耗;memcache是多线程。

从持久化来说:
redis支持持久化,而memcache不支持

免责声明:
1. 本站资源转自互联网,源码资源分享仅供交流学习,下载后切勿用于商业用途,否则开发者追究责任与本站无关!
2. 本站使用「署名 4.0 国际」创作协议,可自由转载、引用,但需署名原版权作者且注明文章出处
3. 未登录无法下载,登录使用金币下载所有资源。
IT小站 » 深入Redis学习教程之知识汇总和常见面试题型及答案

常见问题FAQ

没有金币/金币不足 怎么办?
本站已开通每日签到送金币,每日签到赠送五枚金币,金币可累积。
所有资源普通会员都能下载吗?
本站所有资源普通会员都可以下载,需要消耗金币下载的白金会员资源,通过每日签到,即可获取免费金币,金币可累积使用。

发表评论