概念
持久化的功能:Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘;当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。
Redis持久化分为RDB持久化和AOF持久化:前者将当前数据保存到硬盘,后者则是将每次执行的写命令保存到硬盘;由于AOF持久化的实时性更好,即当进程意外退出时丢失的数据更少,因此AOF是目前主流的持久化方式,不过RDB持久化仍然有其用武之地
RDB持久化
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。当Redis重新启动时,可以读取快照文件恢复数据。
触发条件
对RDB来说,有手动触发和自动触发两种情况
手动触发
手动触发对应save和bgsave命令,两者都会生成RDB文件
save
save命令会阻塞Redis服务器进程,直到RDB文件创建完毕为止,在Redis服务器阻塞期间,服务器不能处理任何命令请求。
执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。bgsave
执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体操作是Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。
bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃。此外,在自动触发RDB持久化时,Redis也会选择bgsave而不是save来进行持久化。
自动触发
save m n
表示m秒内数据集存在n次修改时,自动触发bgsave
配置文件如下:
触发机制:
- 满足save的规则时,会自动触发RDB
- 从节点执行全量复制操作,主节点自动执行bgsave生成RDB文件并发送给子节点
- 执行debug reload命令重新加载Redis时,也会自动触发save操作。
- 执行flushall命令,也会生成rdb文件,但里面是空的
- 退出redis,也会产生rdb文件
备份就自动生成dump.rdb文件
如果想关闭自动RDB持久化,在配置文件删除save m n
的配置即可
工作流程
图片来自学习Redis持久化
- 执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接返回。主要是基于性能方面的考虑:两个并发的子进程同时执行大量的磁盘写操作,可能引起严重的性能问题。
- 父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作的耗时,单位为微秒。
- 父进程fork完成后,bgsave命令返回”Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。
- 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成对原有文件执行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
- 进程发送信号给父进程表示完成,父进程更新统计信息,
恢复数据
将rdb文件放在redis启动目录,,redis启动时会自动检查dump.rdb恢复其中的数据
查看需要存在的位置
1
2
3
4127.0.0.1:6379> config get dir
1) "dir"
2) "/Redis"
# 如果在这个目录下存在dump.rdb文件,启动就会自动恢复其中数据
RDB优缺点
优点
- RDB是一个紧凑的二进制文件,它保存了redis 在某个时间点上的数据集。这种文件非常适合用于进行备份和灾难恢复。
- 生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
- RDB 在恢复大数据集的速度比 AOF 的恢复速度要快。
缺点
- RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,如果不采用压缩算法(内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑),频繁执行成本过高(影响性能)
- RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题(版本不兼容)
- 在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改(数据有丢失)
使用场景
- 数据备份
- 可容忍部分数据丢失
- 跨数据中心的容灾备份
AOF持久化
RDB持久化是将进程数据写入文件,而AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中;当Redis重启时再次执行AOF文件中的命令来恢复数据。
与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。
配置文件如下
默认不开启,将appendonly 改为yes就开启了aof。
默认文件名是appendonly.aof。保存路径同RDB持久化方式一致。
如果aof文件有错位,这是redis是无法启动的,需要修改这个aof文件才能正常启动
redis提供了一个工具redis-check-aof --fix
进行修复
执行流程
由于需要记录Redis的每条写命令,因此AOF不需要触发,
AOF的执行流程包括:
- 命令追加(append):将Redis的写命令追加到缓冲区aof_buf;
- 文件写入(write)和文件同步(sync):根据不同的同步策略将aof_buf中的内容同步到硬盘;
- 文件重写(rewrite):定期重写AOF文件,达到压缩的目的。
命令追加
Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。
命令追加的格式是Redis命令请求的协议格式,它是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点;具体格式略。在AOF文件中,除了用于指定数据库的select命令(如select 0 为选中0号数据库)是由Redis添加的,其他都是客户端发送来的写命令。
文件写入和文件同步
Redis提供了多种AOF缓冲区同步文件策略,由参数appendfsync控制。
说明:
为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。
这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性
不同的含义:
- always:命令写入aof_buf后调用系统fsync操作同步到AOF文件,fsync完成后线程返回
- no:命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步,同步硬盘操作由操作系统负责,通常同步周期最长30秒
- everysec:命令写入aof_buf后调用系统write操作,write完成后线程返回。fsync同步文件操作由专门线程每秒调用一次。
everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置。
文件重写
AOF采用文件追加方式,文件会越来越大。为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。
文件重写是指定期重写AOF文件,减小AOF文件的体积。需要注意的是,AOF重写是把Redis进程内的数据转化为写命令,同步到新的AOF文件;不会对旧的AOF文件进行任何读取、写入操作。
重写后的AOF文件为什么可以变小?有如下原因:
- 进程内已经超时的数据不再写入文件
- 旧的AOF文件含有有效命令,如del key1、hdel key2、srem keys、set a111、set a222等。重写使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令。
- 多条写命令可以合并为一下,如:lpush list a、lpush list b、lpush list c可以转化为:lpush list a b c。为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash、zset等类型操作,以64个元素为界拆分为多条。
AOF重写降低了文件占用空间,除此之外,另一个目的是:更小的AOF文件可以更快被Redis加载。
文件重写的触发机制
AOF重写过程可以手动触发和自动触发。
手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。
自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机
- auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认 为64MB。
- auto-aof-rewrite-percentage:代表当前AOF文件空间 (aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值。
自动触发时机:aof_current_size > auto-aof-rewrite-minsize &&(aof_current_size-aof_base_size)/ aof_base_size >= auto-aof-rewritepercentage
其中aof_current_size和aof_base_size可以在info Persistence统计信息中查看
AOF优缺点
优点:
- 备份机制更稳健,丢失数据概率更低
- 可读的日志文本,通过操作AOF稳健,可以处理误操作。
- AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损。
缺点:
- 比起RDB更占用磁盘空间。
- 回复备份的速度慢。
- 每次读写同步的话,有一定的性能压力。
- 存在BUG,可能不能完全恢复一摸一样的数据。
RDB和AOF同时开启
RDB和AOF同时开启时,逻辑如下
图片来自redis之持久化
参考文献
Redis三大问题