Redis的事务是什么?
Redis通过MULTI、EXEC、WATCH等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。
事务的流程
命令开始 => 命令入队 => 执行命令
命令开始
MULTI命令的执行标志着事务的开始,MULTI命令可以将执行该命令的客户端从非事务状态切换至事务状态。
命令入队
当一个客户端处于非事务状态时,这个客户端发送的命令会立即被服务器执行,而处于事务状态时服务器会根据这个客户端发来的不同的命令执行不同的操作:
image.png
执行事务
当一个处于事务状态的客户端向服务器发送 EXEC命令时,这个EXEC命令将立即被服务器执行。服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端。
Watch命令
WATCH命令是一个乐观锁(optimisticlocking),它可以在EXEC命令执行之前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是的话,服务器将拒绝执行事务,并向客户端返回代表事务执行失败的空回复。
在T4,客户端B修改了"name"键的值,当客户端A在T5执行EXEC命令时,服务器会发现WATCH监视的键"name"已经被修改,因此服务器拒绝执行客户端A的事务,并向客户端 A 返回空回复。
Watch的原理
每个Redis数据库都保存着一个watched keys字典,这个字典的键是某个被WATCH命令监视的数据库键,而字典的值则是一个链表,链表中记录了所有监视相应数据库键的客户端,结构如下∶
image.png
所有对数据库进行修改的命令,比如SET、LPUSH、SADD、ZREM、DEL、FLUSHDB 等等,在执行之后都会调用multi.c/touchWatchKey函数对watched_keys字典进行检查,查看是否有客户端正在监视刚刚被命令修改过的数据库键,如果有的话,那么touchwatchKey函数会将监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,表示该客户端的事务安全性已经被破坏。一旦客户端的REDIS_DIRTY_CAS被打开那么该客户端发送的Exec命令服务器都将拒绝执行。
Redis事务的特性(ACID)
事务具有原子性指的是,数据库将事务中的多个操作当作一个整体来执行,服务器要么就执行事务中的所有操作,要么就一个操作也不执行。
注意:Redis的事务和传统的关系型数据库事务的最大区别在于,Redis不支持事务回滚机制,即使事务队列中的某个命令在执行期间出现了错误,整个事务也会继续执行下去,直到将事务队列中的所有命令都执行完毕为止。
事务具有一致性指的是,如果数据库在执行事务之前是一致的,那么在事务执行之后,无论事务是否执行成功,数据库也应该仍然是一致的。
"一致"指的是数据符合数据库本身的定义和要求,没有包含非法或者无效的错误数据。
事务的隔离性指的是,即使数据库中有多个事务并发地执行,各个事务之间也不会互相影响,并且在并发状态下执行的事务和串行执行的事务产生的结果完全相同。
因为 Redis使用单线程的方式来执行事务(以及事务队列中的命令),并且服务器保证,在执行事务期间不会对事务进行中断,因此,Redis的事务总是以串行的方式运行的,并且事务也总是具有隔离性的。
事务的持久性指的是,当一个事务执行完毕时,执行这个事务所得的结果已经被保存到永久性存储介质(比如硬盘)里面了,即使服务器在事务执行完毕之后停机,执行事务所得的结果也不会丢失。
注意: 因为Redis的事务不过是简单地用队列包裹起了一组Redis命令,Redis并没有为事务提供任何额外的持久化功能,所以 Redis事务的耐久性由Redis所使用的持久化模式决定∶
1.当服务器在无持久化的内存模式下运作时,事务不具有耐久性∶一旦服务器停机,包括事务数据在内的所有服务器数据都将丢失。
2.当服务器在RDB持久化模式下运作时,服务器只会在特定的保存条件被满足时,才会执行BGSAVE 命令,对数据库进行保存操作,并且异步执行的BGSAVE 不能保证事务数据被第一时间保存到硬盘里面,因此 RDB 持久化模式下的事务也不具有耐久性。
3.当服务器运行在AOF持久化模式下,并且appendfsync 选项的值为always时,程序总会在执行命令之后调用同步(sync)函数,将命令数据真正地保存到硬盘里面,因此这种配置下的事务是具有耐久性的。
4.当服务器运行在AOF持久化模式下,并且appendfsync选项的值为everysec时,程序会每秒同步一次命令数据到硬盘。因为停机可能会恰好发生在等待同步的那一秒钟之内,这可能会造成事务数据丢失,所以这种配置下的事务不具有耐久性。
5.当服务器运行在AOF持久化模式下,并且appendfsync 选项的值为no时,程序会交由操作系统来决定何时将命令数据同步到硬盘。因为事务数据可能在等待同步的过程中丢失,所以这种配置下的事务不具有耐久性。
不论 Redis 在什么模式下运作,在一个事务的最后加上SAVE命令总可以保证事务的耐久性,不过效率会低(阻塞所有客户端)
redis> MULTI
redis> SET msg"hello"
redis> SAVE
redis> EXEC
网友评论