Redis 实现发布订阅

目录

发布订阅(pub/sub)是一种消息通信模式,本质是实现队列(先进先出)的远程操作功能。

使用 redis 实现发布订阅有 3 种方式:

  1. 使用列表(list)数据结构,通过 lpush、rpop(brpop)实现队列先进先出
  2. 使用 redis 发布/订阅功能
  3. 使用 redis 5.0 stream 数据结构(功能)

结论:虽然 redis 可以作为消息队列,但是严谨的生产环境还是应该选择专业的 MQ,因为可靠性是软件的基石。

1、使用列表(list)数据结构实现

利用 list 数据结构的特性,实现队列的先进先出。

lpush 向 list 左边添加元素,rpop 从 list 右边取出元素。brpop 可以以阻塞的方式从 list 头部取出元素。

优缺点

优点:实现简单,方便接入

缺点:

  1. 不支持多播(一发多收)
  2. 如果消费者消费速度跟不上生产者生产的速度,队列会一直增长,时间久了可能发生 OOM

2、redis 发布/订阅功能

redis 发布/订阅是 MQ 功能的简单实现,没有基于任何数据类型实现,所以它也不具备「数据持久化」的能力。

也就是说,Pub/Sub 的相关操作,不会写入到 RDB 和 AOF 中,当 Redis 宕机重启,Pub/Sub 的数据也会全部丢失。

命令有:

  • publish – 发布
  • subscribe(psubscribe)– 订阅
  • unsubscribe(punsubscribe)– 取消订阅

redis 发布/订阅有两种模式:

  1. 基于频道(Channel)的发布/订阅
  2. 基于模式(pattern)的发布/订阅

优缺点

优点:实现简单,支持多播

缺点:

  1. 无法持久化保存消息,如果 redis 服务器宕机或重启,那么所有的消息将会丢失;客户端必须一直在线才能收到消息
  2. 发布订阅模式是“发后既忘”的工作模式,如果有订阅者离线重连之后不能消费之前的历史消息。

3、redis 5.0 stream

stream 出现是为了给 redis 提供完善的消息队列功能。

stream 是新增加的数据类型,它与其它数据类型一样,每个写操作,也都会写入到 RDB 和 AOF 中。

虽然 stream 是完整功能的消息队列,但是受限于内存和 RDB 落盘时间(间隔 1 秒刷一次盘),redis 本身的无法保证严格的数据完整性。

3.1 总结

综上可以看到,把 redis 当作队列来使用时,始终面临两个问题:

  • redis 本身可能会丢数据
  • 面对消息积压,redis 内存资源紧张

3.2 优缺点

优点:使用成本低。几乎每一个项目都会使用 redis,用 stream 做消息队列就不需要额外引入中间件了,减少了系统复杂性,运维成本。

缺点:

  1. redis 的数据结构存储在内存,内存持续增长超过机器内存上限,就会面临 OOM 的风险
  2. stream 作为 redis 的一种数据结构,redis 在持久化或者主从切换时有丢失数据的风险,所有 stream 也有丢失消息的风险
  3. 所有的消息会一直保存在 stream 中,没有删除机制。要么定时清除,要没设置队列长度自动丢弃先入队列的消息

3.3 应用场景

适用场景:

  1. 场景足够简单
  2. 对于数据丢失不敏感
  3. 消息积压概率小

不适用场景:

  1. 对于数据丢失非常敏感,如订单系统
  2. 写入量非常大,并发请求大,如日志系统
  3. 消息积压时会占用很多内存,消息数量大