我在生产项目里是如何使用Redis发布订阅的?(一)使用场景
转载请注明出处!
导语
Redis是我们很常用的一款nosql数据库产品,我们通常会用Redis来配合关系型数据库一起使用,弥补关系型数据库的不足。
其中,Redis的发布订阅功能也是它的一大亮点。虽然它不是一款专门做发布订阅的产品,但其自带的发布订阅功能已经满足我们日常需求了。
那Redis的发布订阅功能都可以用在哪些场景呢?我在生产项目里又是如何使用Redis发布订阅的?今天我们就来探讨一下这个问题。
什么是发布订阅
所谓发布订阅,就是消息发布者发布消息及消息订阅者接收消息,二者通过某种媒介关联起来。这类似以前的『订报』,当我们订阅了某种报纸后(比如财经报),每当报纸有新的期刊出版后,就会有邮递员给我们送过来。即,只有定了这种报纸才会收到出版社发布的这种新报纸。
Redis的发布订阅功能也是类似,首先要有消息的发布者,其次要有消息的订阅者。有了消息发布者和订阅者之后,还缺少什么?
那就是上述的『某种报纸』,并不是出版社出版的每一种报纸(如人民日报,财经报,体育报)都给你送过来,而是明确你要定哪一种,你定了哪一种才给你送哪一种。
回到Redis的发布订阅上,上述的『某种报纸』就抽象为频道channel,客户端订阅了某channel后,当发布者通过此channel发布消息时,所有订阅者就会收到该频道发布的消息。
发布和订阅机制
当一个客户端通过 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的发布订阅到底具体能做什么。
1、异步消息通知
比如渠道在调支付平台的时候,我们可以用回调的方式给支付平台一个我们的回调接口来通知我们支付状态,还可以利用Redis的发布订阅来实现。比如我们发起支付的同时订阅频道`pay_notice_` + `wk` (假如我们的渠道标识是wk,不能让其他渠道也订阅这个频道),当支付平台处理完成后,支付平台往该频道发布消息,告诉频道的订阅者该订单的支付信息及状态。收到消息后,根据消息内容更新订单信息及后续操作。
当很多人都调用支付平台时,支付时都去订阅同一个频道会有问题。比如用户A支付完订阅频道`pay_notice_wk`,在支付平台未处理完时,用户B支付完也订阅了`pay_notice_wk`,当A收到通知后,接着B的支付通知也发布了,这时渠道收不到第二次消息发布。因为同一个频道收到消息后,订阅自动取消,也就是订阅是一次性的。
所以我们订阅的订单支付状态的频道就得唯一,一个订单一个频道,我们可以在频道上加上订单号`pay_notice_wk`+orderNo保证频道唯一。这样我们可以把频道号在支付时当做参数一并传过去,支付平台处理完就可以用此频道发布消息给我们了。(实际大多接口用回调通知,因为用Redis发布订阅限制条件苛刻,系统间必须共用一套Redis)

2、任务通知
比如通过跑批系统通知应用系统做一些事(跑批系统无法拿到用户数据,且应用系统又不能做定时任务的情况下)。
如每天凌晨3点提前加载一些用户的用户数据到Redis,应用系统不能做定时任务,可以通过系统公共的Redis来由跑批系统发布任务给应用系统,应用系统收到指令,去做相应的操作。

这里需要注意的是在线上集群部署的情况下,所有服务实例都会收到通知,都要做同样的操作吗?完全没必要。可以用Redis实现锁机制,其中一台实例拿到锁后执行任务。另外如果任务比较耗时,可以不用锁,可以考虑一下任务分片执行。当然这不在本文的讨论范畴,这里不在赘述。
3、参数刷新加载
众所周知,我们用Redis无非就是将系统中不怎么变的、查询又比较频繁的数据缓存起来,例如我们系统首页的轮播图啊,页面的动态链接啊,一些系统参数啊,公共数据啊都加载到Redis,然后有个后台管理系统去配置修改这些数据。
打个比方我们首页的轮播图要再增加一个图,那我们就在后管系统加上,加上就完事了吗?当然没有,因为Redis里还是老数据。那你会说不是有过期时间吗?是的,但有的过期时间设置的较长如24小时并且我们想立即生效怎么办?这时候我们就可以利用Redis的发布订阅机制来实现数据的实时刷新。当我们修改完数据后,点击刷新按钮,通过发布订阅机制,订阅者接收到消息后调用重新加载的方法即可。

关于发布订阅的JAVA版源码实现,由于篇幅原因将会在下篇文章分享
[end]
文章首发于公众号@编程大道

我在生产项目里是如何使用Redis发布订阅的?(一)使用场景的更多相关文章
- 我在生产项目里是如何使用Redis发布订阅的?(二)Java版代码实现(含源码)
上篇文章讲了在实际项目里的哪些业务场景用到Redis发布订阅,这篇文章就讲一下,在Java中如何实现的. 图解代码结构 发布订阅的理论以及使用场景大家都已经有了大致了解了,但是怎么用代码实现发布订阅呢 ...
- Nodejs开源项目里怎么样写测试、CI和代码测试覆盖率
测试 目前主流的就bdd和tdd,自己查一下差异 推荐 mocha和tape 另外Jasmine也挺有名,angularjs用它,不过挺麻烦的,还有一个选择是qunit,最初是为jquery测试写的, ...
- 如何把Spring制作成jar包,然后在项目里运行。
第一步:首先我们先把Spring的代码准备好.如图一 (图1). 第二步:我们在桌面新建一个文件夹,如图二 (图2). 我们要在这个文件夹里新建两个夹,一个文件夹是你项目的包名,也就是我们图1的aop ...
- ANDROID STDUIO 项目里的R文件突然丢失的解决办法N种之一
刚刚项目里的R文件突然挂了,清理项目,关闭重开Studio,都不能解决.快没折了. 然后只好在项目上右击,看看有没有解决的办法.发现有个 Make Module ,姑且试试吧. 结果,竟然修复了.这是 ...
- 在asp.net mvc4项目里bootstrap datetimepicker控件的使用
前段时间写了一篇关于调用阿里大于的短信接口来开发例会短信群发通知功能的文章http://www.cnblogs.com/zhouyuangan/p/apicall_1.html,其中的例会时间是需求中 ...
- 在Android Studio和Android Eclipse 更改现有项目里的SDK版本
一,在Eclipse下改项目里的SDK的版本方法有几种,都比较简单:1.右键单击项目--->properties---->Resource----->Android在Project ...
- 项目里的jquery.min.js错误
项目里的jquery.min.js报一系列 - Missing semicolon - Missing semicolon - Missing semicolon - Missing semicolo ...
- [Cordova] 无法编译Visual Studio项目里Plugin副本的Native Code
[Cordova] 无法编译Visual Studio项目里Plugin副本的Native Code 问题情景 开发Cordova Plugin的时候,开发的流程应该是: 建立Cordova Plug ...
- eclipse项目中关于导入的项目里提示HttpServletRequest 不能引用的解决办法
eclipse项目中关于导入的项目里提示HttpServletRequest 不能引用的解决办法 当使用eclipse导入外部的web工程时,有时会提示HttpServletRequest, Serv ...
随机推荐
- Python爬虫实践~BeautifulSoup+urllib+Flask实现静态网页的爬取
爬取的网站类型: 论坛类网站类型 涉及主要的第三方模块: BeautifulSoup:解析.遍历页面 urllib:处理URL请求 Flask:简易的WEB框架 介绍: 本次主要使用urllib获取网 ...
- MySql配置主从模式 Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
今天在学习MyCat环境搭建的时候,在配置MySql的主从模式,发现slave在配置完毕后,配置的内容全部正确的情况下,报错了? Last_IO_Error: Fatal error: The sla ...
- 致Python初学者的六点建议
Python是最容易学习的编程语言之一,其语法近似英语.通常,初学者只会遇到一些小麻烦,如强制缩进.在函数中使用self等. 然而,当开始阅读.复制和编辑他人代码时,麻烦就接踵而至了. 这里,我将解释 ...
- 从《华为的冬天》到AI的冬天 | 甲子光年
知难不难,惶者生存. 作者 | DougLong 编辑 | 火柴Q.甲小姐 *本文为甲子光年专栏作家DougLong独家稿件.作者为AI从业者.Gary Marcus<Rebooting AI& ...
- 024.微服务架构之服务注册与发现(kubernetes / SpringCloud)
微服务 微服务是一种架构模式,一种分布式的架构风格. 顾名思义,micro service,将一个庞大的单体应用拆分成若干个“微小”的服务,服务间通过进程通讯完成原本在单体应用中的调用. 其中必要的六 ...
- ORA-1562 and ORA-1650 Unable to Extend Rollback Segment (Doc ID 1066542.6)
ORA-1562 and ORA-1650 Unable to Extend Rollback Segment (Doc ID 1066542.6) APPLIES TO: Oracle Databa ...
- [PHP] CentOS下搭建下PHP的运行环境
在公司里面有分配的测试机,所有的开发代码都运行在测试机里面.因为公司的测试机机房退租,所以要在新申请的几台测试机上搭建开发环境.开发环境尽量做到和线上的环境一致,包括代码的目录路径,运行程序的进程用户 ...
- 关于如何刷新清除某个特定网站的缓存---基于Chrome浏览器
今天工作时又发现了一个小技巧 1.打开一个网站如:百度 2.打开F12开发者模式 3.右键浏览器的刷新按钮,会出现三个选项:正常重新加载,硬性重新加载,清空缓存并硬性重新加载 正常重新加载 Ctrl+ ...
- 网络流(3)——找到最小st-剪切
在大规模战争中,后勤补给是重中之重,为了尽最大可能满足前线的物资消耗,后勤部队必然要充分利用每条运输网.与此同时,交战双方也想要以最小的代价切断敌军的补给,从而使敌军处于孤立无援的境地.在古今中外的各 ...
- selenium python 脚本不支持中文问题
在 python shell 中执行以下脚本: ...... dr.find_element_by_xpath("//a[test()='查看']") ...... 点击 Run ...