Redis实现消息队列

时间:2021-04-04 17:40:58

1. Redis实现消息队列有两种方式

Redis能做消息队列得益于他list对象blpop/brpop接口以及Pub/Sub(发布/订阅)的某些接口。他们都是阻塞版的,所以Redis实现消息队列有两种方式:

  • 通过数据结构list来实现
  • 通过pub/sub来实现

另外redis存放的数据都只能是string类型,所以在任务传递的时候只能是传递字符串。我们可以将消息在发布者序列化成json格式的字符串,然后消费者那边再转换一下即可。

2. 通过数据结构list来实现

2.1 实现机制

消息接收:
redis> brpop tasklist 0
“im task 01”
这个例子使用blpop命令会阻塞方式地从tasklist列表中取头一个数据,最后一个参数就是等待超时的时间。如果设置为0则表示无限等待。

消息发送:
redis> lpush tasklist ‘im task 01’
redis> lpush tasklist ‘im task 02’

2.2 优点

  • 能够实现持久化
    采用 Master-Slave 数据复制模式。队列操作都是写操作,Master任务繁重,能让Slave分担的持久化工作,就不要Master做。RDB和AOF两种方法都用上,多重保险。
  • 支持集群
  • 接口使用简单

2.3 不足

  • Redis上消息只会被一个消费者消费,不会有多个订阅者消费同一个消息,简单一对一
  • 生产者或者消费者崩溃后的处理机制,需要自己实现
  • 生产者写入太快,消费者消费太慢,导致Redis的内存问题,处理机制需要自己实现

2.4 应用场景

3. 通过pub/sub来实现

3.1 实现机制

订阅,取消订阅和发布实现了发布/订阅消息范式,发布者不是计划发送消息给特定的订阅者。而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅。订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的。
这是一种基于非持久化的消息机制,消息发布者和订阅者必须同时在线,否则一旦消息订阅者由于各种异常情况而*断开连接,在其重新连接后,其离线期间的消息是无法被重新通知的(即发即弃)。

Redis中的消息可以提供两种不同的功能。一类是基于Channel的消息,这一类消息和Redis中存储的Keys没有太多关联,也就是说即使不在Redis中存储任何Keys信息,这类消息也可以独立使用。另一类消息可以对(也可以不对)Redis中存储的Keys信息的变化事件进行通知,可以用来向订阅者通知Redis中符合订阅条件的Keys的各种事件。

3.2 优点

  • 一个生产者能够对应多个消费者
  • 支持集群
  • 接口使用简单

3.3 不足

Redis提供的订阅/发布功能并不完美,更不能和ActiveMQ/RabbitMQ提供的订阅/发布功能相提并论。

首先这些消息并没有持久化机制,属于即发即弃模式。也就是说它们不能像ActiveMQ中的消息那样保证持久化消息订阅者不会错过任何消息,无论这些消息订阅者是否随时在线。

  • 由于本来就是即发即弃的消息模式,所以Redis也不需要专门制定消息的备份和恢复机制。
  • 也是由于即发即弃的消息模式,所以Redis也没有必要专门对使用订阅/发布功能的客户端连接进行识别,用来明确该客户端连接的ID是否在之前已经连接过Redis服务了。ActiveMQ中保持持续通知的功能的前提,就是能够识别客户端连接ID的历史连接情况,以便确定哪些订阅消息这个客户端还没有处理。
  • Redis也没有为发布者和订阅者准备保证消息性能的任何方案,例如在大量消息同时到达Redis服务是,如果消息订阅者来不及完成消费,就可能导致消息堆积。而ActiveMQ中有专门针对这种情况的慢消息机制。

3.4 应用场景:未知

参考资料

Redis官网
架构设计:系统存储(16)——Redis事件订阅和持久化存储
Java中使用Jedis操作Redis
Redis笔记(七)Java实现Redis消息队列
Redis编程实践【pub/sub】
用redis实现支持优先级的消息队列
java redis使用之利用jedis实现redis消息队列
基于Redis实现分布式消息队列