Redis事务的ACID
原子性
对于Redis的事务功能来说,事务队列中的命令要么就全部都执行,要么就一个都不执行,因此,Redis的事务是具有原子性的
Redis的事务 和 传统的关系型数据库事务 的 最大区别在于,Redis不支持事务回滚机制(rollback)
即使 事务队列中的某个命令 在执行期间 出现了错误,整个事务也会继续执行下去,直到 将事务队列中 的 所有命令 都执行完毕 为止
为什么Redis不支持回滚(面试题)
- Redis 命令 只会因为 错误的语法而失败,或是 命令用在了错误类型的键上面
也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中 - 因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速
Redis主要认为失败 都是由 使用者造成的 所以就没有回滚操作
在Redis中除了没有回滚,Redis对事务也没有隔离级别的概念,所以就不会产生在使用关系型数据库时需要关注的脏读,幻读,重复读的问题
一致性
Redis通过谨慎的错误检测和简单的设计来保证事务的一致性
入队错误
如果一个事务在入队命令的过程中,出现了 命令不存在,或者 命令的格式不正确 等情况,那么Redis将拒绝执行这个事务
因为服务器会拒绝 执行入队过程中 出现错误的事务,所以Redis事务的一致性 不会被 带有 入队错误的事务 影响
Redis 2.6.5以前的入队错误处理
根据文档记录,在Redis 2.6.5以前的版本,即使有命令在入队过程中发生了错误,事务一样可以执行,不过被执行的命令只包括那些正确入队的命令
因为错误的命令不会被入队,所以Redis不会尝试去执行错误的命令
因此,即使在2.6.5以前的版本中,Redis事务的一致性也不会被入队错误影响
执行错误
除了入队时可能发生错误以外,事务还可能在执行的过程中发生错误
关于这种错误有两个需要说明的地方:
- 执行过程中 发生的错误 都是一些 不能在入队时被服务器发现的错误,这些错误 只会在 命令实际执行时被触发
- 即使 在事务的执行过程中 发生了错误,服务器 也不会中断 事务的执行,它会继续执行 事务中 余下的其他命令,并且 已执行的命令(包括执行命令所产生的结果)不会被 出错的命令影响
对数据库键执行了错误类型的操作是事务执行期间最常见的错误之一
服务器停机
如果Redis服务器在执行事务的过程中停机,那么根据服务器所使用的持久化模式,可能有以下情况出现:
- 如果服务器运行在无持久化的内存模式下,那么重启之后的数据库将是空白的,因此数据总是一致的
- 如果服务器运行在RDB模式下,那么在事务中途停机不会导致不一致性,因为服务器可以根据现有的RDB文件来恢复数据,从而将数据库还原到一个一致的状态。如果找不到可供使用的RDB文件,那么重启之后的数据库将是空白的,而空白数据库总是一致的
- 如果服务器运行在AOF模式下,那么在事务中途停机不会导致不一致性,因为服务器可以根据现有的AOF文件来恢复数据,从而将数据库还原到一个一致的状态。如果找不到可供使用的AOF文件,那么重启之后的数据库将是空白的,而空白数据库总是一致的
- 牵扯到Redis持久化的原理,感觉这里不太对呢,如果同步文件到一半,服务器停机了,那一致性如何保持呢?
隔离性
因为Redis使用单线程的方式来执行事务(以及事务队列中的命令),并且服务器保证,在执行事务期间不会对事务进行中断,因此,Redis的事务总是以串行的方式运行的,并且事务也总是具有隔离性的
持久性
因为Redis的事务 不过是 简单地 用队列 包裹起了 一组Redis命令,Redis并没有为事务提供任何额外的持久化功能,所以Redis事务的持久性由Redis所使用的持久化模式决定:
- 当服务器在无持久化的内存模式下运作时,事务不具有持久性。一旦服务器停机,包括事务数据在内的所有服务器数据都将丢失
- 当服务器在RDB持久化模式下运作时,服务器只会在特定的保存条件被满足时,才会执行
BGSAVE
命令,对数据库进行保存操作,并且异步执行的BGSAVE
不能保证事务数据被第一时间保存到硬盘里面,因此RDB持久化模式下的事务也不具有持久性 - 当服务器运行在AOF持久化模式下,并且
appendfsync
选项的值为always
时,程序 总会在 执行命令之后 调用同步(sync)函数,将命令数据真正地保存到硬盘里面,因此这种配置下的事务是具有持久性的 - 当服务器运行在AOF持久化模式下,并且
appendfsync
选项的值为everysec
时,程序会每秒同步一次命令数据到硬盘。因为停机可能会恰好发生在等待同步的那一秒钟之内这可能会造成事务数据丢失,所以这种配置下的事务不具有持久性 - 当服务器运行在AOF持久化模式下,并且
appendfsync
选项的值为no
时,程序 会交由 操作系统来决定 何时将命令数据同步到硬盘。因为事务数据可能在等待同步的过程中丢失,所以这种配置下的事务不具有持久性 - 在命令执行之后同步到硬盘?如果通过硬盘过程中此时服务器停机了呢?
不论Redis在什么模式下运作,在一个事务的最后加上SAVE
命令总可以保证事务的持久性
no-appendfsync-on-rewrite配置选项对持久性的影响
配置选项no-appendfsync-on-rewrite
可以配合appendfsync
选项为always
或者everysec
的AOF持久化模式使用
当no-appendfsync-on-rewrite
选项处于打开状态时,在执行BGSAVE
命令或者BGREWRITEAOF
命令期间,服务器会暂时停止对AOF文件进行同步,从而尽可能地减少I/O阻塞
但是这样一来,关于“always模式的AOF持久化可以保证事务的持久性”这一结论将不再成立
因为在服务器停止对AOF文件进行同步期间,事务结果可能会因为停机而丢失
因此,如果服务器打开了no-appendfsync-on-rewrite
选项,那么即使服务器运行在always
模式的AOF持久化之下,事务也不具有持久性
在默认配置下,no-appendfsync-on-rewrite
处于关闭状态