redis 订阅发布 可靠吗_redis项目

redis 订阅发布 可靠吗_redis项目(第8章 发布订阅与事务) 前言 参考资料:《Redis设计与实现 第二版》; 第三部分为独立功能的实现,主要由以下模块组成:发布订阅、事务、Lua 脚本、排序、二进制位数组、慢查询日志、监视器; 本

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

目录
  • 前言
    • 《Redis常用命令及示例总结(API)》:https://www.cnblogs.com/dlhjw/p/15639773.html
  • 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://www.cnblogs.com/dlhjw/p/15639773.html

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 命令总可以保证事务的耐久性。但因为效率低,不具有实用性;


最后


新人制作,如有错误,欢迎指出,感激不尽!

欢迎关注公众号,会分享一些更日常的东西!

如需转载,请标注出处!

redis 订阅发布 可靠吗_redis项目



版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5648.html

(0)
上一篇 2023-04-30
下一篇 2023-04-30

相关推荐

  • 用Python实现高效数据爬取

    用Python实现高效数据爬取互联网时代的到来让人们无时不刻不在接收和产生着海量的数据,如何实现高效数据的获取和信息提取已经成为了当今互联网行业最重要的工作之一。在这个过程中,数据爬取技术是至关重要的一环,Python作为一门较为常用的编程语言,有着很多优秀的爬虫框架和工具,使用Python编写代码能够有效地实现高效数据爬取。

    2024-04-21
    72
  • 存储过程条件判断_条件语句和循环语句

    存储过程条件判断_条件语句和循环语句条件语句部分 循环语句:有 **1.**REPEAT 直至条件表达式为True时执行的语句 UNTIL 条件表达式 END REPEAT; **2.**WHILE 条件表达式 DO 系列语句 END…

    2023-03-29
    160
  • PLSQL错误总结[通俗易懂]

    PLSQL错误总结[通俗易懂]1、'' is null为true,''和null是同一个东西。 神经病写法:无论vc_itemids是null还是'',or后面的那一句都为false

    2023-03-07
    158
  • excel截取字符子串_从后往前截取字符串用什么函数

    excel截取字符子串_从后往前截取字符串用什么函数函数:mid需求:提取A1单元格字符串的一部分(第四个字符算起,截取2个字符)放在A2单元格。使用:=mid(A1,4,2)

    2023-03-01
    149
  • Python中的items函数用法

    Python中的items函数用法Python是一种功能强大、易于学习和使用的编程语言,它提供了很多内置函数和方法来方便地操作数据。其中一个常用的函数是items()函数,它可以将一个字典类型的数据转换为一个包含字典中所有项的列表,每个项由键和值组成。

    2024-05-12
    71
  • sql分组排序row_number() over()

    sql分组排序row_number() over()
    sql分组排序函数 row_number() over(partition by 分组列 order by 排序列 desc) select tmp.pk_…

    2023-04-07
    163
  • NumPy数组添加元素方法详解

    NumPy数组添加元素方法详解NumPy是Python中用于科学计算的核心库之一,它提供了高性能的多维数组对象以及相关工具。在NumPy中,向数组中添加元素是一个经常需要用到的操作。因此,本文将详细介绍使用NumPy数组添加元素的方法,以帮助读者更好地理解和使用NumPy库。

    2024-09-06
    24
  • Python函数:计算两个数的和

    Python函数:计算两个数的和函数是Python中非常重要的概念,通俗来说,函数就是一段可复用的代码块,它能接受输入参数,经过处理后返回输出结果。在Python中,要创建一个函数,需要使用关键字def,函数名称后面紧跟着一对小括号,括号中是函数的参数。函数的执行过程是先将参数传递给函数,然后执行函数内部的代码,最后返回结果。

    2023-12-13
    104

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注