关于Redis,面试都会问什么?(持续更新中...)

文章目录

      • 问题1:为什么要使用Redis?
      • 问题2:为什么使用Redis,不使用Memcached?
      • 问题3:Redis都有哪些数据结构?这些数据结构分别最适合的场景?
      • 问题4:如果有大量的key需要设置同一时间过期,一般需要注意什么?
      • 问题5:如何实现Redis分布式锁?
      • 问题6:redis中keys命令
      • 问题7:redis是怎么持久化?服务主从数据怎么交互的?
      • 问题8:pipeline有什么好处?为什么要使用pipeline?
      • 问题9:redis为何具备支撑高并发的特性?

问题1:为什么要使用Redis?

:因为传统的关系型数据库如MySQL已经不能适用于所有场景了,如秒杀的库存扣减、APP首页的访问流量高峰等等,很容易把数据库打崩,所以要引入缓存中间件。目前市面上常用的缓存中间件有Redis和Memcached,中和考虑他们的优缺点,最终选择Redis

问题2:为什么使用Redis,不使用Memcached?

:redis支持更多的数据类型,Memcached仅支持key/value键值对。使用简单的key-value存储的话,Memcached的内存利用率更高,而如果Redis采用hash结构来做key-value存储,由于其组合式的压缩,其内存利用率会高于Memcached。
从性能上来讲,虽然memcache支持多核,但系统的瓶颈一般不在缓存上。
但抛开性能不说,与 Redis 相比,Memcached 有几个很明显的缺陷:

  1. key、value 大小有限制,尤其是 key,印象中只能存几百字节,对于比较长的 key,只能哈希后再存。
  2. key 难以遍历,导致管理起来很麻烦,运维、数据迁移等都是头疼事。
  3. key 过期后,不会自动删除,除非主动访问这个 key,或者空间快满了开始清理。实际使用中,偶尔会出现某个高频读写的 key 过期时间自动变成永不过期,不按预设的过期时间来。

问题3:Redis都有哪些数据结构?这些数据结构分别最适合的场景?

:基本类型:字符串String、字典Hash、列表List、集合Set、有序集合SortedSet
1、字符串String:
redis最基本的数据类型,首先键是字符串类型,而且其他几种结构都是再字符串类型基础上构建的。(简单的字符串、复杂的字符串(xml、json)、数字(整数、浮点数)、二进制(图片、音频、视频),最大不能超过512M)
使用场景:缓存功能、计数器、共享session、限速

共享session:出于负载均衡考虑,分布式服务会将用户信息的访问均衡到不同服务器上。用户刷新一次访问可能需要重新登录,为了避免这个问题可以用redis将用户session集中管理。这种模式下只要保证redis的高可用和扩展性,每次获取用户更新或查询登录信息都直接从redis中集中获取。
限速:处于安全考虑,每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率。

2、字典Hash:
在redis中,哈希类型是指键本身又是一种键值对结构,如value={{field1, value1}, …{fieldn, valuen}}
使用场景:哈希结构相对于字符串序列化缓存信息更加直观,并且在更新操作上更加便捷。所以常用胡用户信息等管理。

3、列表List:
列表类型是用来存储多个有序的字符串,列表中每个字符串成为元素,一个列表最多可以存储2^32-1个元素。可以充当栈和队列的角色。
优点:列表元素是有序的,可以通过索引下标获取某个或某个范围内的元素列表;列表中元素是可以重复的
使用场景:消息队列

消息队列:redis的lpush+brpop命令组合即可实现阻塞队列,生产者客户端是用lupsh从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞时的“抢”列表尾部元素,多个客户端保证了消费的负载均衡和高可用性。

redis做异步队列,一般会使用list结构作为队列,rpush生产消息,lpop消费消息,当lpop没有消息的时候,要适当sleep一会再试。或者使用blpop消费消息,它再没有消息的时候,会阻塞住知道消息到来。
使用pub/sub主题订阅者模式,可以实现1:N的消息队列。但是再消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如RocketMQ等。

使用列表技巧:
lpush+lpop=Stack(栈)
lpush+rpop=Queue(队列)
lpush+ltrim=Capped Collection(有限集合)
lpush+brpop=Message Queue(消息队列)
4、集合Set:
集合类型也是可以保存多个字符串的元素,但和列表不同的是集合不允许有重复的元素。并且集合里的元素是无序的,不能通过索引获取元素。
使用场景:标签

标签:集合类型比较典型的使用场景。用户和标签的关系维护应该放在一个事务内执行,防止部分命令失败造成数据不一致。
sadd=tagging(标签)
spop/srandmember=random item(生成随机数,比如抽奖)
sadd+sinter=social Graph(社交需求)

5、有序集合:
有序集合和集合有着必然的联系,他保留了集合不能有重复成员的特性,但不同得是,有序集合中的元素是可以排序的,但是它和列表的使用索引下标作为排序依据不同的是,它给每个元素设置一个分数,作为排序的依据。
使用场景:排行榜

排行榜:有序集合经典使用场景。例如视频网站需要对用户上传的视频做排行榜,榜单维护可能是多方面:按照时间、按照播放量、按照获得的赞数等。

BloomFilter(布隆过滤器)

问题4:如果有大量的key需要设置同一时间过期,一般需要注意什么?

**答:**如果大量的key过期时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象。严重的话会出现缓存雪崩,我们一般需要在时间上加一个随机值,使得过期时间分散一些。

问题5:如何实现Redis分布式锁?

**答:**使用setnx、getset、expire、del这4个redis命令实现。
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放;
expire和setnx不是原子操作,如果setnx的节点突然挂掉,那么expire来不及执行就变成了无止尽的锁,这时候就可以使用redis的set多参数方法

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。不同主机之间共享了一组资源,访问这些资源的时候,需要互斥来防止彼此干扰来保持一致性,所欲就需要使用到分布式锁。
分布式锁有三种实现方式:①数据库乐观锁;②基于Redis的分布式锁;③基于ZooKeeper的分布式锁

问题6:redis中keys命令

答: keys命令可以扫除指定模块的key列表。
但是redis是单线程的,keys命令会导致线程阻塞一段时间,线上服务会停顿,直至命令执行完毕,才能恢复。这时可以使用scan命令。scan命令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,再有客户端做一次去重就可以了。

问题7:redis是怎么持久化?服务主从数据怎么交互的?

**答:**RDB做的事镜像全量持久化,AOF做增量持久化。因为RDB会耗费较长时间,不够实时,再停机的时候会导致大量丢失数据,所以需要AOF来配合使用。再redis实例重启时,会使用RDB持久化文件重新构建内存,再使用AOF重放近期的操作指令来实现完整恢复重启之前的状态。

RDB的原理:fork是指redis通过创建子进程来进行RDB操作,cow指的是copy on write,子进程创建后吗父子进程共享数据段,父进程继续提供读写服务,写藏的页面数据会主键和子进程分离开来。

问题8:pipeline有什么好处?为什么要使用pipeline?

**答:**可以将多次IO往返的时间缩减为一次,前提是pipeline执行的之峰之间没有因果相关性。使用redis-benchmark进行压测的时候可以发现影响redis的QPS峰值的一个重要因素就是pipeline批次指令的数目。

问题9:redis为何具备支撑高并发的特性?

答: redis 采用网络IO多路复用技术来保证在多连接的时候, 系统的高吞吐量。
多路,指的是多个socket连接,复用-指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。epoll是最新的也是目前最好的多路复用技术。这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路I/O复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络IO的时间消耗),且Redis在内存中操作数据的速度非常快(内存内的操作不会成为这里的性能瓶颈),主要以上两点造就了Redis具有很高的吞吐量。

你可能感兴趣的:(面经)