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

    Redis 提供的事务机制与传统的数据库事务有些不同,传统数据库事务必须维护以下特性:原子性(Atomicity),  一致性(Consistency),  隔离性(Isolation),  持久性(Durability),简称ACID。

     我们逐项考察下 Redis 在事务的 ACID 上做出的权衡与取舍:

     

    (1)原子性(Atomicity)

    原子意味着操作的不可再分,要么执行要么不执行。Redis 本身提供的所有 API 都是原子操作,那么 Redis 事务其实是要保证批量操作的原子性。Redis 实现批量操作的原理是在一个事务上下文中(通过 MULTI命令开启),所有提交的操作请求都先被放入队列中缓存,在 EXEC 命令提交时一次性批量执行。这样保证了批量操作的一次性执行过程,但 Redis 在事务执行过程的错误情况做出了权衡取舍,那就是放弃了回滚。 Redis 官方文档对此给出的解释是:

    1. Redis 操作失败的原因只可能是语法错误或者错误的数据库类型操作,这些都是在开发层面能发现的问题不会进入到生产环境,因此不需要回滚。
    2. Redis 内部设计推崇简单和高性能,因此不需要回滚能力。
    据实而说第一条说法感觉有点站不住脚,可以想象得到 Redis 操作失败的原因绝对不止语法层面的错误,特别是一些像依赖操作系统、文件系统的操作。第二条说法更实在,Redis 的应用场景明显不是为了数据存储的高可靠而设计的,而是为了数据访问的高性能而设计,设计者为了简单性和高性能而部分放弃了原子性。
    出于以上考虑 Redis 的事务执行有以下特点:
    1. 批量操作在发送 EXEC 命令前被放入队列缓存
    2. 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行
    3. 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中

    注意:get、set是原子操作,但是get+set组合不是原子操作,存在多线程并发问题,使用incr, 或watch保证正确性

    (2)一致性(Consistency)
    一致性意味着事务结束后系统的数据依然保证一致。在事务开始之前,数据保持有效的状态,事务结束后也如此。显然在前面讨论原子性时,Redis 舍弃了回滚的设计,基本上也就舍弃对数据一致性的有效保证。不过对于一个高效的 key-value store 或 data structure server,数据操作一致性很多时候更多应该依赖应用层面,事实也是我们使用 Redis 时很多时候都是分片和集群的,数据一致性无法依靠任何事务机制。
     
    (3)隔离性(Isolation)
    隔离性保证了在事务完成之前,该事务外部不能看到事务里的数据改变。也不能访问一些中间状态,因为假如事务终止的话,这些状态将永远不会发生。Redis 采用单线程设计,在一个事务完成之前,其他客户端提交的各种操作都无法执行因此自然没法看见事务执行的中间状态,隔离性得到保证。
     
    (4)持久性(Durability)
    Redis 一般情况下都只进行内存计算和操作,持久性无法保证。但 Redis 也提供了2种数据持久化模式,SNAPSHOT 和 AOF,SNAPSHOT的持久化操作与命令操作是不同步的,无法保证事务的持久性。而AOF模式意味着每条命令的执行都需要进行系统调用操作磁盘写入文件,可以保证持久性,但会大大降低 Redis 的访问性能。
     
    Redis 在2.6版本开始提供脚本(Lua scripting)能力,一种更灵活的批量命令组织方式用于取代目前的事务机制。脚本提供了更强大和灵活的编程能力,但也是一把双刃剑,由于 Redis 需要保证脚本执行的原子性和隔离性,脚本执行期间会阻塞其他命令的执行,因此建议写一些高效的脚本。不过从开发者的角度来说使用Lua脚本的成本(学习成本、开发成本、维护成本)都要更大,特别是一些开发者如果将应用的业务逻辑放入脚本中来执行,是不是让人想起了数据库的存储过程。

    一。multi & exec

    1. redis只能保证一个client发起的事务中的命令可以连续的执行, 由于redis是单线程来处理所有client的请求的,所以做到这点是很容易的。

    redis> multi
    OK
    redis> incr a
    QUEUED
    redis> incr b
    QUEUED
    redis> exec
    1. (integer) 1
    2. (integer) 1

    2. discard: 取消事务

    redis> multi
    OK
    redis> incr a
    QUEUED
    redis> incr b
    QUEUED
    redis> discard
    OK
    redis> get a
    "1"
    redis> get b
    "1"

     3.  虽说redis事务在本质上也相当于序列化隔离级别的了。但是由于事务上下文的命令只排队并不立即执行,所以事务中的写操作不能依赖事务中的读操作结果。

    redis> multi
    OK
    redis> incr a
    QUEUED
    redis> incr b
    QUEUED
    redis> discard
    OK
    redis> get a
    "1"
    redis> get b
    "1"

    4. watch : 实现乐观锁

    redis> watch a
    OK
    redis> get a
    "1"
    redis> multi
    OK
    redis> set a 2
    QUEUED
    redis> exec
    1. OK
    redis> get a,
    "2"

    连接断开,监视和事务都会被自动清除。 exec,discard,unwatch命令都会清除所有监视.

    二。存在问题

    1.redis只能保证事务的每个命令连续执行,但是如果事务中的一个命令失败了,并不回滚其他命令

    redis> set a 5
    OK
    redis> lpush b 5
    (integer) 1
    redis> set c 5
    OK
    redis> multi
    OK
    redis> incr a
    QUEUED
    redis> incr b
    QUEUED
    redis> incr c
    QUEUED
    redis> exec
    1. (integer) 6
    2. (error) ERR Operation against a key holding the wrong kind of value
    3. (integer) 6

    2.当事务的执行过程中,如果redis意外的挂了,只有部分命令执行。如果我们使用的append-only file方式持久化,redis会用单个write操作写入整个事务内容。

    即是是这种方式还是有可能只部分写入了事务到磁盘。发生部分写入事务的情况下,redis重启时会检测到这种情况,然后失败退出。可以使用redis-check-aof

    工具进行修复,修复会删除部分写入的事务内容。

  • 相关阅读:
    Oracle查看所有表空间使用情况
    Oracle版本信息查看
    Windows 7关闭和开启系统休眠
    ORACLE 创建表空间
    sp_helpdb使用
    SQL SERVER的数据类型
    博客园开通啦
    http keep alive
    android开发学习
    http与html
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/3936112.html
Copyright © 2011-2022 走看看