Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua
开心一刻
我找了个女朋友,挺丑的那一种,她也知道自己丑,平常都不好意思和我一块出门
昨晚,我带她逛超市,听到有两个人在我们背后小声嘀咕:“看咱前面,想不到这么丑都有人要。”
女朋友听后,羞的满脸通红,我想女朋友虽然丑但是对我很好,我不会嫌弃她的
后面两个人继续嘀咕:“是啊,那男人真丑!”
卧槽,小丑竟是我自己!
写在前面
Redis 客户端
除了 Redis 自己提供的命令行工具:redis-cli,还有各种针对不同编程语言的客户端:Clients
Java 语言的 Redis 客户端有很多,推荐使用的有:Jedis、lettuce、Redisson,而 Redisson 就是本文的主角之一
环境准备
Redis 版本:3.2.8
Redisson 版本:3.13.6
下文都是基于这两个版本来进行讲解的;不同的版本,功能、特性还是有所不同的,这点还是需要注意的
Redis 的发布/订阅
官方文档:Redis Pub/Sub
什么是发布/订阅
Redis 提供了基于 “发布 / 订阅” 模式的消息机制,此种模式下,消息发布者和订阅者不进行直接通信,发布者向指定的频道发布消息,订阅该频道的每个客户端都可以收到该消息
发布订阅模型如下:
四个角色:发布者(Pub)、订阅者(Sub)、对两者解耦的中间方(Channel)、消息(Message)
Sub 订阅 Channel,Pub 向 Channel 发布消息(Message),Sub 就能收到 Pub 发布的消息了
以公众号为例,我们(Sub)订阅某个公众号(Channel),公众号作者(Pub)在公众号每发表一篇文章(Message),就会向我们推送这篇文章,我们就可以浏览这篇文章了
当我们取消订阅了,它就不会再向我们推送这篇文章了;只要这个公众号一直在运行,就会一直有人订阅它或者取消订阅
可以将发布/订阅理解成分布式版的观察者模式,关于观察者模式,大家可以查看:设计模式之观察者模式 → 事件机制的底层原理
很多的 MQ 产品中都存在发布/订阅模式,只是各自的实现有细微差别
Redis 中发布/订阅相关的命令只有 6 个,我们在 redis-cli 下一个一个来看
SUBSCRIBE
通过该命令,客户端可以订阅一个或多个频道
基本语法: subscribe channel [channel ...]
假设我们订阅频道:channel:1,可以如下操作
关于订阅命令(subscribe、psubscribe)有两点需要注意:
1、客户端在执行订阅命令后进入了订阅状态,只能接收 subscribe、psubscribe、unsubscribe、punsubscribe 这四个命令
在 redis-cli 下更是表现为阻塞状态,只能接收消息,不能输入任何命令
但是我们要明白,redis 客户端除了 redis-cli,还很多针对不同编程语言的客户端
实际应用中,redis-cli 用的非常少,用的多的还是各种编程语言的 Redis 客户端
2、新开启的订阅客户端,无法接收到该频道之前的消息,因为 Redis 不会持久化发布的消息
PUBLISH
通过该命令,客户端可以向某个频道发布一条消息
基本语法: publish channel message
假设我们向频道:channel:1 发布消息,可以如下操作
返回值: (integer) 1 表示有 1 个订阅者收到了消息
我们再看看之前的订阅客户端,收到了发布的消息
UNSUBSCRIBE
通过此命令,客户端可以取消对指定频道的订阅,取消成功后不再接收该频道发布的消息
基本语法: unsubscribe [channel [channel ...]]
我们取消对频道:channel:1 的订阅,可以如下操作
PSUBSCRIBE
按照模式订阅,可以理解成正则匹配订阅
subscribe 只能订阅一个或多个具体的频道,不能按正则匹配订阅,而此命令正好弥补这个空缺
基本语法: psubscribe pattern [pattern ...]
我们订阅以 channel:u 开头的所有频道,可以如下操作
此时,我们向频道:channel:user 发布消息,那么此客户端也能收到消息
PUNSUBSCRIBE
按照模式取消订阅,可以理解成正则匹配取消订阅
unsubscribe 只能对一个或多个具体的频道取消订阅,不能按正则匹配来取消订阅,而此命令正好弥补这个空缺
基本语法: punsubscribe [pattern [pattern ...]]
我们对 channel:r 开头的所有频道取消订阅,可以如下操作
我们可以将 psubscribe、punsubscribe 与 subscribe、unsubscribe 进行类比,便于理解
PUBSUB
该命令用于查看订阅与发布系统状态,它由数个不同格式的子命令组成
基本语法: pubsub subcommand [argument [argument ...]]
该命令用法比较灵活,常用的功能有如下几个
1、查看活跃的频道
活跃的频道指的是当前频道至少有一个订阅者
基本语法: pubsub channels [pattern] ,其中 [pattern] 是可以指定具体的模式
查看所有活跃的频道,可以如下操作
查看符合某种模式的活跃频道,可以如下操作
2、查看频道订阅数
基本语法: pubsub numsub [channel ...]
channel:1 频道的订阅数是 1,channel:user 频道的订阅数也是 1
3、查看模式订阅数
基本语法: pubsub numpat
返回的不是订阅模式的客户端的数量, 而是客户端订阅的所有模式的数量总和
Redisson 发布/订阅
上面讲了那么多,其实都是在 redis-cli 下自嗨,如何在实际项目中应用起来了,我们基于 Redisson 来实现个简单示例
订阅端
发布端
完整代码:pubsub,执行结果如下
至此,相信大家对 Redis 的发布/订阅有了一定的了解了
Redis 的 Lua
官方文档:Redis Lua scripting
关于 Lua,本文不作详细介绍;语法比较简单,基本都能看懂,感兴趣的可以去看它的官方文档:Lua Documentation
Redis 提供了一系列的命令供我们使用:Redis Commands,基本上能满足我们的绝大部分需求
但是,总有一些特殊的需求游离在三界之外,不在五行之中,不能通过其中的某个命令直接实现
有人可能就会说了:一个命令不行,那就多个命令组合实现嘛
但是,我们需要考虑到:多个命令组合能保证原子性吗,如果有逻辑处理又该怎么办?
Redis 早已替我们想好了解决办法,那就是:Lua 脚本
在 Redis 中执行 Lua 脚本有两种方法:eval 和 evalsha
eval
基本语法: eval script numkeys key [key ...] arg [arg ...]
其中 script 表示 Lua 脚本,numkeys 表示 key 个数
通过一个具体案例,我们就能理解了
其中表示 .. 表示连接两个字符串
如果 Lua 脚本太长,还可以使用 redis-cli --eval 直接执行文件
基本语法: redis-cli --eval script key [key...] , arg [arg ...]
注意:key 与 arg 之间是 , ,英文逗号前后都有一个空格
hello.lua 文件内容: return 'hello '..KEYS[1]..ARGV[1]
evalsha
除了 eval,Redis 还提供了 evalsha 来执行 Lua 脚本
基本语法: evalsha sha1 numkeys key [key ...] arg [arg ...]
使用 evalsha 之前需要将 Lua 脚本加载到 Redis 服务端,得到该脚本的 SHA1 校验和,然后将 SHA1 作为 evalsha 的入参执行对应的 Lua 脚本
脚本会常驻 Redis 服务端,客户端执行脚本时不需要每次都传递脚本到服务端,使得脚本得以复用,降低了参数传递的开销
加载脚本基本语法: redis-cli script load script
得到 SHA1: 5a8bcaa0ac71ab25ea5c504d61964859fffc20ce ,再执行 evalsha 命令
Lua 的 Redis API
Lua 可以使用 redis.call 函数实现对 Redis 命令的调用,例如:
另外还可以使用 redis.pcall 函数实现对 Redis 命令的调用
redis.call 和 redis.pcall 的区别在于,如果 redis.call 执行失败,那么脚本执行结束会直接返回错误,而 redis.pcall 会忽略错误继续执行脚本
Lua 带来的好处
Lua 为 Redis 开发和运维人员带来了如下三个好处:
1、Lua 脚本在 Redis 中是原子执行的,执行过程中不会插入其他命令
2、通过 Lua 脚本,我可以创造出自己定制的命令,并可以将这些命令常驻在内存,实现复用
3、Lua 脚本可以将多条命令一次性打包,有效减少网络开销
Redisson Lua
基于 Redisson,我们来看看 Lua 的简单使用
完整代码:LuaDemo,执行结果如下:
LuaDemo.java 中有个方法 distLockTest ,有兴趣的可以看看,对理解 Redisson 分布式锁的实现有帮助
细节疑问
给大家留两个问题
1、客户端未主动取消订阅,而是直接断开连接,Redis 服务端会如何处理该客户端订阅的那些频道
2、lua 脚本保证的是执行该脚本的过程中,不能有其他命令插入,但是如果脚本中的某个命令出错了,Redis 会如何处理
总结
1、Redis 发布订阅模式可以类比观察者模式,便于理解
涉及 4 个角色,理清楚它们各自的作用就好理解了
2、Lua 在 Redis 中非常灵活,相当于给我们留了一个自定义命令的接口
3、Redis 客户端有很多,我们不能只局限于 redis-cli
参考
《Redis开发与运维》
Redisson 分布式锁实现之前置篇 → Redis 的发布/订阅 与 Lua的更多相关文章
- Redisson 分布式锁实现之源码篇 → 为什么推荐用 Redisson 客户端
开心一刻 一男人站在楼顶准备跳楼,楼下有个劝解员拿个喇叭准备劝解 劝解员:兄弟,别跳 跳楼人:我不想活了 劝解员:你想想你媳妇 跳楼人:媳妇跟人跑了 劝解员:你还有兄弟 跳楼人:就是跟我兄弟跑的 劝解 ...
- Redisson分布式锁的简单使用
一:前言 我在实际环境中遇到了这样一种问题,分布式生成id的问题!因为业务逻辑的问题,我有个生成id的方法,是根据业务标识+id当做唯一的值! 而uuid是递增生成的,从1开始一直递增,那么在同一台机 ...
- Redisson分布式锁实现
转: Redisson分布式锁实现 2018年09月07日 15:30:32 校长我错了 阅读数:3303 转:分布式锁和Redisson实现 概述 分布式系统有一个著名的理论CAP,指在一个分布 ...
- Redisson 分布式锁源码 09:RedLock 红锁的故事
前言 RedLock 红锁,是分布式锁中必须要了解的一个概念. 所以本文会先介绍什么是 RedLock,当大家对 RedLock 有一个基本的了解.然后再看 Redisson 中是如何实现 RedLo ...
- [转帖]SpringBoot集成redisson分布式锁
SpringBoot集成redisson分布式锁 https://www.cnblogs.com/yangzhilong/p/7605807.html 前几天同事刚让增加上这一块东西. 百度查一下 啥 ...
- Redisson 分布式锁实战与 watch dog 机制解读
Redisson 分布式锁实战与 watch dog 机制解读 目录 Redisson 分布式锁实战与 watch dog 机制解读 背景 普通的 Redis 分布式锁的缺陷 Redisson 提供的 ...
- 又长又细,万字长文带你解读Redisson分布式锁的源码
前言 上一篇文章写了Redis分布式锁的原理和缺陷,觉得有些不过瘾,只是简单的介绍了下Redisson这个框架,具体的原理什么的还没说过呢.趁年前项目忙的差不多了,反正闲着也是闲着,不如把Rediss ...
- Redisson 分布式锁源码 02:看门狗
前言 说起 Redisson,比较耳熟能详的就是这个看门狗(Watchdog)机制. 本文就一起看看加锁成功之后的看门狗(Watchdog)是如何实现的? 加锁成功 在前一篇文章中介绍了可重入锁加锁的 ...
- Redisson 分布式锁源码 11:Semaphore 和 CountDownLatch
前言 Redisson 除了提供了分布式锁之外,还额外提供了同步组件,Semaphore 和 CountDownLatch. Semaphore 意思就是在分布式场景下,只有 3 个凭证,也就意味着同 ...
随机推荐
- Win64 驱动内核编程-19.HOOK-SSDT
HOOK SSDT 在 WIN64 上 HOOK SSDT 和 UNHOOK SSDT 在原理上跟 WIN32 没什么不同,甚至说 HOOK 和 UNHOOK 在本质上也没有不同,都是在指定的地址上填 ...
- Day003 JavaDoc
JavaDoc javadoc命令是用来生成自己的Api文档的 参数信息 @author 作者名 @version 版本号 @since 指明需要最早使用的jdk版本 @param 参数名 @retu ...
- 是时候学习Linux了
前言: Linux是一个开源.免费的操作系统.其稳定性.安全性.处理多并发已经得到业界的认可,目前很多企业级的项目都会部署到Linux/unix系统上.如果你还不太了解Linux,希望本篇文章能够带你 ...
- 【近取 Key】Alpha - v1.0 版本发布说明
功能与特性 Alpha 版本虽然为本软件的第一代版本,但已基本覆盖了用户个人使用时的主要功能.除登陆注册与后台管理外,下文将分版块详细介绍面向用户的主要功能特性. 『产品主页』 潜在应用场景 场景 0 ...
- 日常Bug排查-系统失去响应-Redis使用不当
日常Bug排查-系统失去响应-Redis使用不当 前言 日常Bug排查系列都是一些简单Bug排查,笔者将在这里介绍一些排查Bug的简单技巧,同时顺便积累素材_. Bug现场 开发反应线上系统出现失去响 ...
- Word·去掉复制粘贴自动添加的空格
阅文时长 | 0.05分钟 字数统计 | 145.6字符 主要内容 | 1.引言&背景 2.声明与参考资料 『Word·去掉复制粘贴自动添加的空格』 编写人 | SCscHero 编写时间 | ...
- 关于.NET微服务最热门的问题解答
在我们最近让我们一起学习.NET的微服务专场活动中,我们收到了一些很好的问题.我们在现场已经回答很多问题,但我们想继续回答一些在会议中出现的最热门的问题.如果你错过了现场直播,不要担心,因为你可以按需 ...
- [Qt] 项处理组件
项(Item):一个项存储了文字.文字的格式.自定义数据等. 1.项视图(Item View) 针对一个数据模型,可能有不同的展示需求,如文件夹中图片 ...
- 无法开机 如果您的手机黑屏无法开机,可以按照以下方式操作尝试: 如果是,使用原装充电器或使用弱电流方式充电(例如使用电脑USB接口充电)充电15-30分钟后尝试重新开机;注意:电量过低引起的无法开机,刚插入充电器时可能不亮屏但呼吸灯闪烁状态。
https://www.mi.com/service/support/startup 无法开机 如果您的手机黑屏无法开机,可以按照以下方式操作尝试: 技术支持 如何刷机 无法开机 手机自动关机.重启 ...
- Redis 安装和启动
Redis 安装 安装准备: redis 压缩包 官网下载地址:https://redis.io/download 安装步骤: 第一步:安装 gcc 编译器 官网发布的 Redis 压缩包是 C 语言 ...