Skip to content

Redis面试题-场景

声明

本文中部分内容摘自网络(下方表示出处),如有违规可联系我进行删除 🙏🏻

目录索引

1. 缓存

Redis实现缓存功能的基本原理是将常用的数据存储在内存中,以加快数据访问速度,并且可以通过设置过期时间来自动淘汰过期的缓存数据。适合缓存的数据是那些更新频率较低,访问频率较高的数据,例如商品信息,用户信息等。

2. 延迟队列

延迟队列是一种用于处理延迟消息的队列,它的主要特点是能够在指定的时间间隔后消费消息(执行任务)。基本上类似一个任务调度服务,只是处理的对象是消息而不是任务,常见使用场景有以下几种:

  • 在购物平台下单,超时未成功付款,订单进行自动取消
  • 打车时,规定时间内没有车主接单,订单进行自动取消

实现方案

  1. 在redis中可以使用有序集合(ZSet)来实现延迟消息队列,ZSet有一个Score属性可以用来存储延迟执行的时间。
  2. 使用zadd score1 value1命令就可以一直往内存中生产消息,再利用zrangebyscore查询复合条件的所有待处理的任务,通过循环执行队列任务即可。

存在问题

3. 消息队列

常见消息队列选型Kafka、RocketMQ等服务相对Redis比较重,对于一些简单的,没有大量消息堆积的非关键业务场景可以使用Redis来实现消息队列。

Redis中可以使用List、Stream、Pub/Sub 来实现简单的消息队列

List实现MQ

Redis队列是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)。通过使用以下命令,可以实现一个简单的消息队列功能:

  • LPUSH、RPOP 左进右出
  • RPUSH、LPOP 右进左出

使用RPOP、LPOP命令消费数据时有个问题就是需要消费者轮询Redis,所以可以使用BRPOP、BLPOP避免这个问题。

实现ACK机制

Redis中可以使用双队列来实现ACK机制,步骤如下:

  • 准备两个队列,其中存储数据的队列为queue1,另一个队列名为queue1_bak
  • 消费者使用RPOPLPUSHBRPOPLPUSH命令消费数据(数据在弹出的同时将备份到另一个 bak 队列)
  • 消费者消费数据成功后,使用LREM命令消费 bak 队列的数据
  • 启用定时任务,使用LRANGE命令读取队列数据,解析每条数据(需要包含产生时间戳),将超市消息(认为消费失败)重新入队queue1
    • 超时定义:因为使用redis的队列场景一般不存在大量消息堆积,所以可以简单定一个时间
    • 因为这里的超时定义不严谨,所以建议消息中包含唯一ID实现幂等消费,否则可能会重新消费

Stream实现MQ

Stream是Redis5.0引入的一种专门为消息队列设计的数据结构,Stream是一个包含0个或者多个元素的有序队列,这些元素根据ID的大小进行有序排列,它实现了大部分消息队列的功能:

  • 消息ID序列化生成
  • 消息遍历
  • 消息的阻塞和非阻塞读
  • Consumer Groups(消费组)
    • 消费组的目的是通过多个消费者同时消费一个队列,实现负载均衡和容错
    • 通过XGROUP / XREADGROUP / XACK实现消费组功能
  • ACK确认机制
  • 支持多播
  • 提供了很多消息队列操作命令
  • 提供了消息持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失

参考

发布订阅实现MQ

TIP

严格来说,“发布订阅”只是一个广播机制,而不是真正的消息队列,因为不支持消息累积,从而无法实现MQ必备的异步通信功能。

Redis通过PUBLISHSUBSCRIBE 等命令实现了订阅与发布模式,这个功能提供两种信息机制,分别是订阅 / 发布到频道和订阅 / 发布 到模式(一个类似正则表达式的key)

订阅 / 发布模式包含两种角色,分别是发布者和订阅者,订阅者可以订阅一个或多个channel,而发布者可以向指定的channel发送消息,所有订阅此频道的订阅者都会收到此消息

缺点
由于Redis不会存储消息,所以只有在线的订阅者可以实时接收消息,并且没有ACK机制,离线订阅者会永远丢失消息