跳至主要內容

Redis 事务

blacklad大约 4 分钟RedisRedisRedis 设计与实现

Redis 事务

Redis通过 MULTI/EXEC/WATCH 等命令实现事务的功能,事务提供了一种将多个命令请求打包,一次性按顺序地执行多个命令的机制。

1 事务的实现

事务以一个 MULTI 命令开始,接着将多个命令放入事务当中,最后有 EXEC 命令将这个事务提交给服务器。

1.1 事务开始

MULTI 命令的执行标志事务的开始,将客户端从非事务状态切换为事务状态,通过客户端状态的 flags 属性实现。

1.2 命令入队

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

当客户端处理事务状态时,服务器会根据客户端发来的不同命令执行不同操作。

  • 如果是 EXEC/DISCARD/WATCH/MULTI 命令中的一个,就会被立即执行。
  • 其他命令会被放入一个事务队列里面,然后向客户端返回 QUEUED 回复。

事务队列

服务器的每个redis客户端保存自己的事务状态,事务状态包含一个事务队列和一个已入队命令的计数器,事务队列的长度。

1.3 事务执行

当一个处于事务状态的客户端向服务器发送 EXEC 命令时,这个 EXEC 命令会立即被服务器执行,服务器会遍历这个客户端的事务队列,执行所有命令并返回给客户端。

2 WATCH

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

每个 Redis 数据库保存着一个 watched_keys 字典,这个字典的键是某个被 WATCH 命令监视的数据库键,而字典的值是一个链表,链表中记录了所有监视键的客户端。

image-20210824230140469

2.1 监视机制的触发

当执行修改的命令时,会对 watched_keys 进行检查,如果存在,则修改对应reids客户端的 REDIS_DIRTY_CAS 标识,标识客户端的事务安全性已经被破坏。

2.3 EXEC 命令

当服务器收到 EXEC 命令时,会检测这个客户端是否打开了 REDIS_DIRTY_CAS 标识,来决定是否执行事务。

3 事务的 ACID

Redis 中,事务总是具有原子性、一致性、隔离性,对于隔离性需要在特定的持久化模式下才会有。

3.1 原子性

对于 Redis 的事务,多个操作要么全部执行,要不全不执行,满足原子性的。在的过程中,如果发生错误,那么这条事务中的所有命令都不会执行。

但是 Redis 的事务是不支持回滚的,在事务执行期间,如果某条命令运行错误,也会继续执行下去。

3.2 一致性

数据库在执行事务前后是一致的,无论事务是否执行成功,都应该保持一致。

一致性是指 数据符合数据库本身的定义和要求,没有非法、无效、错误的数据。

3.3 隔离性

多个事务并发地执行,各个事务之间不会相互影响,因为Redis使用单线程的方式来执行事务,并且保证执行过程中不会对事务进行终端,因此redis的事务总是以串行的方式运行的。

3.4 持久性

当一个事务执行完毕时,执行这个事务所得到的结果已经被保存到磁盘里面了,即使服务器宕机,也不会丢失结果。

Redis 的事务持久性由持久化模式决定:

  1. 无持久化的内存模式下运作时,一但停机就会丢失所有数据,事务不具有持久性。
  2. RDB 持久化模式,只有在特定的情况下才会执行 bgsave 命令,不能保证一定会被保存到硬盘里面, 事务不具有持久性。
  3. AOF 持久化模式,并且 appendfsync=always 时,程序会在执行命令之后调用同步函数,将命令保存到硬盘里面,事务具有持久性。
  4. AOF 持久化模式,并且 appendfsync=everysec 时,当停机时,可能会丢失一秒内的数据,事务不具有持久性。
  5. AOF 持久化模式,并且 appendfsync=no 时,由操作系统来决定何时将命令同步到磁盘,当停机时,可能会丢失部分数据,事务不具有持久性。
上次编辑于:
贡献者: blacklad