Redis 事务
Redis 的事务的本质是一组命令的批处理。这组命令在执行过程中会被顺序的,一次性全部执行完毕,只要没有出现语法错误,这组命令在执行期间是不会被中断
Redis 事务特性
redis 的事务仅保证了数据的一致性,不具有像 DBMS 一样的 ACID 特性
- 这组命令中的某些命令的执行失败不会影响其他命令的执行,不会引发 回滚 。即不具备原子性
- 这组命令通过乐观锁机制实现了简单的隔离性。没有复杂的隔离级别
- 这组命令的执行结果是被写入到内存的,是否持久取决于 Redis 的持久化策略,与事务无关
Redis 事务实现
-
三个命令
- multi:开启事务
- exec:执行事务
- discard:取消事务
exec 与 discard 不可共存
Redis 持久化
Redis 具有持久化功能,其会按照设置以 快照 或 操作日志 的形式将数据持久化到磁盘
根据持久化使用技术不同,分为两种:RDB 与 AOF
持久化(钝化)基本原理
RDB 与 AOF 可以共存,RDB 是默认持久化技术,而如果开启 AOF,则 AOF 的优先级更高
RDB 持久化
是指将内存中某一时刻的数据快照 全量 写入到指定的 rdb 文件的持久化技术。RDB 持久化是默认开启的。当 Redis 启动时会自动读取 RDB 快照文件,将数据从硬盘载入到内存,以恢复 Redis 关机前的数据库状态
持久化的执行
RDB 持久化的执行有三种方式:手动 save 命令,手动 bgsave 命令,与自动条件触发
-
手动 save 命令
通过在 redis-cli 客户端中执行 save 命令可立即进行一次持久化保存。save 命令在执行期间会阻塞 redis-server 进程,直至持久化过程完毕。而在 redis-server 进程阻塞期间,redis 不能处理任何读写请求,无法对外提供服务
-
手动 bgsave 命令
通过在 redis-cli 客户端中执行 bgsave 命令可立即进行一次持久化保存。不同于 save 的是,可以后台允许 save。bgsave 命令会使服务器进程 redis-server 生成一个子进程,由该子进程负责完成保存过程。在子进程进行保存过程中,不会阻塞 redis-server 进程对客户端读写请求的处理
-
自动条件触发
本质仍是 bgsave 命令的执行。只不过是用户通过在配置文件中做相应的设置后,Redis 会根据设置信息自动调用 bgsave 命令执行。
-
查看上次持久化的时间
- 格式:
lastsave
- 格式:
RDB 优化配置
参考配置文件 redis.conf 中的 SNAPSHOTTING 字段内容
RDB 文件结构
RDB 持久化文件 dump.rdb 分为五部分
-
SOF
SOF 是一个常量,一个字符串 REDIS,仅包含这五个字符,其长度为 5。用于 标识 RDB 文件的开始,以便在加载 RDB 文件时可以迅速判断出文件是否是 RDB 文件
-
rdb_version
一个整数,长度为 4 字节,标识 RDB 文件的版本号
-
databases
内部包含任意多个非空数据库。而每个 database 由三部分组成
- SODB:常量,占1字节,用于标识一个数据库的开始
- db_number:数据库编号
- key_value_pairs:当前数据库中的键值对数据
每个 key_value_pairs 又由很多个用于描述键值对的数据构成
- VALUE_TYPE:常量,占1字节,用于标识该键值对中 value 的类型
- EXPIRETIME_UNIT:常量,占1字节,用于标识过期时间的单位是秒还是毫秒
- time:当前 key-value 的过期时间
-
EOF
一个常量,长度为 1,用于标识 RDB 数据的结束,校验和的开始
-
check_sum
校验和 check_sum 用于判断 RDB 文件中的内容是否出现数据异常,其采用的是 CRC 校验算法
RDB 持久化过程
对于 Redis 默认的 Redis 持久化,在进行 bgsave 持久化时,redis-server 进程会 fork 出一个 bgsave 子进程,由该子进程以异步方式负责完成持久化。而在持久化过程中,redis-server 进程不会阻塞,其会继续接收并处理用户的读写请求。
bgsave 子进程的详细工作原理如下
- 由于子进程可以继承父进程的所有资源,且父进程不能拒绝子进程的继承权。所以,bgsave 子进程有权读取到 redis-server 进程写入到内存中的用户数据,使得将内存数据持久化到 dump.rdb 成为可能
- bgsave 子进程在持久化时首先会将内存中得全量数据 copy 到磁盘中的一个 RDB 临时文件,copy 结束后,在将该文件 rename 为 dump.rdb,替换掉原来的同名文件
- 不过,在进行持久化过程中,如果 redis-server 进程接收到了用户写请求,则系统会将内存中发生数据修改的物理块 copy 出一个副本。等内存中的全量数据 copy 结束后,会再将副本中的数据 copy 到 RDB 临时文件。这个副本的生成是由于 Linux 系统的写时复制技术(Copy-On-Write)实现的
AOF 持久化
AOF,是指 Redis 将每一次的写操作都以日志的形式记录到一个 AOF 文件中的持久性技术。当需要恢复内存数据时,将这些写操作重新执行一次,便会恢复到之前的内存数据状态
AOF 基础配置
-
AOF 的开启
在 redis.conf 配置文件内将
appendonly字段设置为 yes -
文件名配置
包括三类多个文件
- 基本文件:可以是 RDF 格式也可以是 AOF 格式。其存放的内容是由 RDB 转为 AOF 当时内存的快照数据。该文件可以有多个
- 增量文件:以操作日志形式记录转为 AOF 后的写入操作。该文件可以有多个
- 清单文件:用于维护 AOF 文件的创建顺序,保障激活时的应用顺序。该文件只有一个
-
混合式持久化开启
对于基本文件可以是 RDB 格式也可以是 AOF 格式。通过
aof-use-rdb-preamble属性可以选择。其默认值是 yes,即默认 AOF 持久化的基本文件为 rdb 格式文件,也就是默认采用混合式持久化
AOF 文件格式
-
Redis 协议
增量文件扩展名为.aof,采用 AOF 格式。AOF 格式其实就是 Redis 通讯协议格式,AOF 持久化文件的本质就是基于 Redis 通讯协议的文本,将命令以纯文本的方式写入到文件中
Redis 协议规定,Redis 文本是以行来划分,每行以\r\n 行结束。每一行都有一个我消息头,以表示消息类型。消息头由六种不同的符号表示
- (+):表示一个正确的状态信息
- (-):表示一个错误信息
- (*):表示消息体总共有多少行,不包括当前行
- ($):表示下一行消息数据的长度,不包括换行符长度\r\n
- (空):表示一个消息数据
- (:):表示返回一个数值
Rewrite 机制
为了防止 AOF 文件由于太大而占用大量的磁盘空间,降低性能,Redis 引入了 Rewrite 机制来对 AOF 文件进行压缩
-
何为 rewrite
所谓 Rewrite 其实就是对 AOF 文件进行重写整理。当 Rewrite 开启后,主进程 redis-server 创建出一个子进程 bgrewriteaof,由该子进程完成 rewrite 过程。其首先对现有 aof 文件进行 rewrite 计算,将计算结果写入到一个临时文件,写入完毕后,再 rename 该临时文件为原 aof 文件名,覆盖原有文件
-
rewrite 计算
其遵循以下策略
- 读操作命令不写入文件
- 无效命令不写入文件
- 过期数据不写入文件
- 多条命令合并写入文件
-
手动开启 rewrite
- 格式
bgrewriteaof
- 格式
AOF 优化配置
-
appendfsync
当客户端提交写操作命令后,该命令就会写入到 aof_buf 中,而 aof_buf 中的数据持久化到磁盘 AOF 文件的过程称为数据同步。
可以采用以下三种不同的数据同步策略
- always:写操作命令写入 aof_buf 后会立即调用 fsync() 系统函数,将其追加到 AOF 文件。该策略效率较低,但相对比较安全,不会丢失太多的数据。(生产情况不要使用)
- no:写操作命令写入 aof_buf 后什么都不做,不会调用 fsync() 函数。而将 aof_buf 中的数据同步磁盘的操作由操作系统负责。Linux 系统默认同步周期为 30 秒,效率较高。
- everysec:默认策略。写操作命令写入 aof_buf 后并不直接调用 fsync(),而是每秒调用一次 fsync() 系统函数来完成同步。该策略兼顾了性能与安全,是一种折中方案
-
no-appendfsync-on-rewrite
前提是 appendfsync 设置为 always 或 everysec
该属性用于指定,当主进程创建了子进程正在执行 bgsave 或 bgrewriteaof 时,主进程是否不调用 fsync() 来做数据同步
如果调用 fsync(),在需要同步的数据量非常大时,会阻塞主进程对外提供服务,可以将此命令设置为 yes,关闭 rewrite 操作,但这样也就和
appendfsync no一样了 -
aof-rewrite-incremental-fsync
当 bgrewriteaof 在执行过程也是先将 rewrite 计算的结果写入到了 aof_rewrite_buf 缓存中,然后当缓存中数据达到一定量后就会调用 fsync() 进行刷盘操作,即数据同步,将数据写入到临时文件。该属性用于控制 fsync() 每次刷盘的数据量最大不超过 4MB。这样可以避免由于单次刷盘量过大而引发长时间堵塞
-
aof-timestamp-enabled
该属性设置为 yes 则会开启在 AOF 文件中增加时间戳的显示功能,可方便按照时间对数据进行恢复。但该方法可能会与 AOF 解析器不兼容,所以默认值为 no,不开启
-
aof-load-truncated
AOF 文件可能会在加载到内存时被截断(当操作系统崩溃时,极有可能发生。但是当 Redis 崩溃,但系统没有崩溃时,不会发生这个情况),如果此命令设置为 yes,会重新加载 AOF 文件
AOF 持久化过程
RDB 与 AOF 对比
RDB 优势与不足
优势
- RDB 文件较小(快照)
- 数据恢复快
不足
- 数据安全性较差
- 写时复制会降低性能
- RDB 文件可读性较差
AOF 优势与不足
优势
- 数据安全性高
- AOF 文件可读性高
不足
- AOF 文件比较大(日志)
- 写操作会影响性能
- 数据恢复较慢(重新执行命令)
持久化技术的选型
官方推荐使用 RDB 与 AOF 混合式持久化。
若对数据安全性要求不高,则推荐使用纯 RDB 持久化方式
不推荐使用纯 AOF 持久化方式。
若 Redis 仅用于缓存,无需使用任何持久化技术