文章目录
- 1. Redis持久化方式
- 2. RDB(快照)
- 2.1 手动方式
- 2.2 自动方式
- 2.3 何时触发 RDB 持久化
- 2.4 RDB 相关配置
- 3. AOF(追加日志文件)
- 3.1 AOF 文件解读
- 3.2 AOF 的写入与同步
- 3.3 AOF 重写
- 3.4 AOF 重写面临的问题
- 3.5 AOF相关配置
- 4. 混合持久化
1. Redis持久化方式
Redis持久化是指将Redis服务器中的数据保存到磁盘上,以防止数据在服务器重启时丢失。Redis提供了两种主要的持久化方式:RDB(Redis DataBase)和AOF(Append Only File)。这两种持久化方式可以分别或同时使用,以满足不同的需求和场景。Redis持久化不保证数据的完整性,有可能会丢数据。当Redis用作DB时,DB数据要完整,所以一定要有一个完整的数据源(文件、mysql),在系统启动时,从这个完整的数据源中将数据load到Redis中。
- RDB:RDB文件是一个经过压缩的二进制文件。
- AOF:AOF则是以追加的方式记录Redis执行的每一条写命令。
2. RDB(快照)
RDB 是 Redis 默认的持久化方式,它将 Redis 在内存中的数据写入到硬盘中,生成一个快照文件。这个快照文件是一个二进制文件,包含了 Redis 在某个时间点内的所有数据。
RDB 文件以二进制格式保存,因此非常紧凑,并且在 Redis 重启时可以快速加载数据。相比于 AOF,通常情况下 RDB 文件会更小。
RDB 的优点在于快速、简单,适用于大规模数据备份和恢复。然而,RDB 也存在一些缺点,其中一个主要缺点是数据可能会丢失。因为 Redis 只会在指定的时间点生成快照文件,如果在快照文件生成之后,但在下一次快照文件生成之前服务器宕机,那么这期间的数据就会丢失。
RDB 持久化可以通过两种方式触发:手动和自动。
- 手动方式是通过 SAVE 命令或 BGSAVE 命令触发的。
- 自动方式则是在 Redis 配置文件中设置触发条件,当满足条件时自动触发持久化操作。
2.1 手动方式
手动触发 RDB 持久化可以通过 SAVE 命令或 BGSAVE 命令来完成。
-
SAVE 命令:SAVE 命令会阻塞 Redis 服务器进程,直到 RDB 快照文件创建完毕为止。在创建 RDB 文件期间,Redis 服务器不能处理其他命令请求。因此,SAVE 命令会造成阻塞,不适合在生产环境中频繁使用。
-
BGSAVE 命令:BGSAVE 命令会在后台异步执行 RDB 持久化操作,不会阻塞 Redis 服务器进程,因此可以在不影响正常命令处理的情况下生成 RDB 文件。这是推荐的手动触发持久化方式。使用 BGSAVE 命令时,Redis 会创建一个子进程来执行持久化操作,主进程继续处理命令请求。
2.2 自动方式
自动触发 RDB 持久化可以通过设置 Redis 配置文件中的参数来实现。主要有两个参数控制自动触发 RDB 持久化的条件:
- save 参数:save 参数用于配置自动触发 RDB 持久化的条件。它接受一组数字参数,每个数字参数包含两个值:时间和修改次数。当满足任一组条件时,Redis 将执行 RDB 持久化操作。
save <seconds> <changes>
例如,save 900 1 表示在 900 秒内,如果至少有 1 个键被修改,则触发 RDB 持久化。
- stop-writes-on-bgsave-error 参数:stop-writes-on-bgsave-error 参数用于配置当 RDB 持久化失败时是否停止写入操作。设置为 yes 表示在 RDB 持久化失败时停止写入操作,设置为 no 表示即使 RDB 持久化失败也继续写入操作。
stop-writes-on-bgsave-error yes
在 Redis 的配置文件中,您可以根据具体需求配置这些参数。例如:
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
上述配置表示:
- 在 900 秒内,如果至少有 1 个键被修改,则触发 RDB 持久化。
- 在 300 秒内,如果至少有 10 个键被修改,则触发 RDB 持久化。
- 在 60 秒内,如果至少有 10000 个键被修改,则触发 RDB 持久化。
- 如果 RDB 持久化失败,则停止写入操作。
2.3 何时触发 RDB 持久化
Redis 服务器内部维护了一个计数器 dirty 和一个时间戳 lastsave 用于触发 RDB 持久化。Redis 判断触发 RDB 持久化的时机是在每个命令执行完成后,Redis 会检查是否满足了执行 RDB 持久化的条件。具体来说,它会在每次执行写入命令后(如 SET、DEL 等),检查以下两个条件:
- Dirty 数据量达到阈值: Redis 会维护一个 dirty 计数器,记录自上次 RDB 持久化以来被修改的键值对的数量。当 dirty 计数器的值超过了配置的 save 选项中的 save 参数中的 阈值时,就会触发 RDB 持久化。
- 上次 RDB 持久化时间间隔超过阈值: Redis 会记录上次执行 RDB 持久化的时间戳 lastsave。当当前时间与上次执行 RDB 持久化的时间间隔超过了配置的 save 选项中的 save 参数中的 阈值时,也会触发 RDB 持久化。
只有同时满足了上述两个条件,Redis 才会在命令执行完成后触发 RDB 持久化。
2.4 RDB 相关配置
- save :指定 RDB 持久化操作的条件,即在指定的时间间隔内(seconds)内有多少次写操作(changes)触发 RDB 快照的保存。
- stop-writes-on-bgsave-error:指定在 RDB 持久化过程中如果出现错误是否停止写入操作。如果设置为 yes,当 Redis 在执行 RDB 操作时遇到错误时,Redis 将停止接受写入操作;如果设置为 no,Redis 将继续接受写入操作。
- rdbcompression:指定是否对 RDB 文件进行压缩。如果设置为 yes,Redis 会在生成 RDB 文件时对其进行压缩,从而减少磁盘占用空间;如果设置为 no,Redis 不会对生成的 RDB 文件进行压缩。
- rdbchecksum:指定是否对 RDB 文件进行校验和计算。如果设置为 yes,在保存 RDB 文件时,Redis 会计算一个 CRC64 校验和并将其追加到 RDB 文件的末尾;在加载 RDB 文件时,Redis 会对文件进行校验和验证,以确保文件没有受到损坏或篡改。
- repl-diskless-sync:这是 Redis 2.8 中引入的一个配置项,用于指定复制节点在进行初次全量同步(即从主节点获取全部数据)时是否采用无盘同步方式。当设置为 yes 时,复制节点将通过网络直接获取主节点的数据,并且不会将数据存储到本地磁盘中;当设置为 no 时,复制节点将先将主节点的数据保存到本地磁盘中,然后再进行同步操作。采用无盘同步方式可以避免磁盘 IO 操作对系统性能的影响,但同时也会增加网络负载和内存占用。
- replica-serve-stale-data:这是 Redis 4.0 中新增的一个配置项,用于指定复制节点在与主节点断开连接后是否继续向客户端提旧数据。当设置为 yes 时,在复制节点与主节点断开连接后,该节点将继续向客户端提供旧数据,直到重新连接上主节点并且同步完全新的数据为止;当设置为 no 时,复制节点会立即停止向客户端提供数据,并且等待重新连接上主节点并同步数据。需要注意的是,当 replica-serve-stale-data 设置为 yes 时,可能会存在一定的数据不一致性问题,因此建议仅在特定场景下使用。
3. AOF(追加日志文件)
AOF(Append Only File)持久化是按照 Redis 的写命令顺序将写命令追加到磁盘文件的末尾,是一种基于日志的持久化方式,它保存了 Redis 服务器所有写入操作的日志记录。
AOF 的核心思想是将 Redis 服务器执行的所有写命令追加到一个文件中。这样做的好处是可以保证数据的完整性,当Redis服务器重新启动时,可以通过重新执行 AOF 中的命令来恢复服务器的状态,使其数据与写入时保持一致。
3.1 AOF 文件解读
一个简单的 AOF 文件示例如下:
这个文件展示了两条命令:
select 0
set k1 hello
其中:
- *号:表示参数个数,后面紧跟着参数的长度和值。
- $号:表示参数长度,后面紧跟着参数的值。
AOF文件中保存的所有命令都遵循相同的格式,即以*开头表示参数个数,$开头表示参数长度,其后紧跟着参数的值。
AOF有个比较好的优势是可以恢复误操作,如果你不小心执行了 FLUSHALL 命令,导致数据被误删,但只要 AOF 文件未被重写,那么只要停止服务器,移除 AOF 文件末尾的 FLUSHALL 命令,并重启 Redis,就可以将数据集恢复到 FLUSHALL 执行之前的状态。
3.2 AOF 的写入与同步
当启用 AOF 时,Redis 发生写命令时其实并不是直接写入到AOF 文件,而是将写命令追加到AOF缓冲区的末尾,之后 AOF缓存区再同步至 AOF文件中。
而 AOF 缓存区同步至 AOF 文件,这一过程由名为 flushAppendonlyFile 的函数完成。而 flushAppendOnlyFile 函数的行为由服务器配置文件的 appendfsync 选项来决定,该参数有以下三个选项:
- always:每次发生写命令都会立即将内容同步到 AOF 文件中,这是最安全的选项,但也会带来较大的性能开销。
- everysec:每秒钟同步一次写入操作到 AOF 文件,平衡了性能和安全性。
- no:不主动同步写入操作到 AOF 文件,而是由操作系统来决定同步时机,这样可能会提高性能,但也增加了数据丢失的风险。
默认情况下,Redis的 appendfsync 参数为 everysec。如果需要提高持久化安全性,可以将其改为 always ,如果更关注性能,则可以将其改为 no。但是需要注意的是,使用 no 可能会导致数据丢失的风险,建议在应用场景允许的情况下谨慎使用。
3.3 AOF 重写
AOF 重写是 Redis 中的一种机制,用于解决 AOF 文件不断增长导致文件过大的问题。随着 Redis 执行写命令的增加,AOF 文件会不断增长,可能会占用大量的磁盘空间。AOF 重写机制可以重新生成一个新的 AOF 文件,该文件包含了重写期间所发生的写命令所代表的数据状态,但是文件大小会更小,同时保留了原来 AOF 文件中的所有数据。
AOF 重写是通过遍历 Redis 数据库当前的键空间来实现的。在 AOF 重写期间,Redis 会维护一个用于记录所有写命令的数据结构,然后将这些写命令按照一定的规则进行合并和优化,最终生成一个新的 AOF 文件。
AOF 重写的触发条件通常是在后台执行,并且是在满足以下条件时触发的:
- AOF 重写至少间隔一定的时间,默认为1秒钟。
- AOF 文件的增长尺寸超过指定的比例,默认是100%。
- AOF 文件的增长尺寸超过指定的大小,默认是64MB。
AOF 重写机制的优点是生成的新 AOF 文件大小更小,因此可以节省磁盘空间。另外,由于 AOF 重写是在后台执行的,因此不会阻塞 Redis 的正常服务。
3.4 AOF 重写面临的问题
当子进程执行AOF重写时,父进程仍然在接收和处理新的命令,而这些新的命令可能会对数据库状态进行修改。为了解决这个问题,Redis在AOF重写期间采取了以下策略:
-
写入同步(write-rewrite): 父进程在执行新的写入命令时,会将这些写入操作同时写入到AOF重写缓冲区,以确保重写后的AOF文件能够包含所有正在进行的写入操作。
-
延迟重写(delayed rewrite): Redis会在父进程执行完一定数量或一定时间的写入命令后,才开始执行AOF重写操作。这样可以减少AOF重写对系统性能的影响,并尽量保证新的AOF文件与当前数据库状态一致。
-
标记重写(rewrite marker): 在AOF重写开始之前,Redis会在AOF文件中添加一个特殊的标记,表示AOF重写的起始位置。这样在AOF重写期间,即使有新的写入命令被追加到AOF文件中,也能够确保重写后的AOF文件不会覆盖这个标记之前的部分。
通过以上策略,Redis能够在AOF重写期间尽可能地保持数据库状态的一致性,并确保生成的新AOF文件包含所有的写入操作,从而避免数据丢失和不一致的问题。
3.5 AOF相关配置
在 Redis 的配置文件 redis.conf 中,可以通过以下配置项来设置 AOF 相关参数:
- appendonly: 用于开启或关闭 AOF,默认为关闭。若开启了 AOF,Redis 会在每次执行写命令时,将命令追加到 AOF 文件末尾。
- appendfilename: 指定AOF文件的名称,默认为appendonly.aof。可以通过设置这个选项来指定AOF文件的文件名。
- appendfsync: 用于控制AOF何时将缓冲区的数据同步到AOF文件中。可选值有always、everysec和no。默认值为everysec,表示每秒将缓冲区的数据同步到AOF文件中。设置为always表示每次发生写入命令都立即同步到AOF文件中,而设置为no则表示由操作系统决定何时进行同步。
- no-appendfsync-on-rewrite: 当开启AOF重写时,如果设置了这个选项为yes,那么Redis不会对AOF文件进行同步操作。这个选项可以减少AOF重写的时候对性能的影响。
- auto-aof-rewrite-percentage: 设置AOF文件重写时,AOF文件大小增长比例的下限,默认为100。当AOF文件的大小比上一次重写后的大小增长到这个比例以上时,会触发AOF文件的重写。
- auto-aof-rewrite-min-size: 设置AOF文件重写时,AOF文件的最小大小,默认为64MB。只有当AOF文件的大小超过这个阈值时,才会触发AOF文件的重写。
- aof-use-rdb-preamble: Redis 4版本新增特性,用于控制AOF重写期间是否使用RDB文件内容进行增量同步。默认情况下为no,如果设置为yes,则在AOF文件头加入一个RDB文件的内容,以尽可能减小AOF文件大小并方便数据恢复。
4. 混合持久化
在过去,Redis 用户通常会因为 RDB 持久化和 AOF 持久化之间不同的优缺点而陷入两难的选择当中:
- RDB 持久化能够快速地储存和恢复数据,但是在服务器停机时可能会丢失大量数据。
- AOF 持久化能够有效地提高数据的安全性,但是在储存和恢复数据方面却要耗费大量的时间。
为了让用户能够同时拥有上述两种持久化的优点, Redis 4.0 推出了一个“鱼和熊掌兼得”的持久化方案 —— RDB-AOF 混合持久化。
这种持久化能够通过 AOF 重写操作创建出一个同时包含 RDB 数据和 AOF 数据的 AOF 文件, 其中 RDB 数据位于 AOF 文件的开头, 它们储存了服务器开始执行重写操作时的数据库状态。至于那些在重写操作执行之后执行的 Redis 命令, 则会继续以 AOF 格式追加到 AOF 文件的末尾, 也即是 RDB 数据之后。
也就是说当开启混合持久化之后,AOF文件中的内容:前半部分是二进制的RDB内容,后面跟着AOF增加的数据,AOF位于两次RDB之间。
在目前版本中, RDB-AOF 混合持久化功能默认是处于关闭状态的, 要启用该功能, 用户不仅需要开启 AOF 持久化功能, 还需要将 aof-use-rdb-preamble 选项的值设置为 true。
appendonly yes
aof-use-rdb-preamble yes