zoukankan      html  css  js  c++  java
  • redis 事务

    事务相关命令

     
     
    Redis通过multi,discard,exec和watch四个命令来实现事务功能,
     
    一般事务
    • multi
    • discard
    • exec
     
    特殊:watch
     
    服务器在执行完事务中的所有命令之后,才会继续处理其他客户端的其他命令
     
     
    事务由multi开启,将多个命令入队到事务中,最后exec命令触发事务,一并执行性:
    一个事务从开始到执行会经历以下三个阶段:
    • 开始事务。
      • multi命令将服务器切换到事务状态
    • 命令入队。
      • 将命令放进事务队列里
    •  执行事务。
      • 从事务对列中取出命令并执行
     
     
    事务队列是一个数组,每个数组项包含三个属性
    • 要执行的命令(cmd)
    • 命令的参数(argv)
    • 参数的个数(argc)
     
    例子:
    举个例子,如果客户端执行以下命令:
    redis> MULTI
    OK
    redis> SET book-name "Mastering C++ in 21 days"
    QUEUED
    redis> GET book-name
    QUEUED
    redis> SADD tag "C++" "Programming" "Mastering Series"
    QUEUED
    redis> SMEMBERS tag
    QUEUED
     
    

      

    程序为客户端创建一下事务队列
    exec,discard,multi,watch 是不放入事务队列中的,而是直接执行的。
     
    事务队列的执行结果,放入回复队列中,当执行exec命令会将回复队列作为自己的执行结果放回客户端,
    并从事务状态返回到非事务状态。
     
    无论在事务状态下,还是在非事务状态下,Redis 命令都由同一个函数执行,所以它们共享很
    多服务器的一般设置,比如 AOF 的配置、 RDB 的配置,以及内存限制,等等
     
    事务中命令和普通命令的区别
    • 非事务状态下的命令以单个命令为单位执行,前一个命令和后一个命令的客户端不一定是同一个;
      • 而事务状态则是以一个事务为单位,执行事务队列中的所有命令:
      • 除非当前事务执行完毕,否则服务器不会中断事务,也不会执行其他客户端的其他命令。
    • 在非事务状态下,执行命令所得的结果会立即被返回给客户端;
      • 而事务则是将所有命令的结果集合到回复队列,再作为 EXEC 命令的结果返回给客户端
     
    Redis 的事务是不可嵌套的,处于事务状态的客户端在发送multi,则服务器只会返回一个简单错误不做任何操作,
    继续等待其他命令入队。
     
    DISCARD
    • 命令用于取消一个事务,它清空客户端 的整个事务队列,然后将客户端从事务状态调回非事务状态
     
    WATCH
    • 只能在客户端进入事务状态之前执行,在事务状态下发送 WATCH 命令会引发一个简单错误,不会做其他改变
    • 命令用于在事务开始之前监视任意数量的键:
      • 当调用 EXEC 命令执行事务时,如果任意一个被监视的键已经被其他客户端修改了,
      • 那么整个事务不再执行,直接返回失败。
      • watch一个key,这个key只能是自己改动,别人不能改,如果别人改了,我就不玩儿了。
      • 也就是事务的安全性
     
    WATCH命令的实现
     
    存储
    watch_keys 字典,字典的键是这个数据库被监控的键值,而字典的值则是一个链表,链表保存所有监视这个键的客户端。
     
    watch 触发
    在任何对数据库键空间( key space)进行修改的命令成功执行之后(比如 FLUSHDB 、 SET、DEL 、LPUSH 、SADD 、ZREM ,诸如此类),
    multi.c/touchWatchKey 函数都被调用,检查数据库的watch_keys字典,看是否有客户端在监视已经被命令修改的键。
    如果有, 程序将所有监视这个/这些被修改键的客户端的 REDIS_DIRTY_CAS 选项打开,表明事务安全性已经被破坏。
     
    当客户端发送exec命令,触发事务执行性,服务器会对客户端状态进行检查:
    REDIS_DIRTY_CAS
    • 被打开事务安全性已经被破坏,放弃事务,返回执行失败
    • 否则,服务器执行所有事务
     
    最后,当一个客户端结束它的事务时,无论事务是成功执行,还是失败,watched_keys字典中和这个客户端相关的资料都会被清除。
     
    事务的ACID性质

    在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的安全性。
    Redis 事务保证了其中的一致性( C)和隔离性( I),但并不保证原子性( A)和持久性( D)
     
    原子性(Atomicity)
    事务中命令要么全部执行成功,有一条失败则全部回滚
     
    单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以Redis事务的执行并不是原子性的
    如果 Redis 服务器进程在执行事务的过程中被停止,那么事务执行失败,但是不会回滚。
     
    一致性(Consistency)
    redis的一致性问题分三部分
    • 入队错误
    • 执行错误
    • redis进程被终结
     
    入队错误
    客户端向服务器发送了错误的命令。
    • 服务器将想客户端返回出错信息,并将客户端设为REDIS_DIRTY_EXEC状态。
    • 当执行exec命令时,Redis拒绝执行状态为 REDIS_DIRTY_EXEC 的事务。
    • 因此,带有不正确入队命令的事务不会被执行,也不会影响数据库的一致性
     
    执行错误
    对一个不同类型的 key 执行了错误的操作
    • Redis 只会将错误包含在事务的结果中
    • 这不会引起事务中断或整个失败
    • 不会影响已执行事务命令的结果
    • 也不会影响后面要执行的事务命令
    • 所以它对事务的一致性也没有影响
     
    redis进程被终结
    Redis 进程被终结 那么
    根据 Redis 所使用的持久化模式,可能有以下情况出现:
    • 内存模式
      • 如果 Redis 没有采取任何持久化机制,那么重启之后的数据库总是空白的,所以数据总是一致的。
    • RDB模式
      • 在执行事务时,Redis 不会中断事务去执行保存 RDB 的工作,只有在事务执行之后,保存 RDB 的工作才有可能开始。
      • 所以当 RDB 模式下的 Redis 服务器进程在事务中途被杀死时,事务内执行的命令,不管成功了多少,都不会被保存到 RDB文件里。
      • 恢复数据库需要使用现有的 RDB 文件,而这个 RDB 文件的数据保存的是最近一次的数据库快照( snapshot),所以它的数据可能不是最新的
        • 但只要 RDB 文件本身没有因为其他问题而出错,那么还原后的数据库就是一致的。
    • AOF模式
      • 因为保存 AOF 文件的工作在后台线程进行,所以即使是在事务执行的中途,保存 AOF 文件的工作也可以继续进行
      • 因此,根据事务语句是否被写入并保存到 AOF文件,有以下两种情况发生:
        • 如果事务语句未写入到 AOF 文件,或 AOF 未被 SYNC 调用保存到磁盘
          • 那么当进程被杀死之后,Redis 可以根据最近一次成功保存到磁盘的 AOF 文件来还原数据库
          • 只要 AOF 文件本身没有因为其他问题而出错,那么还原后的数据库总是一致的,但其中的数据不一定是最新的
        • 如果事务的部分语句被写入到 AOF 文件,并且 AOF 文件被成功保存
          • 那么不完整的事务执行信息就会遗留在 AOF 文件里
          • 当重启 Redis 时,程序会检测到 AOF 文件并不完整,Redis 会退出,并报告错误
            • 需要使用 redis-check-aof 工具将部分成功的事务命令移除之后,才能再次启动服务器。
            • 还原之后的数据总是一致的,而且数据也是最新的(直到事务执行之前为止)。
     
    隔离性(lsolation)
    Redis 是单进程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执
    行完所有事务队列中的命令为止。因此,Redis 的事务是总是带有隔离性的。
     
     
    持久性(Durability)
    因为事务不过是用队列包裹起了一组 Redis 命令,并没有提供任何额外的持久性功能,所以事
    务的持久性由 Redis 所使用的持久化模式决定:
    • 在单纯的内存模式下,事务肯定是不持久的。
    • 在RDB模式下,服务器可能在事务执行之后,RDB文件更新之前的这段时间失败,所以RDB模式下的Redis 事务也是不持久的
    • 在AOF的“总是 SYNC ”模式下,事务的每条命令在执行成功之后,都会立即调用 fsync或 fdatasync 将事务数据写入到 AOF 文件。
      • 但是,这种保存是由后台线程进行的,主线程不会阻塞直到保存成功,所以从命令执行成功到数据保存到硬盘之间,还是有一段非常小的间隔,所以这种模式下的事务也是不持久的
      • 其他 AOF 模式也和“总是 SYNC ”模式类似,所以它们都是不持久的
     
    小结
    •  事务提供了一种将多个命令打包,然后一次性、有序地执行的机制。
    •  事务在执行过程中不会被中断,所有事务命令执行完之后,事务才能结束。
    •  多个命令会被入队到事务队列中,然后按先进先出( FIFO)的顺序执行。
    •  带 WATCH 命令的事务会将客户端和被监视的键在数据库的 watched_keys 字典中进行关联,
      • 当键被修改时,程序会将所有监视被修改键的客户端的REDIS_DIRTY_CAS选项打开。
      • 只有在客户端的 REDIS_DIRTY_CAS 选项未被打开时,才能执行事务,否则事务直接返回失败。
    •  Redis 的事务保证了 ACID 中的一致性( C)和隔离性( I),但并不保证原子性( A)和持久性( D)。
     
  • 相关阅读:
    linux hosts文件详+mac主机名被莫名其妙修改
    WPF整理--动态绑定到Logical Resource
    WPF整理-使用逻辑资源
    WPF整理-自定义一个扩展标记(custom markup extension)
    WPF整理-XAML访问静态属性
    WPF整理-为控件添加自定义附加属性
    WPF整理-为User Control添加依赖属性
    使用MS Test进行单元测试
    WPF整理-XAML构建后台类对象
    毕业那点事儿--回顾在大学这7年
  • 原文地址:https://www.cnblogs.com/Aiapple/p/7255492.html
Copyright © 2011-2022 走看看