Redis 事务深入剖析

在传统的关系式数据库中,常常用ACID性质来检验功能的可靠性和安全性。

在Redis中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当Redis运行在某种特定的持久化模式下,事务也具有持久性(Durability)

一次完整事务的流程:

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set url https://www.baidu.com
QUEUED
127.0.0.1:6379> set title baidu
QUEUED
127.0.0.1:6379> set desc java
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
3) OK
127.0.0.1:6379>
127.0.0.1:6379> get url
 https://www.baidu.com
127.0.0.1:6379> get title
"baidu"
127.0.0.1:6379> get desc
"java"
127.0.0.1:6379>

Redis中事务实现分为三个阶段:

(1)事务开始

(2)命令入队

(3)事务执行

在Redis中实现事务主要依靠以下几个命令来实现:

Redis 事务深入剖析_第1张图片

事务开始

MULTI命令的执行标志事务的开始

Redis中使用MULTI命令标记事务的开始,可以理解为在传统关系型数据库中的BEGIN TRANCATION语句,Redis将执行该命令的客户端从非事务状态切换成事务状态,这一切换是通过在客户端状态的flags属性中打开REDIS_MULTI标识完成, 我们看下Redis中对应部分的源码实现:

Redis 事务深入剖析_第2张图片

命令入队

当一个客户端处于非事务状态时,这个客户端发送的命令会立即被服务器执行。

但时,如果当一个客户端切换到事务状态之后,服务器会根据这个客户端发来的不同命令执行不同的操作:

如果客户端发送的命令时EXEC、DISCARD、 WATCH 、MULTI 四个命令的其中一个,那么服务器立即执行这个命令

与此相反,如果客户端发送的命令时EXEC、DISCARD、 WATCH 、MULTI 四个命令之外的其他命令,那么服务器并不立即执行这个命令,而是将这个命令放入一个事务队列里面,然后向客户端返回QUEUED回复。

以下是服务器判断命令是该入队还是该执行的过程

Redis 事务深入剖析_第3张图片

事务队列

每个Redis客户端都有自己的事务状态,这个事务状态保存在客户端状态的mastate状态里:

Redis 事务深入剖析_第4张图片

事务状态包含一个事务队列,以及一个已入队命令的计数器(记录事务队列的长度):

Redis 事务深入剖析_第5张图片

事务队列是一个multiCmd类型的数组,数组中的每隔multiCmd结构都保存了已入队命令的相关信息,包括指向命令实现函数指针、命令的参数,以及参数的数量

Redis 事务深入剖析_第6张图片

事务队列以先进新出(FIFO)的方式保存入队的命令,较先入队的命令会被放到数组的前面,而较后入队的命令则会被放到数组的后

面。

整体结构如下

Redis 事务深入剖析_第7张图片

执行事务

当一个处于事务状态的客户端向服务器发送EXEC命令的时候,这个EXEC命令将立即被服务器执行。服务器会遍历这个客户端的事务队列,执行队列中保存的所有命令,最后将执行命令所得的结果全部返回给客户端

WATCH机制

WATCH命令是一个乐观锁(optimistic locking),它可以在EXEC命令执行前,监视任意数量的数据库键,并在EXEC命令执行时,检查被监视的键是否至少有一个已经被修改过了,如果是,服务器将拒绝执行事务,冰箱客户端返回代表事务执行失败的空回复。

每个Redis数据库都保存着一个watched_key字典,用于记录被WATCH命令监视的数据库键,而字典的值是一个链表,链表中记录了所有监视相应数据库键的客户端

Redis 事务深入剖析_第8张图片

通过watched_keys字典,服务器可以知道那些数据库键被监视,以及那些客户端正在监视这些数据库键

所有对数据库进行修改的命令,比如SET LPUSH SADD ZREM DEL FLUSHDB等等,在执行之后都会调用multi.c/touchWatchKey函数对watched_keys字典进行检查,查看是否有客户端正在监视刚刚被命令修改过的数据库键,如果有,那么touchWatchKey函数会将监视被修改键的客户端的REDIS_DIRTY_CAS标识打开,表示事务安全性已经被破坏

事务提交时候,如果发现CAS标识已经打开,那么说明事务已经不再安全,服务器将会拒绝客户端事务提交

Redis 事务深入剖析_第9张图片

你可能感兴趣的:(redis)