我在生产项目里是如何使用Redis发布订阅的?(一)使用场景

转载请注明出处!html

导语redis

Redis是咱们很经常使用的一款nosql数据库产品,咱们一般会用Redis来配合关系型数据库一块儿使用,弥补关系型数据库的不足。sql

其中,Redis的发布订阅功能也是它的一大亮点。虽然它不是一款专门作发布订阅的产品,但其自带的发布订阅功能已经知足咱们平常需求了。数据库

那Redis的发布订阅功能均可以用在哪些场景呢?我在生产项目里又是如何使用Redis发布订阅的?今天咱们就来探讨一下这个问题。编程

 

什么是发布订阅缓存

所谓发布订阅,就是消息发布者发布消息及消息订阅者接收消息,两者经过某种媒介关联起来。这相似之前的『订报』,当咱们订阅了某种报纸后(好比财经报),每当报纸有新的期刊出版后,就会有邮递员给咱们送过来。即,只有定了这种报纸才会收到出版社发布的这种新报纸。app

 

Redis的发布订阅功能也是相似,首先要有消息的发布者,其次要有消息的订阅者。有了消息发布者和订阅者以后,还缺乏什么?异步

 

那就是上述的『某种报纸』,并非出版社出版的每一种报纸(如人民日报,财经报,体育报)都给你送过来,而是明确你要定哪种,你定了哪种才给你送哪种。nosql

 

回到Redis的发布订阅上,上述的『某种报纸』就抽象为频道channel,客户端订阅了某channel后,当发布者经过此channel发布消息时,全部订阅者就会收到该频道发布的消息。url

发布和订阅机制

当一个客户端经过 PUBLISH 命令向订阅者发送信息的时候,咱们称这个客户端为发布者(publisher)。

而当一个客户端使用 SUBSCRIBE 或者 PSUBSCRIBE命令接收信息的时候,咱们称这个客户端为订阅者(subscriber)。

为了解耦发布者(publisher)和订阅者(subscriber)之间的关系,Redis 使用了 channel (频道)做为二者的中介 —— 发布者将信息直接发布给 channel ,而 channel 负责将信息发送给适当的订阅者,发布者和订阅者之间没有相互关系,也不知道对方的存在。

 

如上图所示,`Redis client A` 和 `Redis client B` 订阅了 `channel`-> `Financial newspapers`,当 `Redis client C`经过  `channel`->`Financial newspapers` 发布消息 `Stocks are up today!` 时,`Redis client A` 和 `Redis client B` 就会收到该消息。

 

原理

Redis是使用C实现的,经过分析 Redis 源码里的 pubsub.c 文件,了解发布和订阅机制的底层实现,籍此加深对 Redis 的理解。

 

Redis 经过 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能。

经过 SUBSCRIBE 命令订阅某频道后,redis-server 里维护了一个字典,字典的键就是一个个 channel ,而字典的值则是一个链表,链表中保存了全部订阅这个 channel 的客户端。SUBSCRIBE 命令的关键,就是将客户端添加到给定 channel 的订阅链表中。

经过 PUBLISH 命令向订阅者发送消息,redis-server 会使用给定的频道做为键,在它所维护的 channel 字典中查找记录了订阅这个频道的全部客户端的链表,遍历这个链表,将消息发布给全部订阅者。

发布订阅的原理详细参考:https://www.cnblogs.com/duanxz/p/6053520.html

 

我在哪些业务场景使用Redis发布订阅?

明确了Redis发布订阅的原理和基本流程后,咱们来看一下Redis的发布订阅到底具体能作什么。

一、异步消息通知

好比渠道在调支付平台的时候,咱们能够用回调的方式给支付平台一个咱们的回调接口来通知咱们支付状态,还能够利用Redis的发布订阅来实现。好比咱们发起支付的同时订阅频道`pay_notice_` + `wk` (假如咱们的渠道标识是wk,不能让其余渠道也订阅这个频道),当支付平台处理完成后,支付平台往该频道发布消息,告诉频道的订阅者该订单的支付信息及状态。收到消息后,根据消息内容更新订单信息及后续操做。 

当不少人都调用支付平台时,支付时都去订阅同一个频道会有问题。好比用户A支付完订阅频道`pay_notice_wk`,在支付平台未处理完时,用户B支付完也订阅了`pay_notice_wk`,当A收到通知后,接着B的支付通知也发布了,这时渠道收不到第二次消息发布。由于同一个频道收到消息后,订阅自动取消,也就是订阅是一次性的。

因此咱们订阅的订单支付状态的频道就得惟一,一个订单一个频道,咱们能够在频道上加上订单号`pay_notice_wk`+orderNo保证频道惟一。这样咱们能够把频道号在支付时当作参数一并传过去,支付平台处理完就能够用此频道发布消息给咱们了。(实际大多接口用回调通知,由于用Redis发布订阅限制条件苛刻,系统间必须共用一套Redis)

二、任务通知

 

好比经过跑批系统通知应用系统作一些事(跑批系统没法拿到用户数据,且应用系统又不能作定时任务的状况下)。

如天天凌晨3点提早加载一些用户的用户数据到Redis,应用系统不能作定时任务,能够经过系统公共的Redis来由跑批系统发布任务给应用系统,应用系统收到指令,去作相应的操做。

这里须要注意的是在线上集群部署的状况下,全部服务实例都会收到通知,都要作一样的操做吗?彻底不必。能够用Redis实现锁机制,其中一台实例拿到锁后执行任务。另外若是任务比较耗时,能够不用锁,能够考虑一下任务分片执行。固然这不在本文的讨论范畴,这里不在赘述。

 

三、参数刷新加载

 

众所周知,咱们用Redis无非就是将系统中不怎么变的、查询又比较频繁的数据缓存起来,例如咱们系统首页的轮播图啊,页面的动态连接啊,一些系统参数啊,公共数据啊都加载到Redis,而后有个后台管理系统去配置修改这些数据。

 

打个比方咱们首页的轮播图要再增长一个图,那咱们就在后管系统加上,加上就完事了吗?固然没有,由于Redis里仍是老数据。那你会说不是有过时时间吗?是的,但有的过时时间设置的较长如24小时而且咱们想当即生效怎么办?这时候咱们就能够利用Redis的发布订阅机制来实现数据的实时刷新。当咱们修改完数据后,点击刷新按钮,经过发布订阅机制,订阅者接收到消息后调用从新加载的方法便可。

 


关于发布订阅的JAVA版源码实现,因为篇幅缘由将会在下篇文章分享

[end]

文章首发于公众号@编程大道

相关文章
相关标签/搜索