MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Redis持久化机制与数据恢复

2021-05-282.3k 阅读

Redis持久化机制概述

Redis作为一款高性能的键值对数据库,其数据默认存储在内存中。虽然内存的读写速度极快,但一旦服务器断电或重启,内存中的数据就会丢失。为了解决这个问题,Redis提供了两种持久化机制:RDB(Redis Database)和AOF(Append - Only - File),它们可以将内存中的数据以不同的方式持久化到磁盘上,以便在重启时能够恢复数据。

RDB持久化机制

RDB原理

RDB持久化是将Redis在某一时刻的内存数据快照,以二进制的形式保存到磁盘上的文件。这个文件通常被称为RDB文件,文件名默认为dump.rdb

当执行RDB持久化时,Redis会fork一个子进程。这个子进程会共享父进程的内存数据(采用写时复制技术,Copy - On - Write,COW)。子进程负责将内存数据写入RDB文件,而父进程继续处理客户端的请求,这样就不会影响Redis的正常运行。

RDB文件的结构非常紧凑,它以一种高效的方式存储了Redis中的所有键值对。对于不同类型的数据(如字符串、哈希、列表、集合、有序集合等),RDB文件都有相应的编码方式来存储。

RDB触发方式

  1. 手动触发

    • SAVE命令:该命令会阻塞Redis服务器进程,直到RDB文件创建完成。在阻塞期间,Redis无法处理任何客户端请求。因此,这个命令通常不建议在生产环境中使用。
    • BGSAVE命令:这个命令会让Redis在后台执行RDB持久化。Redis会fork一个子进程来进行RDB文件的创建,父进程继续处理客户端请求。这种方式不会阻塞服务器进程,是生产环境中常用的手动触发方式。

    以下是Python使用redis - py库手动触发BGSAVE的代码示例:

import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
result = r.bgsave()
print(result)
  1. 自动触发
    • 配置文件中的save配置:在Redis的配置文件(redis.conf)中,可以通过save参数设置自动触发RDB持久化的条件。例如:
save 900 1
save 300 10
save 60 10000

这表示在900秒内如果有1个键被修改,或者300秒内有10个键被修改,又或者60秒内有10000个键被修改,就会自动触发BGSAVE命令进行RDB持久化。

RDB优点

  1. 数据恢复快:RDB文件是内存数据的快照,恢复数据时直接将RDB文件读入内存,速度相对较快。这对于大规模数据的恢复非常有利。
  2. 适合备份:RDB文件是一个紧凑的二进制文件,适合进行数据备份。可以将RDB文件定期拷贝到其他存储设备,以防止数据丢失。
  3. 对服务器性能影响小:使用BGSAVE命令时,由于是在后台fork子进程进行持久化,对Redis服务器的正常运行影响较小。

RDB缺点

  1. 数据丢失风险:RDB持久化是基于快照的方式,两次持久化之间的数据修改不会被记录。如果Redis服务器在两次RDB持久化之间发生故障,那么这期间的数据将会丢失。例如,按照save 900 1的配置,在900秒内如果服务器崩溃,那么这900秒内的数据变化将无法恢复。
  2. fork子进程开销:每次执行BGSAVE命令时,Redis都需要fork一个子进程。这个操作会消耗一定的系统资源,特别是在服务器内存较大时,fork操作可能会导致短暂的性能问题。

AOF持久化机制

AOF原理

AOF持久化是将Redis执行的写命令,以追加的方式写入到一个文件中,这个文件被称为AOF文件,文件名默认为appendonly.aof

当Redis服务器启动时,它会读取AOF文件,并重放其中的写命令,从而重建内存中的数据。与RDB不同,AOF记录的是命令,而不是数据的快照。

AOF文件中的内容是可读的文本格式,每一行都是一个Redis的写命令。例如,执行SET key value命令,在AOF文件中就会记录一行*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n。这种格式采用了RESP(Redis Serialization Protocol)协议进行编码。

AOF触发方式

AOF持久化是实时进行的,每当Redis执行一个写命令时,这个命令就会被追加到AOF缓冲区中。AOF缓冲区的内容会根据不同的策略被同步到AOF文件中。

在Redis的配置文件中,可以通过appendfsync参数来设置同步策略,有以下三种取值:

  1. always:每次执行写命令都会立即将AOF缓冲区的内容同步到AOF文件。这种策略保证了数据的高安全性,即使服务器崩溃,也只会丢失最后一条未同步的命令。但由于每次都进行磁盘I/O操作,性能相对较低。
  2. everysec:每秒将AOF缓冲区的内容同步到AOF文件。这种策略在性能和数据安全性之间做了一个平衡。在大多数情况下,即使服务器崩溃,也只会丢失1秒内的数据。这是生产环境中常用的同步策略。
  3. no:由操作系统决定何时将AOF缓冲区的内容同步到AOF文件。这种策略性能最高,但数据安全性最差,因为在操作系统将数据真正写入磁盘之前,如果服务器崩溃,AOF缓冲区中的所有数据都会丢失。

以下是Python使用redis - py库设置AOF同步策略的代码示例(假设已经连接到Redis服务器):

import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
# 设置为always同步策略
r.config_set('appendfsync', 'always')

AOF优点

  1. 数据安全性高:采用alwayseverysec同步策略时,数据丢失的风险相对较小。特别是always策略,几乎可以保证不丢失数据。
  2. 可读性强:AOF文件是文本格式,内容可读,便于进行故障排查和数据恢复的调试。如果AOF文件出现损坏,可以通过人工编辑或使用工具进行修复。

AOF缺点

  1. 文件体积大:由于AOF文件记录的是命令,随着时间的推移和写操作的增加,AOF文件会变得越来越大。例如,多次对同一个键进行修改,AOF文件中会记录每一次的修改命令,而不是像RDB那样只保存最终的状态。
  2. 恢复速度慢:在恢复数据时,Redis需要重放AOF文件中的所有写命令。如果AOF文件非常大,重放命令的过程会比较耗时,导致数据恢复速度比RDB慢。

AOF重写机制

AOF重写原理

由于AOF文件会不断增大,为了控制AOF文件的大小,Redis提供了AOF重写机制。AOF重写并不是对原AOF文件进行直接修改,而是通过读取当前数据库中的数据,然后按照一定的规则将其转化为一系列的写命令,生成一个新的、体积更小的AOF文件。

在重写过程中,Redis会fork一个子进程。子进程负责读取当前数据库中的数据,并将其转化为写命令写入新的AOF文件。父进程则继续处理客户端的请求,同时将新的写命令记录到一个临时的缓冲区中。当子进程完成重写后,父进程会将临时缓冲区中的命令追加到新的AOF文件中,然后用新的AOF文件替换旧的AOF文件。

AOF重写触发方式

  1. 手动触发:可以通过执行BGREWRITEAOF命令手动触发AOF重写。这个命令会让Redis在后台执行AOF重写操作,不会阻塞服务器进程。

以下是Python使用redis - py库手动触发BGREWRITEAOF的代码示例:

import redis

r = redis.Redis(host='localhost', port=6379, db = 0)
result = r.bgrewriteaof()
print(result)
  1. 自动触发:在Redis的配置文件中,可以通过auto - aof - rewrite - min - sizeauto - aof - rewrite - percentage两个参数来设置自动触发AOF重写的条件。
    • auto - aof - rewrite - min - size:表示AOF文件的最小大小,只有当AOF文件大小超过这个值时,才会触发自动重写。默认值是64MB。
    • auto - aof - rewrite - percentage:表示AOF文件大小的增长率。当AOF文件大小超过auto - aof - rewrite - min - size,并且AOF文件大小比上一次重写后的大小增长了指定的百分比时,就会触发自动重写。默认值是100%,即当AOF文件大小是上一次重写后大小的两倍时,触发自动重写。

AOF重写优点

  1. 减小文件体积:通过重写,去除了AOF文件中冗余的命令,将对同一个键的多次修改合并为一次,从而有效减小了AOF文件的大小。
  2. 提高恢复速度:较小的AOF文件在恢复数据时重放命令的时间会缩短,提高了数据恢复的速度。

AOF重写缺点

  1. 消耗资源:AOF重写过程中需要fork子进程,并且子进程需要读取整个数据库的数据,这会消耗一定的系统资源,包括内存和CPU。在重写期间,可能会对Redis的性能产生一定的影响。
  2. 数据一致性问题:在重写过程中,虽然父进程会将新的写命令记录到临时缓冲区并追加到新的AOF文件中,但在极端情况下,如在重写完成但还未替换旧的AOF文件时服务器崩溃,可能会导致数据不一致。不过这种情况发生的概率较低。

混合持久化

混合持久化原理

从Redis 4.0开始,引入了混合持久化的方式。混合持久化结合了RDB和AOF的优点,在进行持久化时,先将当前内存中的数据以RDB的格式写入AOF文件的开头,然后再将后续的写命令以AOF的格式追加到AOF文件中。

当Redis服务器重启时,首先会以RDB的方式快速加载数据到内存中,然后再重放AOF部分的命令,这样既利用了RDB恢复速度快的优点,又保证了数据的完整性,减少了数据丢失的风险。

混合持久化开启方式

在Redis的配置文件中,可以通过设置aof - use - rdb - preamble yes来开启混合持久化。开启混合持久化后,在执行AOF重写时,新生成的AOF文件就会采用混合持久化的格式。

以下是通过修改Redis配置文件开启混合持久化的示例(假设配置文件路径为/etc/redis/redis.conf):

sudo vi /etc/redis/redis.conf
# 在文件中添加或修改以下行
aof - use - rdb - preamble yes
sudo systemctl restart redis

混合持久化优点

  1. 快速恢复与数据安全兼顾:结合了RDB的快速恢复和AOF的数据安全性,在保证数据丢失风险较小的同时,提高了数据恢复的速度。
  2. 减少AOF文件体积:由于开头部分采用RDB格式存储数据,相比纯AOF格式,在一定程度上减少了AOF文件的大小,从而降低了重写的频率和重写时的资源消耗。

混合持久化缺点

  1. 兼容性问题:混合持久化是Redis 4.0才引入的特性,如果需要与旧版本的Redis兼容,可能无法使用这种方式。
  2. 复杂性增加:对于运维人员来说,混合持久化方式增加了一定的复杂性。在处理AOF文件相关的问题时,需要同时考虑RDB和AOF两部分的内容。

Redis数据恢复

使用RDB文件恢复数据

当Redis服务器配置了RDB持久化并且存在RDB文件(dump.rdb)时,在启动Redis服务器时,它会自动检测并加载RDB文件。如果需要手动恢复数据,可以将RDB文件放置到Redis的工作目录(可以通过config get dir命令查看),然后启动Redis服务器,Redis会自动将RDB文件中的数据加载到内存中。

以下是在Linux环境下手动恢复数据的步骤示例:

  1. 假设RDB文件在/tmp/dump.rdb,首先查看Redis的工作目录:
redis - cli config get dir

假设工作目录为/var/lib/redis。 2. 将RDB文件移动到Redis工作目录:

sudo mv /tmp/dump.rdb /var/lib/redis/
  1. 重启Redis服务器:
sudo systemctl restart redis

使用AOF文件恢复数据

如果Redis配置了AOF持久化并且存在AOF文件(appendonly.aof),在启动Redis服务器时,它会优先加载AOF文件来恢复数据。如果AOF文件损坏,可以使用Redis自带的redis - check - aof工具进行修复。

以下是修复AOF文件并恢复数据的步骤:

  1. 停止Redis服务器:
sudo systemctl stop redis
  1. 使用redis - check - aof工具修复AOF文件:
redis - check - aof --fix /var/lib/redis/appendonly.aof
  1. 启动Redis服务器,Redis会加载修复后的AOF文件恢复数据:
sudo systemctl start redis

混合持久化数据恢复

当使用混合持久化时,Redis启动时会先按照RDB的方式加载AOF文件开头的RDB部分数据到内存,然后再重放AOF部分的命令。如果AOF文件损坏,同样可以使用redis - check - aof工具进行修复,但需要注意工具对混合持久化格式的支持情况。一般来说,Redis较新的版本对混合持久化格式的AOF文件修复有较好的支持。

持久化机制的选择与优化

选择持久化机制的考量因素

  1. 数据丢失容忍度:如果对数据丢失非常敏感,几乎不允许丢失任何数据,那么AOF持久化(特别是always同步策略)是较好的选择。如果可以容忍一定时间内的数据丢失,RDB持久化可能更适合,因为它具有更快的恢复速度。
  2. 性能要求:如果应用对Redis的性能要求极高,对数据丢失有一定容忍度,RDB持久化的BGSAVE方式以及AOF的everysecno同步策略可能更符合需求。而AOF的always同步策略会因为频繁的磁盘I/O操作而对性能产生较大影响。
  3. 数据恢复速度:对于大规模数据的恢复,RDB由于是直接加载内存快照,恢复速度通常比AOF快。但如果AOF文件经过合理的重写优化,其恢复速度也可以接受。
  4. 存储设备:如果存储设备的I/O性能较差,AOF的频繁写操作可能会导致性能瓶颈,此时RDB可能更合适。相反,如果存储设备具有较高的I/O性能,AOF可以更好地保证数据的安全性。

持久化机制的优化

  1. RDB优化
    • 合理设置save条件:根据应用的写操作频率,合理设置save参数中的时间和修改键的数量,避免过于频繁或过于稀疏地触发RDB持久化。例如,如果应用写操作较少,可以适当延长时间间隔和增加修改键的数量。
    • 定期备份RDB文件:将RDB文件定期备份到其他存储设备,以防止磁盘故障导致数据丢失。可以使用脚本定时将RDB文件拷贝到远程存储或其他磁盘。
  2. AOF优化
    • 选择合适的同步策略:根据应用对数据安全性和性能的要求,选择合适的appendfsync同步策略。在大多数情况下,everysec策略是一个较好的平衡。
    • 定期重写AOF文件:通过合理设置auto - aof - rewrite - min - sizeauto - aof - rewrite - percentage参数,确保AOF文件在合适的时机进行重写,避免AOF文件过大影响性能和恢复速度。
    • 使用外部工具压缩AOF文件:除了Redis自身的重写机制,还可以使用一些外部工具(如aof - rewrite - tool等)对AOF文件进行进一步的压缩和优化,但在使用外部工具时需要谨慎,确保不会损坏AOF文件。

在实际应用中,可能需要根据具体的业务场景和需求,灵活选择和优化Redis的持久化机制,以达到数据安全、性能和存储成本之间的最佳平衡。同时,要定期对持久化文件进行检查和维护,确保在需要恢复数据时能够顺利进行。