redis 的ACID 性质

摘录自《Redis 设计与实现》19.3
在Redis中 事务总是具有原子性,一致性,隔离性,隔离性,持久性。一下四个小结分别对四个特性进行讨论

19.1 原子性

事物具有原子性指的是,数据库将十五中的多个操作当做一个整体来执行,服务器要不执行执行十五中的所有操作,要不就一个操作都不执行。对于Redis的事务功能来说,事务队列的命令要不就全部执行,要不就一个都不执行,因此Redis的事务是具有原子性的(注:有待讨论)
举个例子,一下展示的是一个成功执行的事务,事务中的所有命令都会被执行,

redis>MULTI
OK
redis>SET msg "hello"
QUEUED
redis>GET msg
QUEUED
redis>EXEC
1)OK
2)"hello"

与此相反,以下展示的是一个执行失败的事务,这个事务因为命令入队出错拒绝执行,事务中的所有命令都不会被执行。

redis>MULTI
OK
redis>SET msg "hello"
QUEUED
redis>GET
(error) ERR wrong number of arguments for 'get' command
redis>GET msg
QUEUED
redis>EXEC
(error)EXECABORT Transaction discarded because of previous errors.

Redis的事务和传统的关系型数据库事务的最大区别在于,Redis 不支持事务的回滚机制,即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,知道事务队列中所有的命令都执行完毕。

在下面的例子中,即使RPUSH命令在执行期间出现了错误,事务的后续命令也会继续执行下去,并且执行的命令也不会有任何影响。


redis>SET msg "hello" #msg
键是一个字符串
OK
redis>MULTI
OK
redis>SADD fruit "apple" "banana" "cherry"
QUEUED
redis>RPUSH msg "good bye" "byebye"
QUEUED
redis>SADD alphabet "a" "b" "c"
QUEUED
redis>EXEC
1) (integer)3
2(error) WRONGTYPE Operation against a key holding the wrong kind of value
3)(integer)3

Redis的作者在事务的文档中解释说,不支持事务的回滚是因为这种复杂的功能和Redis追求简单高效的设计主旨不相符,并且他认为,Redis事务的执行时错误通常都是编程错误产生的,这种错误通常出现在开发环境中,很少在实际生产环境中出现,没有必要开发事务的回滚功能。

19.3.2一致性

事物具有一致性指的是,如果数据库在执行事务之前是一直的,那么在执行事务之后,无论事务是否成功,数据库也应该仍然是一致的。

“一致”指的是数据符合数据库本身的定义和要求,并没有包含非法或者无效的错误数据。

Redis通过谨慎的错误检测和简单的设计保证事物的一致性,一下三个小结介绍Redis事务可能出错的地方,并说明Redis是如何妥善的处理这些错误,从而保证事务的一致性的。

入队错误:如果一个事务在入队过程中出现命令不存在,或者命令格式不正确等情况,redis将拒绝执行这个事务。 2.6.5以前,如果在入队以前发生了错误,事务一样可以执行,不过只执行那些正确入队的命令。

执行错误:关于这种错误,有两个需要说明的地方,执行过程中发生的错误都是一些不能再入队时被服务器发现的错误,这些错误只会在命令实际是中被触发。即使执行过程中发生错误,服务器也不会中断事务的执行,它会继续执行事务中余下的命令。并且已经执行的命令不会被出错的命令影响。

服务器停机:如果在执行事务中停机,那么根据服务器使用的持久化模式,可能有以下的情况,如果服务器在无持久化内存模式下,重启后数据库是空白的,因此总是一致的。

如果运行于RDB模式下,停机不会导致不一致,因为可以根据RDB恢复数据,如果找不到RDB文件,重启后数据库是空白的,总是一致的。

如果运行于AOF模式下,事务中途停机不会导致不一致,因为可以根据AOF文件恢复数据。如果没有AOF,重启后是空白的,总之一直的。

19.3.3 隔离性

因为Redis使用单线程方式执行事务,并且服务器保证,执行事务中不会对事务进行中断,因此Redis的事务总是以串行的方式运行的,并且总是具有隔离性的。

19.3.4耐久性

事务的耐久性指的是,当一个事务执行完毕的时候,执行这个事务所得的结果已经保存到硬盘里面了,即使执行事务完毕之后停机,执行事务所得结果也不会丢失。
因为
Redis的事务不过是简单地用队列包裹起一组Redis命令
,Redis并没有为事务提供任何额外的持久化功能,并且Redis的事务耐久性由Redis所使用的耐久化模式决定的。

当服务器在无持久化内存模式下,事务不具有耐久性,一旦服务器停机,包括事务在内的所有服务器数据都停止。

当服务器在RDB持久化模式下运行时,服务器只会在特定的保存条件满足时,才会执行BGSAVE命令。并且异步执行的BGSAVE 不能保证事务数据第一之间内保存在硬盘里面,因此RDB模式下不具有持久性。

当服务器运行在AOF持久化模式下,并且appendsync选项为always时,程序总会在执行命令后调用sync,将数据真正保存在硬盘里面,因此这种配置喜爱具有耐久性。

当服务器运行于AOF持久化模式下,并且appendfsync选项为everysec时,程序每秒同步一次命令到硬盘,如果停机恰好发生在同步的那一秒,可能会造成事务数据丢失,因此这种配置下,事务不具有耐久性。
当服务器运行于AOF持久化模式下,并且appendfsync选项为no时,程序交给操作系统决定何时同步命令到硬盘,事务数据可能在等待同步中丢失,因此这种配置下,事务不具有耐久性。

不论Redis在什么模式下工作,在事务的最后加SAVE 命令,总是看以保证事物的耐久度的,不过会影响效率。

Leave a comment

Your email address will not be published.

*