文章目录redis消息队列生产者/消费者模式发布者/订阅者模式redis消息队列消息队列把要传输的数据放在队列中从而实现应用之间的数据交换。常用功能可以实现多个应用系统之间的解耦异步削峰/限流等。常用的消息队列应用Kafka, RabbitMQ, Redis消息队列分为两种生产者/消费者模式Producer/Consumer发布者/订阅者模式Publisher/Subscriber生产者/消费者模式生产者消费者模式下多个消费者同时监听一个频道redis 用队列实现但是生产者产生的一个消息只能被最先抢到消息的一个消费者消费一次队列中的消息可以由多个生产者写入也可以有不同的消费者取出进行消费处理此模式应用广泛。思来想去只有 List 和 Streams 两种数据类型可以实现消息队列的这些需求当然Redis 还提供了发布、订阅pub/sub模式。List 实现消息队列Redis 列表是简单的字符串列表按照插入顺序排序。你可以添加一个元素到列表的头部左边或者尾部右边。所以常用来做异步队列使用。将需要延后处理的任务结构体序列化成字符串塞进 Redis 的列表另一个线程从这个列表中轮询数据进行处理。挑几个弹入、弹出的命令就可以组合出很多姿势LPUSH、RPOP左进右出RPUSH、LPOP右进左出案例# 生产者生成消息redis-cli 为在 shell 中启动的 Redis 命令行客户端进入交互式连接本机 6379 端口的 Redis 服务[rootlocalhost ~]# redis-cli# LPUSH haizeiwang jishu1haizeiwang 为消息队列列表键名LPUSH 从左端写入消息作为生产端生产一条消息127.0.0.1:6379LPUSH haizeiwang jishu1# LPUSH 生产者从左边写入消息(integer)1# 写入成功队列当前积压 1 条消息# LPUSH haizeiwang jishu2haizeiwang 为队列键名从左端生产第 2 条消息 jishu2127.0.0.1:6379LPUSH haizeiwang jishu2(integer)2# 写入成功队列当前积压 2 条消息# LPUSH haizeiwang jishu3haizeiwang 为队列键名从左端生产第 3 条消息 jishu3127.0.0.1:6379LPUSH haizeiwang jishu3(integer)3# 写入成功队列当前积压 3 条消息# LPUSH haizeiwang jishu4haizeiwang 为队列键名从左端生产第 4 条消息 jishu4127.0.0.1:6379LPUSH haizeiwang jishu4(integer)4# 写入成功队列当前积压 4 条消息# LPUSH haizeiwang jishu5haizeiwang 为队列键名从左端生产第 5 条消息 jishu5127.0.0.1:6379LPUSH haizeiwang jishu5(integer)5# 写入成功队列当前积压 5 条消息# 获取所有消息LRANGE haizeiwang 0 -1 中 haizeiwang 为队列键名0 到 -1 查看队列全部消息LPUSH 从左写故 jishu5 在表头127.0.0.1:6379LRANGE haizeiwang0-11)jishu5# 队列中全部消息表头为最后写入的 jishu52)jishu43)jishu34)jishu25)jishu1# 消费者消费消息RPOP haizeiwang 中 haizeiwang 为队列键名RPOP 从右端弹出并移除消息右端是最早写入的 jishu1实现先进先出127.0.0.1:6379RPOP haizeiwang# RPOP 消费者从右边弹出消息基于先进先出原则jishu1# 被消费弹出的最早一条消息# RPOP haizeiwanghaizeiwang 为队列键名从右端继续弹出下一条消息消费127.0.0.1:6379RPOP haizeiwangjishu2# 被消费的第 2 条消息# RPOP haizeiwanghaizeiwang 为队列键名从右端继续弹出下一条消息消费127.0.0.1:6379RPOP haizeiwangjishu3# 被消费的第 3 条消息# RPOP haizeiwanghaizeiwang 为队列键名从右端继续弹出下一条消息消费127.0.0.1:6379RPOP haizeiwangjishu4# 被消费的第 4 条消息# RPOP haizeiwanghaizeiwang 为队列键名从右端弹出最后一条消息消费127.0.0.1:6379RPOP haizeiwangjishu5# 被消费的第 5 条最后一条消息# RPOP haizeiwanghaizeiwang 为队列键名队列已空再弹出时没有消息可返回127.0.0.1:6379RPOP haizeiwang# 验证队列消息消费全部消费完成(nil)# 队列已空返回 nil 表示无消息可消费# LRANGE haizeiwang 0 -1haizeiwang 为队列键名查看消费完毕后队列中的剩余消息127.0.0.1:6379LRANGE haizeiwang0-1(empty list orset)# 队列已清空返回空列表# 生产者生成消息LPUSH haizeiwang jishu1 jishu2 jishu3 jishu4 jishu5 中 haizeiwang 为队列键名一次从左端批量写入 5 条消息127.0.0.1:6379LPUSH haizeiwang jishu1 jishu2 jishu3 jishu4 jishu5# LPUSH 批量写入消息(integer)5# 批量写入成功队列当前积压 5 条消息# 获取所有消息LRANGE haizeiwang 0 -1 中 haizeiwang 为队列键名0 到 -1 查看批量写入后队列的全部消息127.0.0.1:6379LRANGE haizeiwang0-11)jishu5# 批量写入后队列中的全部消息2)jishu43)jishu34)jishu25)jishu1即时消费问题通过 LPUSH、RPOP 这样的方式会存在一个性能风险点就是消费者如果想要及时的处理数据就要在程序中写个类似 while(true) 这样的逻辑不停的去调用 RPOP 或 LPOP 命令这就会给消费者程序带来些不必要的性能损失。所以Redis 还提供了 BLPOP、BRPOP 这种阻塞式读取的命令带 B-Blocking 的都是阻塞式客户端在没有读到队列数据时自动阻塞直到有新的数据写入队列再开始读取新数据。这种方式就节省了不必要的 CPU 开销。LPUSH、BRPOP左进右阻塞出RPUSH、BLPOP右进左阻塞出# 消费者消费消息BRPOP haizeiwang 10 中 haizeiwang 为队列键名10 为阻塞超时秒数BRPOP 阻塞式从右端弹出消息队列空时最多等 10 秒有消息则立即返回127.0.0.1:6379BRPOP haizeiwang10# BRPOP 阻塞式右弹出等待 10 秒有消息则立即返回1)haizeiwang# 返回两个元素第 1 个是弹出消息所在的队列名第 2 个是消息内容2)jishu1# BRPOP haizeiwang 10haizeiwang 为队列键名10 为超时秒数继续阻塞式从右端弹出下一条消息127.0.0.1:6379BRPOP haizeiwang101)haizeiwang# 弹出结果队列名 消息内容2)jishu2# BRPOP haizeiwang 10haizeiwang 为队列键名10 为超时秒数继续阻塞式从右端弹出下一条消息127.0.0.1:6379BRPOP haizeiwang101)haizeiwang# 弹出结果队列名 消息内容2)jishu3# BRPOP haizeiwang 10haizeiwang 为队列键名10 为超时秒数继续阻塞式从右端弹出下一条消息127.0.0.1:6379BRPOP haizeiwang101)haizeiwang# 弹出结果队列名 消息内容2)jishu4# BRPOP haizeiwang 10haizeiwang 为队列键名10 为超时秒数继续阻塞式从右端弹出下一条消息127.0.0.1:6379BRPOP haizeiwang101)haizeiwang# 弹出结果队列名 消息内容2)jishu5# 消费的时候已经没有消息了10 秒内再开一个窗口使用命令 LPUSH haizeiwang jishu6 产生新消息BRPOP haizeiwang 10 中 haizeiwang 为队列键名10 为阻塞超时秒数队列暂时为空时阻塞等待直到新消息 jishu6 写入后立即弹出127.0.0.1:6379BRPOP haizeiwang10# 如果将超时时间设置为 0 时即可无限等待直到弹出消息1)haizeiwang# 阻塞等待后弹出队列名 消息内容2)jishu6(2.73s)# 本次阻塞等待耗时约 2.73 秒后才收到消息发布者/订阅者模式在发布者订阅者 Publisher/Subscriber 模式下发布者 Publisher 将消息发布到指定的频道 channel事先监听此 channel 的一个或多个订阅者 Subscriber 都会收到相同的消息。即一个消息可以由多个订阅者获取到对于社交应用中的群聊、群发、群公告等场景适用于此模式。案例# 订阅者订阅频道# 窗口 Aredis-cli 启动Redis命令行客户端默认连接本机127.0.0.1:6379[rootlocalhost ~]# redis-cli127.0.0.1:6379SUBSCRIBE douluodalu# SUBSCRIBE channel订阅者事先订阅指定的频道之后发布的消息才能收到douluodalu为要订阅的频道名Reading messages...(press Ctrl-C to quit)1)subscribe2)douluodalu3)(integer)1# 窗口 Bredis-cli 另开一个终端窗口同样连接本机Redis[rootlocalhost ~]# redis-cli127.0.0.1:6379SUBSCRIBE douluodalu haizeiwang# 订阅多个频道Reading messages...(press Ctrl-C to quit)1)subscribe2)douluodalu3)(integer)11)subscribe2)haizeiwang3)(integer)2# 发布者发布消息# 窗口 C127.0.0.1:6379PUBLISH douluodalu fuhuoba,wodeairen# PUBLISH channel message发布者向频道发布消息douluodalu为目标频道fuhuoba,wodeairen为消息内容(integer)2# 订阅者个数 2 个127.0.0.1:6379PUBLISH haizeiwang 5danglufei# PUBLISH 发布消息到 haizeiwang 频道haizeiwang为频道名5danglufei为消息内容(integer)1# 各个订阅者都能收到消息# 窗口 Aredis-cli 切回窗口A观察订阅者是否收到推送[rootlocalhost ~]# redis-cli127.0.0.1:6379SUBSCRIBE douluodalu Reading messages...(press Ctrl-C to quit)1)subscribe2)douluodalu3)(integer)11)message2)douluodalu3)fuhuoba,wodeairen# 窗口 Bredis-cli 切回窗口B观察两个订阅频道是否都收到消息[rootlocalhost ~]# redis-cli127.0.0.1:6379SUBSCRIBE douluodalu haizeiwang Reading messages...(press Ctrl-C to quit)1)subscribe2)douluodalu3)(integer)11)subscribe2)haizeiwang3)(integer)21)message2)douluodalu3)fuhuoba,wodeairen1)message2)haizeiwang3)5danglufei# 订阅所有频道PSUBSCRIBE 模式订阅*为通配符模式可匹配任意名称的频道127.0.0.1:6379PSUBSCRIBE *# 订阅匹配的频道PSUBSCRIBE pattern如 douluo* 匹配 douluodaludouluo*为带通配符的模式只订阅前缀为douluo的频道127.0.0.1:6379PSUBSCRIBE douluo*