Redis事务是一个单独的隔离操作,事务中所有命令都会序列化、按顺序地执行。事务在执行过程中,不会被其他客户端发送来的命令请求打断。Redis事务的主要作用就是串联多个命令防止别的命令插队。
Multi、Exec、discard 从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis会将之前的命令队列中的命令以此执行。组队的过程中可以通过discard来放弃组队。
[root@CclSys ~]# redis-cli 127.0.0.1:6379> keys * 1) "15046923700:count" 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set key1 value1 QUEUED 127.0.0.1:6379(TX)> set key2 value2 QUEUED 127.0.0.1:6379(TX)> set key3 value3 QUEUED 127.0.0.1:6379(TX)> exec 1) OK 2) OK 3) OK 127.0.0.1:6379> keys * 1) "key2" 2) "15046923700:count" 3) "key1" 4) "key3" 127.0.0.1:6379> get key1 "value1" 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set a1 v1 QUEUED 127.0.0.1:6379(TX)> set a2 v2 QUEUED 127.0.0.1:6379(TX)> discard OK 127.0.0.1:6379> keys * 1) "key2" 2) "15046923700:count" 3) "key1" 4) "key3"事务的错误处理
-
组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消。
127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set b1 v1 QUEUED 127.0.0.1:6379(TX)> set b2 v2 QUEUED 127.0.0.1:6379(TX)> set b3 (error) ERR wrong number of arguments for 'set' command 127.0.0.1:6379(TX)> exec (error) EXECABORT Transaction discarded because of previous errors.
-
执行时出错,有错误的停止执行,其他不影响
127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set c1 v1 QUEUED 127.0.0.1:6379(TX)> incr c1 QUEUED 127.0.0.1:6379(TX)> exec 1) OK 2) (error) ERR value is not an integer or out of range
多人用一个账户在双十一参加抢购
- 三个请求
- 一个请求想给金额减少8000
- 一个请求想给金额减少5000
- 一个请求想给金额减少1000
解决方案:加锁 :乐观锁、悲观锁
悲观锁:(每次操作之前先上锁)
顾名思义就是很悲观,每次拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到拿到锁。传统的关系型数据库中有很多这种锁机制比如行锁,表锁等,读锁,写锁,都是在做操作之前先上锁。
乐观锁:(在操作时加入一个字段version)
顾名思义很乐观,每次拿数据时认为别人不会修改,所以不会上锁,但是在更新时会判断一下再此期间别人有没有更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。
WATCH key [key …]在执行multi之前,先执行watch key [key …] 可以监视一个或多个key,如果在事务执行之前这个key被其他命令所改动,那么事务将被打断。
Redis事务三特性- 单独的隔离操作
- 事务中的所有命令都会序列化、顺序的执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
- 没有隔离级别的概念
- 队列中的命令没有提交之前不会实际被执行,因为事务提交前任何指令都不会被实际执行。
- 不保证原子性
- 事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有
Redis提供了2中不同的持久化方式
- RDB
- AOF
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束说了,再通过这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何的IO操作,这就确保了极高的性能,如果需要进行大规模数据的回复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加高效。RDB的缺点是最后一次持久化后的数据可能丢失。
Fork- Fork 的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
- 在linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术”
- 一般情况父进程和子进程会共同共用一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。
- 适合大规模的数据恢复
- 对数据完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
- Fork的时候,内存中的数据被克隆了一份,大致 2 倍的膨胀性需要考虑
- 虽然Redis 在 Fork 时使用了写时复制技术,但是如果数据庞大时还是比较消耗性能。
- 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一个快照后的所有修改
以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(不记录读操作),只追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将指令从前到后执行一次以完成数据的恢复工作。
AOF 默认不开启可以在redis.conf中配置文件名称,默认为appendonly.aof
AOF文件的保存路径与RDB相同
-
AOF和RDB都开启,Redis默认读取AOF的数据(数据不存在丢失)
-
重启Redis然后appendonly.aof被重新加载
-
异常恢复
- 修改默认的appendonly no 改为 yes
- 如遇到AOF 文件损坏,通过**/usr/local/bin/redis-check=aof --fixappendonly.aof**进行恢复
- 备份被写坏的AOF文件
- 恢复:重启Redis,然后被重新加载
appendfsync always
始终同步,每次Redis的写入操作都会立刻记入日志,性能较差但数据完整性比较好
appendfsync everysec
每秒同步,每秒记入日志一次,如果宕机,本庙的数据可能丢失
aooendfsync no
redis不主动进行同步,把同步时机交给操作系统
AOF持久化流程- 客户端的请求写命令会被append追加到aof缓冲区内
- AOF缓冲区根据持久化操作策略[always 、everysec、no]将操作sync同步到磁盘的AOF文件中。
- AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量。
- 备份机制更文件,丢失数据概率更低
- 可读的日志文本,通过操作AOF文件,可以处理误操作。
- 比起RDB占用更多的磁盘空间
- 恢复备份速度慢
- 每次读写都同步的话,有一定的性能压力
- 存在个别Bug,造成恢复不稳



