Redis | 第8章 发布订阅与事务《Redis设计与实现》

article/2025/10/14 4:38:22

第8章 发布订阅与事务

  • 前言
  • 1. 发布订阅
    • 1.1 频道的订阅与退订
    • 1.2 模式的订阅与退订
    • 1.3 发送消息
    • 1.4 查看订阅消息
  • 2. 事务
    • 2.1 事务的实现
    • 2.2 WATCH 命令的实现
    • 2.3 事务的 ACID 性质
  • 最后


前言

参考资料:《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;
    };
    

一个 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;
    

pubsub_patterns 链表示例

  • 客户端在订阅模式时,会创建一个 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 实现;
  • 命令入队
    • 当客户端切换到事务模式时,会根据命令不同采取不同的操作;
    • 与事务相关的命令有:EXECDISCARDWATCHMULTI
      服务器判断命令类型
  • 事务队列
    • 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 选项不具有该选项打开时,服务器在执行 BGSAVEBGREWRITEAOF 命令时,会暂时停止对 AOF 文件进行同步(尽可能减少 I/O 阻塞)
    • 不管 Redis 在上面模式下运行,在事务最后加上 SAVE 命令总可以保证事务的耐久性。但因为效率低,不具有实用性;


最后

新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!

http://chatgpt.dhexx.cn/article/WU8vkttE.shtml

相关文章

AOF -- Redis 设计与实现

Redis 分别提供了 RDB 和 AOF 两种持久化机制: RDB 将数据库的快照(snapshot)以二进制的方式保存到磁盘中。AOF 则以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF 文件&#xff0c…

Redis设计与实现学习总结

Redis设计与实现学习总结 本文主要对Redis的设计和实现原理做了一个介绍很总结,有些东西我也介绍的不是很详细准确,尽量在自己的理解范围内把一些知识点和关键性技术做一个描述。如有错误,还望见谅,欢迎指出。 这篇文章主要还是参…

Redis的设计与实现(1):5种基本数据结构的底层实现

一、简单的动态字符串(SDS) Redis没有直接使用C语言传统的字符串表示,而是自己构建了一种名为简单动态字符串(simple dynamic string,SDS)的抽象类型,并将SDS作为Redis默认的字符串表示。 在Redis里,C字符…

Redis设计与实现总结

本文总结自《Redis设计与实现》一书,只打算总结Redis底层数据结构的实现。Redis的使用参考我的另一篇笔记Redis操作指南。 1 Redis概览 Redis是一个C语言编写的开源、非关系型内存数据库。它底层属于单线程、全内存操作,提供对象共享、引用计数和对象回…

Redis设计与实现

文章目录 第一部分:内部数据结构简单动态字符串(simple dynamic string)双端链表字典跳跃表 第二部分:内存映射数据结构整数集合intset压缩列表 redis数据类型对象处理机制(redisObject)字符串string哈希表hash列表list集合set有续集zset 第四部分&#…

redis的设计与实现

redis的设计和实现 第一部分、数据结构与对象 一、简单动态字符串: 在大多数情况下redis只会使用c字符串作为字面量,在大多情况下,redis使用SDS作为字符串表示。 比起C字符串,SDS具有五种优点: SDS结构里面会有一…

虚拟IP注册Nacos的问题

虚拟IP注册Nacos的问题 问题: A服务器有两个网卡,网卡 lo 绑定了 127.0.0.1 和一个虚拟IP,网卡 eth0 绑定了本地公网IP和一个虚拟IP。同样B服务器的网卡也是相同的配置,A、B服务器拥有的虚拟IP都是同一个地址。 当将A、B服务器部…

天翼云高可用虚拟IP(HAVIP)实践

产品概述 天翼云高可用虚拟IP(High-Availability Virtual IP Address,简称HAVIP)是一种可用独立创建和删除的私有网络IP地址资源。通过在VIP CIDR中申请一个私有网络IP地址,然后与高可用软件(如高可用软件Keepalived&…

云服务器虚拟ip绑定主机,如何在云平台上给云主机中的Keepalived的虚拟IP绑定弹性IP?...

1、 查看Keepalived和网卡配置文件中虚拟IP地址 查看虚拟机keepalived.config配置文件可以看到本地IP地址为172.16.100.109,虚拟IP地址为172.16.100.104。 (图1 Keepalived配置文件) 查看虚拟机网卡的IP地址情况,可以看到本地IP和虚拟IP。 (图2 查看虚拟…

EasyConnect虚拟IP地址未分配

工作中遇到EasyConnect虚拟IP地址未分配,导致无法正常连接服务器进行调测工作。 检查是否安装成功

蒲公英联机平台的服务器虚拟IP,蒲公英客户端如何使用固定虚拟IP管理虚拟局域网的步骤是什么?...

蒲公英异地组网分为路由器成员与客户端成员两种。其中路由器成员下的电脑,可通过本地连接获取的局域网IP进行组网通信访问;而安装并登录了蒲公英客户端成员,则是通过系统随机分配的临时虚拟IP,来进行组网成员的通讯。当成员移除原…

服务器怎么做虚拟ip,如何在服务器上添加虚拟IP?看完原来如此简单!!

写在前面最近,有位小伙伴为了实现Nginx的高可用,在自己的服务器上搭建了一套Nginx集群,Nginx节点的服务器总共有3台。那么问题来了:如何对外只使用一个IP地址,通过某种策略来访问三个服务器节点上的Nginx?答…

LNMP详解(九)——Nginx虚拟IP实战

今天继续给大家介绍Linux运维的相关知识,本文主要内容是Nginx的虚拟IP实战。 一、实战背景 在LNMP详解(七)——Nginx反向代理配置实战一文中,我们实现了如下所示的架构: 在该架构中,Nginx作为反向代理&a…

centos7 配置虚拟ip

环境概览 master:192.168.46.26 slave1:192.168.46.27 测试机:192.168.46.22(用于ping机器) 安装keepalived yum install -y keepalived修改master keepalived.conf 配置文件 vim /etc/keepalived/keepalived.confi…

计算机 修改 虚拟ip,怎么样在电脑中设置虚拟IP地址?

满意答案 wtc6981 2020.03.01 采纳率:56% 等级:9 已帮助:114人 更改IP地址 广域IP: 1、如果是PPOE上网只需断开连接再重新连上就好了,服务器会从IP地址池中随机分配一个IP地址给你。 2、固定IP上网那你要找运营商更改了,这样改是快不了的。…

虚拟服务器的真实ip,虚拟ip和真实ip区别(图文)

【导读】虚拟ip和真实ip区别,下面就是191路由网整理的网络知识百科,来看看吧! 大家好,我是191路由器网小编,上述问题将由我为大家讲解。 虚拟ip和真实ip区别是真实IP是网络运营商提供的所以不能自己变更,虚…

keepalived配置虚拟IP

YUM安装 # yum安装 yum -y install keepalived # 查看安装版本 rpm -qa keepalived # 查看安装路径 rpm -ql keepalived或是使用源码安装 到这里下载 https://www.keepalived.org/download.html # 安装依赖 yum -y install gcc openssl-devel libnfnetlink-devel 下载源码包…

虚拟ip的概念

1.虚拟IP是什么? 要是单讲解虚拟 IP,理解起来很困难,所以干脆把 动态 IP 、固定 IP 、实体 IP 与虚拟 IP都讲解一下,加深理解和知识扩展 实体 IP:在网络的世界里,为了要辨识每一部计算机的位置,因此有了计算机 IP 位址的定义。一…

虚拟IP简介

什么是虚拟IP 虚拟IP(Virtual IP Address,简称VIP)是一个未分配给真实弹性云服务器网卡的IP地址。弹性云服务器除了拥有私有IP地址外,还可以拥有虚拟IP地址,用户可以通过其中任意一个IP(私有IP/虚拟IP&…

浮点数的表示及其运算

目录 浮点数一般表示 科学计数法 浮点数一般表示 浮点数表示范围 浮点数规格化 IEEE 754 浮点数一般表示 科学计数法 科学记数法的形式是由两个数的乘积组成的。表示为a10^b,例如电子质量9 x 10^28kg 浮点数一般表示 对于浮点数也是类似 ,S:正…