Redis的持久化
redis所有的数据都是保存在内存中,当redis进程挂了或者机器出现宕机等异常情况,如果不讲数据保存在硬盘中,那么数据将会丢失。redis就提供了持久化的功能,就是可以将所有的数据修改也会异步更新在磁盘上。
Redis的持久化方式
Redis提供了两种持久化的方式:
1. RDB:这是一种快照的方式,它将Redis某时间点的数据都进行快照存储。比如Mysql Dump也是这种方式。
2. AOF:写日志的方式,记录每次对服务器写的操作, 当服务器重启的时候会重新执行这些命令来恢复原始的数据。例如Mysql binlog,Hbase HLog。
RDB(Redis DataBase)
一. RDB介绍
在 Redis 运行时, RDB 将当前内存中的数据库生成一个Snapshot快照保存到磁盘文件中, 在 Redis 重启动时, RDB 可以通过载入 RDB 文件来还原数据库的状态。
二. RDB的触发方式:
RDB 有三种触发方式,其实就是生成RDB文件的方式。
1. save命令:这个是同步方式,会阻塞当前其他的命令执行,直到save命令执行完毕。
2. bgsave命令:这个是一个异步命令,会单独在后台去执行,不会阻塞其他命令。它其实是新创建(fork)了一个子进程,这个进程就是负责生成RDB文件的工作。
3. 自动方式:就是在某些条件下会自动去生成,这个是在Redis配置文件中去设置。
这里说一下上面配置时间策略具体的意思。
1. 900秒内有一个key变化
2. 300秒内10个key变化
3. 60秒内有10000个key发生变化。
三. RDB的文件生成策略
如果存在老的RDB文件,那么会生成一个临时文件,然后新生成的文件就会替换老的RDB文件。
四. Save和Bgsave命令的区别
命令 | save | bgsave |
IO类型 | 同步 | 异步 |
是否阻塞 | 是 | 是(阻塞发生在fork时候,不过fork是非常快的) |
时间复杂度 | O(n) | O(n) |
优点 | 不会消耗额外内存 | 不会阻塞客户端命令执行 |
缺点 | 会阻塞客户端命令执行 | 需要fork 消耗内存 |
五. RDB的持久化配置选项
# 时间策略 save 900 1 save 300 10 save 60 10000 # RDB文件名称 dbfilename dump.rdb # 文件保存路径 dir /home/work/app/redis/data/ # 如果持久化出错,主进程是否停止写入 stop-writes-on-bgsave-error yes # 是否压缩 rdbcompression yes # 导入时是否检查 rdbchecksum yes
六. RDB最佳配置
这里RDB最佳配置也是相对而言,具体也可以根据线上环境和具体业务来调整。这里只是一般通常配置
# RDB文件名称加上端口号进行文件的区别,现在机器多核,会运行多个Redis实例可以充分利用多核优势,这样产生多个RDB文件进行区分
dbfilename dump-${port}.rdb
# 文件保存路径
dir /空间大的路径
# 如果持久化出错,主进程是否停止写入,这里选择开启,如果bgsave发生错误就不能正常的写入,说明redis就可能会出现问题了,这时候应该停止写入
stop-writes-on-bgsave-error yes
# 是否压缩,采用压缩,这样文件会比较小,而且Redis主从复制之间会有拷贝
rdbcompression yes
七. 触发机制-不容忽略方式
1. 全量复制:有时候没有执行save,bgsave命令或者配置文件设置RDB自动生成方式时候也会生成RDB文件,那是因为可能主从之间会有全量复制导致生成的,主节点会自动生成RDB文件。
2. debug reload:进行debug级别的重启,不会将Redis内存进行清空的重启,这个时候也会触发RDB文件的生成。
3. shutdown save:这个也会导致RDB文件的生成。
AOF
一. AOF介绍
Redis的另一种持久化方式就是AOF(Append Only File),与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF是通过保存Redis所执行的写命令来记录数据库状态的。在了解AOF之前先看看RDB所存在的问题。
二. RDB所存在的问题
1. 耗时,耗性能,每次保存 RDB 的时候Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。 在数据集比较庞大时fork() 可能会非常耗时,比如写的数据量很大,内存页设置的比较大,会产生很大的内存消耗,造成服务器在某某毫秒内停止处理客户端, 如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至会更长。同时RDB也是一个IO的过程,RDB文件很大拷贝速度就会很慢。
2. 不可控,容易丢失数据,服务器在发生故障时候会丢失数据。
下面是一个时间线流程操作说明
T3和T4时间段所操作的命令都会丢失。因为无法知道什么时候会宕机及其他异常情况。如果使用save和bgsave做定时备份也是无法保障数据不会丢失。
如果避免RDB所出现的问题,这里就需要AOF。
AOF运行工作图
客户端每执行一条命令都会被记录在AOF文件中。当Redis服务器宕机后,Redis可以从AOF文件中恢复数据。
三. AOF三种策略
Redis提供了三种决定AOF写入的频率。
Redis在执行写入AOF日志文件的时候不是直接去写入文件中,而是先记录在硬盘的缓冲区,缓冲区会根据一些刷新策略来决定什么时候刷新到磁盘中,这样会提高写入的效率。
1. always: 每次写入一条数据就立即将这个数据对应的写日志fsync到磁盘上去,虽然可以确保Redis里的数据一条都不丢,但是性能非常差,吞吐量很低。
2. everysec:每秒将缓冲中的数据fsync到磁盘,这个比较最常用的,生产环境一般都这么配置,而且性能很高。但是缺点就是不像always那样保证每个命令都会记录,Redis服务器出现故障有可能会丢失一秒钟的数据。
3. no: 仅仅redis负责将数据写入缓冲区,什么时候刷新到磁盘中是根据操作系统自己决定。这种一般不会使用。
三种策略对比
命令 | always | everysec | no |
优点 | 不丢失数据 | 每秒一次fsync | 不用管 |
缺点 | IO开销大,一般SATA盘每秒只有几百TPS | 可能会丢一秒的数据 | 不可控 |
在保证数据不丢失,硬盘开销方面作了权衡,使用everysec策略会更加合适。
四. AOF 重写实现原理
AOF策略保证Redis命令写入到AOF文件中,不过随着命令逐步的写入,时间的推移,并发量写入量逐步的变大,AOF文件的体积也会逐渐的变大。这时候使用AOF进行恢复数据会变的很慢。当AOF文件无限制的变大,无论是对于文件的管理,写入命令的速度都会有一定的影响。所以Redis提供了一个AOF重写的机制来解决这些问题。
根据上图分析原生AOF那一列最上面写入三条命令,都是对同一个key进行操作的,最后一次将前面两次写入的值更新了,实际上只有最后一次修改对我们是有用的。中间的incr自增命令也是一样的。下面三次rpush也是可以优化的,可以统一成一个命令。同时对于一些过期的数据,当时写入到AOF文件中,但是某个时间点已经过期了,这个key内部会执行一个删除命令操作并同步到AOF文件中,这个在AOF重写中是没有用的。
所以可以得出AOF重写的作用:
将过期的,没有用的,重复的命令,以及一些可以优化的命令都进行一个精简,来缩小AOF文件的体积,减少对磁盘的占用量。同时文件体积缩小也可以加速Redis恢复的速度。
五. AOF 重写的两种方式
1. 手动触发(Bgrewriteaof命令):这个命令有点类似于RDB中的bgsave,Bgrewriteaof 命令会fork一个子进程用于异步执行一个 AOF(AppendOnly File) 文件重写操作,重写会创建一个当前 AOF 文件的体积优化版本。即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。
注意:从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。
Bgrewriteaof命令工作图
1. 自动触发:
自动触发与AOF重写配置几个参数有关。
1)auto-aof-rewrite-min-size:AOF文件重写需要的最小的大小。就是说当AOF文件至少多大体积的时候在开始进行重写,默认64M。
2)auto-aof-rewrite-percentage:AOF文件增长率。当进行过了一次重写,下一次进行重写的时候看这个AOF文件的增长率,默认100。
3)aof_current_size:当前AOF文件的大小(单位:字节)。
4)aof_base_size:上一次操作或者重写后的AOF文件大小(单位:字节)。
触发条件 :
aof_current_size > auto-aof-rewrite-min-size 并且 (aof_current_size - aof_base_size) / aof_base_size >= auto-aof-rewrite-percentage。其中,aof_current_size是当前AOF文件大小,aof_base_size 是上一次重写后AOF文件的大小,这两部分的信息可从info Persistence处获取。
AOF重写流程图
六. AOF配置项
# 打开AOF持久化机制,默认是no
appendonly yes
# AOF文件名
appendfilename appendonly-${port}.aof
# AOF同步策略
appendfsync everysec
# 文件保存路径
dir /空间大的路径
#在AOF重写时候是否做正常的AOF的append操作,如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造# 成阻塞(因为没有竞争磁盘),但是如果这个时候redis挂掉,就会丢失数据。丢失多少数据呢?在linux的操作系统的默认设置下,最多会丢失30s的数据。
no-appendfsync-on-rewrite yes
七. AOF优缺点
1. 优点
1)AOF机制可以带来更高的数据安全性。
2)由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容
3)AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。
2. 缺点
1)对于相同数量的数据集而言,AOF文件通常要大于RDB文件。RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快
2)AOF对系统开销有一定的影响。AOF常用的持久化策略是everysec,在这种策略下,fsync同步文件操作由专门线程每秒调用一次。当系统磁盘较忙时,会造成Redis主线程阻塞,所以在Redis的负载较高情况下,RDB 比 AOF 具好更好的性能保证。
RDB和AOF的选择
RDB和AOF对比
命令 | RDB | AOF |
启动优先级(Redis同时开启了RDB和AOF,Redis先加载哪个) | 低 | 高 |
体积 | 小(RDB使用二进制模式存储,并做了压缩,体积比较小) | 大 |
恢复速度 | 快(体积比较小所以恢复速度快) | 慢 |
数据安全性 | 丢数据(RDB快照所以容易丢失数据) | 根据策略来决定 |
命令操作的轻重(比如是否耗时,耗资源) | 重(备份Redis时间点全部数据) | 轻 |
RDB和AOF的选择
如果可以忍受一小段时间内数据的丢失,毫无疑问使用 RDB 是最好的,定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快,而且使用 RDB 还可以避免 AOF 一些隐藏的 bug;否则就使用 AOF 重写。但是一般情况下建议不要单独使用某一种持久化机制,而是应该两种一起用,在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。Redis后期官方可能都有将两种持久化方式整合为一种持久化模型。
参考来源及其他资料