Redis 实现发布订阅
目录
发布订阅(pub/sub)是一种消息通信模式,本质是实现队列(先进先出)的远程操作功能。
使用 redis 实现发布订阅有 3 种方式:
- 使用列表(list)数据结构,通过 lpush、rpop(brpop)实现队列先进先出
- 使用 redis 发布/订阅功能
- 使用 redis 5.0 stream 数据结构(功能)
结论:虽然 redis 可以作为消息队列,但是严谨的生产环境还是应该选择专业的 MQ,因为可靠性是软件的基石。
1、使用列表(list)数据结构实现
利用 list 数据结构的特性,实现队列的先进先出。
lpush
向 list 左边添加元素,rpop
从 list 右边取出元素。brpop
可以以阻塞的方式从 list 头部取出元素。
优缺点
优点:实现简单,方便接入
缺点:
- 不支持多播(一发多收)
- 如果消费者消费速度跟不上生产者生产的速度,队列会一直增长,时间久了可能发生 OOM
2、redis 发布/订阅功能
redis 发布/订阅是 MQ 功能的简单实现,没有基于任何数据类型实现,所以它也不具备「数据持久化」的能力。
也就是说,Pub/Sub 的相关操作,不会写入到 RDB 和 AOF 中,当 Redis 宕机重启,Pub/Sub 的数据也会全部丢失。
命令有:
- publish – 发布
- subscribe(psubscribe)– 订阅
- unsubscribe(punsubscribe)– 取消订阅
redis 发布/订阅有两种模式:
- 基于频道(Channel)的发布/订阅
- 基于模式(pattern)的发布/订阅
优缺点
优点:实现简单,支持多播
缺点:
- 无法持久化保存消息,如果 redis 服务器宕机或重启,那么所有的消息将会丢失;客户端必须一直在线才能收到消息
- 发布订阅模式是“发后既忘”的工作模式,如果有订阅者离线重连之后不能消费之前的历史消息。
3、redis 5.0 stream
stream 出现是为了给 redis 提供完善的消息队列功能。
stream 是新增加的数据类型,它与其它数据类型一样,每个写操作,也都会写入到 RDB 和 AOF 中。
虽然 stream 是完整功能的消息队列,但是受限于内存和 RDB 落盘时间(间隔 1 秒刷一次盘),redis 本身的无法保证严格的数据完整性。
3.1 总结
综上可以看到,把 redis 当作队列来使用时,始终面临两个问题:
- redis 本身可能会丢数据
- 面对消息积压,redis 内存资源紧张
3.2 优缺点
优点:使用成本低。几乎每一个项目都会使用 redis,用 stream 做消息队列就不需要额外引入中间件了,减少了系统复杂性,运维成本。
缺点:
- redis 的数据结构存储在内存,内存持续增长超过机器内存上限,就会面临 OOM 的风险
- stream 作为 redis 的一种数据结构,redis 在持久化或者主从切换时有丢失数据的风险,所有 stream 也有丢失消息的风险
- 所有的消息会一直保存在 stream 中,没有删除机制。要么定时清除,要没设置队列长度自动丢弃先入队列的消息
3.3 应用场景
适用场景:
- 场景足够简单
- 对于数据丢失不敏感
- 消息积压概率小
不适用场景:
- 对于数据丢失非常敏感,如订单系统
- 写入量非常大,并发请求大,如日志系统
- 消息积压时会占用很多内存,消息数量大