Redis事务概述
Redis事务可以理解为一种将多个Redis命令打包,然后一次性、有序地执行的机制。它确保这些命令作为一个整体进行执行,要么全部成功执行,要么全部不执行,从而保持数据的一致性。
- 定义:
Redis事务是一个单独的隔离操作,事务中的所有命令都会序列化,然后按照顺序地执行。
事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 - 特点:
原子性:在事务块中,所有命令要么全部成功执行,要么全部不执行。这意味着在事务中出现错误时,所有已暂存的命令都会被回滚,确保数据状态保持一致。但需要注意的是,Redis事务的原子性与其他数据库(如关系型数据库)中的原子性有所不同,Redis中的单条命令是原子性的,但事务整体并不保证原子性。
隔离性:Redis事务在执行过程中不会被其他事务干扰,每个事务都是独立执行的。这种隔离性减少了并发事务之间的数据竞争问题。
多命令支持:在事务块中,可以包含多个Redis命令,这些命令会按照顺序执行。
灵活性:Redis提供了一些命令来控制事务块,如MULTI、EXEC、DISCARD和WATCH等。 - 注意事项:
Redis事务不支持传统数据库中的回滚机制。
Redis事务在执行期间不会阻塞其他客户端对数据库的读写操作。
总结来说,Redis事务提供了一种将多个命令打包执行的机制,确保这些命令作为一个整体进行执行,从而保持数据的一致性。然而,与传统数据库中的事务相比,Redis事务在某些方面(如原子性)存在差异,需要在使用时注意。
怎么理解 Redis 事务
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行
Redis 事务相关的命令有哪几个
MULTI、EXEC、DISCARD、WATCH
Redis通过MULTI、EXEC、WATCH等一组命令集合,来实现事务机制。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
- 使用方法和相关命令:
MULTI:用于标记事务的开始。
EXEC:用于执行事务中的所有命令。
DISCARD:用于取消事务。
WATCH:用于在事务执行期间监视一个或多个键,当这些键被其他客户端修改时,事务会被中断。
简言之,Redis事务就是顺序性、一次性、排他性的执行一个队列中的一系列命令。
Redis执行事务的流程
开始事务(MULTI)
命令入队
执行事务(EXEC)、撤销事务(DISCARD ) - 执行流程:
在调用EXEC命令之前,所有命令都不会立即执行,而是暂存起来。
当EXEC命令被调用时,Redis会执行队列中的所有命令,并将执行结果一并返回给客户端。返回结果的顺序与命令在事务中的顺序相同。 - 事务失败的处理:
如果事务中的某个命令执行失败,那么在执行回滚操作或提交操作时,这个错误命令的执行结果将被丢弃。但Redis在事务失败时不进行回滚,而是继续执行余下的命令。
如果事务执行中出现了错误,比如语法错误或者命令不存在等,Redis会将错误信息放入一个列表中,并在事务执行完成后返回错误结果。
WATCH命令和基于CAS的乐观锁
在Redis的事务中,WATCH命令可用于提供CAS(check-and-set)功能。假设我们通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Null multi-bulk应答以通知调用者事务执行失败。例如,我们再次假设Redis中并未提供incr命令来完成键值的原子性递增,如果要实现该功能,我们只能自行编写相应的代码。其伪码如下:
val = GET mykey val = val + 1 SET mykey $val
以上代码只有在单连接的情况下才可以保证执行结果是正确的,因为如果在同一时刻有多个客户端在同时执行该段代码,那么就会出现多线程程序中经常出现的一种错误场景–竞态争用(race condition)。比如,客户端A和B都在同一时刻读取了mykey的原有值,假设该值为10,此后两个客户端又均将该值加一后set回Redis服务器,这样就会导致mykey的结果为11,而不是我们认为的12。为了解决类似的问题,我们需要借助WATCH命令的帮助,见如下代码: WATCH mykey val = GET mykey val = val + 1 MULTI SET mykey $val EXEC 和此前代码不同的是,新代码在获取mykey的值之前先通过WATCH命令监控了该键,此后又将set命令包围在事务中,这样就可以有效的保证每个连接在执行EXEC之前,如果当前连接获取的mykey的值被其它连接的客户端修改,那么当前连接的EXEC命令将执行失败。这样调用者在判断返回值后就可以获悉val是否被重新设置成功
redis事物的了解CAS(check-and-set 操作实现乐观锁 )
和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制。在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事务的基石。相信对有关系型数据库开发经验的开发者而言这一概念并不陌生,即便如此,我们还是会简要的列出Redis中事务的实现特征:
1). 在事务中的所有命令都将会被串行化的顺序执行,事务执行期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。
2). 和关系型数据库中的事务相比,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为"BEGIN TRANSACTION"语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。
4). 在事务开启之前,如果客户端与服务器之间出现通讯故障并导致网络断开,其后所有待执行的语句都将不会被服务器执行。然而如果网络中断事件是发生在客户端执行EXEC命令之后,那么该事务中的所有命令都会被服务器执行。
5). 当使用Append-Only模式时,Redis会通过调用系统函数write将该事务内的所有写操作在本次调用中全部写入磁盘。然而如果在写入的过程中出现系统崩溃,如电源故障导致的宕机,那么此时也许只有部分数据被写入到磁盘,而另外一部分数据却已经丢失。Redis服务器会在重新启动时执行一系列必要的一致性检测,一旦发现类似问题,就会立即退出并给出相应的错误提示。此时,我们就要充分利用Redis工具包中提供的redis-check-aof工具,该工具可以帮助我们定位到数据不一致的错误,并将已经写入的部分数据进行回滚。修复之后我们就可以再次重新启动Redis服务器了。
redis 事务的 CAS 方案-redis 的并发竞争问题
这个也是线上非常常见的一个问题,就是多客户端同时并发写一个 key,可能本来应该先到的数据后到了,导致数据版本错了;或者是多客户端同时获取一个 key,修改值之后再写回去,只要顺序错了,数据就错了。而且 redis 自己就有天然解决这个问题的 CAS 类的乐观锁方案。
某个时刻,多个系统实例都去更新某个 key。可以基于 zookeeper 实现分布式锁。每个系统通过 zookeeper 获取分布式锁,确保同一时间,只能有一个系统实例在操作某个 key,别人都不允许读和写。
你要写入缓存的数据,都是从 mysql 里查出来的,都得写入 mysql 中,写入 mysql 中的时候必须保存一个时间戳,从 mysql 查出来的时候,时间戳也查出来。
每次要写之前,先判断一下当前这个 value 的时间戳是否比缓存里的 value 的时间戳要新。如果是的话,那么可以写,否则,就不能用旧的数据覆盖新的数据。

5752

被折叠的 条评论
为什么被折叠?



