Redis | 第8章 发布订阅与事务《Redis设计与实现》
前言
参考资料:《Redis设计与实现 第二版》;
第三部分为独立功能的实现,主要由以下模块组成:发布订阅、事务、Lua 脚本、排序、二进制位数组、慢查询日志、监视器;
本篇将介绍 Redis 的发布订阅与事务。Redis 提供了频道与模式的订阅与退订,支持对频道发送消息。Redis 的事务机制支持一次性、按顺序执行多个命令,以及事务的 ACID 性质;
与本章相关的 Redis 命令总结在下篇文章,欢迎点击收藏,本篇将不再重复:
《Redis常用命令及示例总结(API)》:https://blog.csdn.net/dlhjw1412/article/details/119713214
1. 发布订阅
1.1 频道的订阅与退订
客户端使用 SUBSCRIBE 命令订阅某个或某些频道;
客户端使用 UNSUBSCRIBE 命令退订频道;
Redis 将所有频道的订阅关系保存在服务器状态的
pubsub_challens字典里:struct redisService{
//...
//保存所有频道的订阅关系
dict *pubsub_channels;
};

- 频道订阅的情况:
- 频道已有其他订阅者,则将客户端添加到订阅者链表末端;
- 反之,字典里没有该频道,则创建一个键值对项;
- 频道退订的情况:
- 找到频道对应链表,删除客户端信息;
- 若删除后链表长度为0,则删除键;

1.2 模式的订阅与退订
客户端使用 PSUBSCRIBE 命令订阅某个或某些模式;
客户端使用 PUNSUBSCRIBE 命令退订模式;
Redis 将所有模式的订阅关系保存在服务器状态的
pubsub_patterns链表里:struct redisServer{
//...
//保存所有模式订阅关系,记录被订阅的模式
list *pubsub_patterns;
};
pubsub_patterns链表保存的结构体如下:typedef struct pubsubPattern{
//订阅模式的客户端
redisClient *client;
//被订阅的模式
robj *pattern;
} pubsubPattern;

- 客户端在订阅模式时,会创建一个
pubsubPattern结构体,并添加到链表尾部; - 客户端在退订模式时,遍历链表删除对应模式;

1.3 发送消息
- 客户端执行 PUBLISH channel message 命令将 message 消息发送给 channel 频道,然后服务器将消息发送给频道与模式订阅者;
- 将消息发送给频道订阅者:
- 在
pubsub_channels字典里找到频道channel的所有订阅者名单(链表),然后将消息发送给名单上的所有客户端;
- 在
- 将消息发送给模式订阅者:
- 遍历
pubsub_patterns链表,查找与channel频道相匹配的模式,然后将消息发送给订阅了这些模式的客户端;
- 遍历


1.4 查看订阅消息
- 客户端使用 PUBSUB 命令查看频道或模式的相关信息;
- PUBSUB CHANNELS [pattern] 命令用于返回服务器当前被订阅的频道;
- PUBSUB NUMSUB [channel ...] 命令接受任意多个频道作为输入参数,返回这些频道的订阅者数量。通过查询
pubsub_channels字典中对应频道键的链表值的长度; - PUBSUB NUMPAT 命令用于返回服务器当前被订阅模式的数量。通过查询
pubsub_patterns链表的长度;
2. 事务
- 事务提供一种将多个命令打包,然后一次性、按顺序执行多个命令的机制;
- 并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求;
2.1 事务的实现
- 事务开始:
- 使用 MULTI 命令;
- 通过修改客户端状态中
flags属性为 REDIS_MULTI 实现;
- 命令入队:
- 当客户端切换到事务模式时,会根据命令不同采取不同的操作;
- 与事务相关的命令有:EXEC、DISCARD、WATCH、MULTI;

- 事务队列:
Redis 客户端里有事务状态属性
mstate:typedef struct redisClient{
//...
//事务状态
multiState mstate;
} redisClient;
multiState事务状态结构,包含事务队列与计数器:typedef struct multiState{
//事务队列,FIFO排序
multiCmd *commands;
//已入队命令计数
int count;
} multiState;

- 执行事务:
- 处于事务状态的客户端向服务器发送 EXEC 命令时,会执行事务;
- 服务器遍历客户端的事务队列,执行队列中保存的所有命令,将执行结果返回给客户端;
2.2 WATCH 命令的实现
WATCH 命令是一个乐观锁;
在执行 EXEC 命令前:监视任意数量的数据库建;
在执行 EXEC 命令时:检查被监视的键是否至少有一个已经被修改,是则拒绝执行事务,返回错误;
Redis 数据库保存一个
watched_keys字典:typedef struct redisDb{
//...
// 字典,键表示被 WATCH 命令监视的数据库键;值为链表,记录监视该键的客户 端
dict *watched_keys;
} redisDb;
所有对数据库进行修改的命令,在执行后都会调用
multi.c/touchWatchKey函数对watched_keys字典进行检查:- 如果有客户端监视被修改的键,则将客户端的 REDIS_DIRTY_CAS 标识打开,表示客户端的事务安全性被破坏;
服务器接收到 EXEC 命令时,会根据客户端是否打开 REDIS_DIRTY_CAS 标识决定是否执行事务:
- 如果打开,说明本次提交不安全,服务器会拒绝执行客户端提交的事务;
- 否则说明事务安全,可以提交;

2.3 事务的 ACID 性质
- Redis 数据库的事务具有原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、耐久性(Durability);
- 原子性:
- 事务队列要么全部执行,要么一个都不执行;
- Redis 不支持事务回滚机制(rollback),事务队列中某个命令在执行期间出现错误,后续事务也会继续执行;
- 一致性:
- 一致指:数据符合数据库本身的定义和要求,没有包含非法或无效的错误数据;
- 数据库在执行事务之前是一致的,在执行事务之后,无论事务是否成功,数据库也应该是一致的;
- Redis 的一致性有:入队错误、执行错误、服务器停机;
- 隔离性:
- 数据库中多个事务并发执行,各个事务之间不会互相影响,并且与串行执行的结果相同;
- 原因:Redis 使用单线程方式执行事务以及事务队列中的命令,且服务器保证在事务执行期间不会对事务中断;
- 耐久性:
当一个事务执行完毕,执行事务所得的结果会被保存到永久性存储介质;
Redis 的事务耐久性由持久化模式支持:
服务器的持久化模式 事务的耐久性 说明 无持久化模式 不具有 RDB 持久化模式 不具有 服务器只会在特定条件下执行 BGSAVE AOF 持久化模式,且 appendfsync的值为always具有 程序总在执行命令后调用同步函数 AOF 持久化模式,且 appendfsync的值为everysec不具有 程序每秒同步一次命令数据到硬盘 AOF 持久化模式,且 appendfsync的值为no不具有 同步操作由操作系统决定 服务器打开了 no-appendfsync-on-rewrite选项不具有 该选项打开时,服务器在执行 BGSAVE 或 BGREWRITEAOF 命令时,会暂时停止对 AOF 文件进行同步(尽可能减少 I/O 阻塞) 不管 Redis 在上面模式下运行,在事务最后加上 SAVE 命令总可以保证事务的耐久性。但因为效率低,不具有实用性;
最后
新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!

Redis | 第8章 发布订阅与事务《Redis设计与实现》的更多相关文章
- Redis(二)-- 发布订阅、事务、安全、持久化
一.Redis发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. 打开两个窗口:session1 和 session2 在sess ...
- redis发布订阅、事务、脚本
Redis 发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 下图展示了频道 cha ...
- 【Redis数据库】命令学习笔记——发布订阅、事务、脚本、连接等命令汇总
本篇基于redis 4.0.11版本,学习发布订阅.事务.脚本.连接的相关命令. Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. 序号 ...
- 第三百零一节,python操作redis缓存-管道、发布订阅
python操作redis缓存-管道.发布订阅 一.管道 redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pi ...
- Redis 有序集合(sorted set),发布订阅,事务,脚本,连接,服务器(三)
Redis 有序集合(sorted set) Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员. 不同的是每个元素都会关联一个double类型的分数.redis正是通过 ...
- (二)Redis 笔记——发布&订阅、事务、数据库操作
1. Redis 发布订阅 1.1 概述 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 下 ...
- redis之mq实现发布订阅模式
示例代码-github 概述 Redis不仅可作为缓存服务器,还可用作消息队列,本示例演示如何使用redis实现发布/订阅消息队列. 在Redis中,发布者没有将消息发送给特定订阅者的程序.相反,发布 ...
- RedisRepository封装—Redis发布订阅以及StackExchange.Redis中的使用
本文版权归博客园和作者本人吴双共同所有,转载请注明本Redis系列分享地址.http://www.cnblogs.com/tdws/tag/NoSql/ Redis Pub/Sub模式 基本介绍 Re ...
- Redis学习笔记8--Redis发布/订阅
发布订阅(pub/sub)是一种消息通信模式,主要的目的是解耦消息发布者和消息订阅者之间的耦合,这点和设计模式中的观察者模式比较相似.pub /sub不仅仅解决发布者和订阅者直接代码级别耦合也解决两者 ...
随机推荐
- 2021.9.22考试总结[NOIP模拟59]
T1 柱状图 关于每个点可以作出两条斜率绝对值为\(1\)的直线. 将绝对值拆开,对在\(i\)左边的点\(j\),\(h_i-i=h_j-j\),右边则是把减号换成加号. 把每个点位置为横坐标,高度 ...
- 2021.8.3考试总结[NOIP模拟29]
T1 最长不下降子序列 数据范围$1e18$很不妙,但模数$d$只有$150$,考虑从这里突破. 计算的式子是个二次函数,结果只与上一个值有关,而模$d$情况下值最多只有$150$个,就证明序列会出现 ...
- 单片机stm32串口分析
stm32作为现在嵌入式物联网单片机行业中经常要用多的技术,相信大家都有所接触,今天这篇就给大家详细的分析下有关于stm32的出口,还不是很清楚的朋友要注意看看了哦,在最后还会为大家分享有些关于stm ...
- .NET 生态系统的蜕变之 .NET 6
.NET 6 是自.NET 4 框架以来生态系统看到的最大版本更新,虽然.NET Core 是2014年开始非常大的一项重大战略举措,但是.NET 6是真正的具有强大动力的非常重要的版本. 2021年 ...
- tar 解压分割压缩文件
被分割后的压缩文件必须先合并成一个压缩文件才能正常的解压. 第一步.合并压缩文件 第二步.正常解压 $ls TINA-1.3.tar.gzaa TINA-1.3.tar.gzab TINA-1.3.t ...
- python读取、写入txt文本内容
转载:https://blog.csdn.net/qq_37828488/article/details/100024924 python常用的读取文件函数有三种read().readline().r ...
- STL 去重 unique
一.unique函数 类属性算法unique的作用是从输入序列中"删除"所有相邻的重复元素. 该算法删除相邻的重复元素,然后重新排列输入范围内的元素,并且返回一个迭代器(容器的长度 ...
- 使用vsftpd 搭建ftp服务
ftp 基础服务器基础知识 ftp有三种登录方式.匿名登录(所有用户).本地用户.虚拟用户(guest). FTP工作模式 主动模式:服务端从20端口主动向客户端发起链接. 控制端口21:数据传输端口 ...
- 【数据结构&算法】02-复杂度分析之执行效率和资源消耗
目录 前言 复杂度 分析方法 大 O 复杂度表示法 例子-评估累加和的各种算法执行效率 算法 1(for 循环): 算法 2(嵌套 for 循环): 大 O 表示 时间复杂度分析 关注执行最多的一段代 ...
- Docker容器间网络互联原理,讲不明白算我输....
@ 目录 一.今天我们要搞明白的实验 二.前置网络知识 2.1.docker默认为我们创建的网络 2.2.怎么理解docker0网桥 2.3.什么是veth-pair技术? 三.同一个局域网中不同主机 ...