Redis速度快,很大原因是它的数据都存储在内存中。如果断电或宕机,会导致内存中的数据丢失。
为了实现重启后数据不丢失,Redis提供了两种持久化方案,一种RDB快照(Redis DataBase),一种AOF(Append Only File)。
持久化是Redis和Memcache的主要区别之一。
一、RDB
1.1 RDB简介
RDB是Redis默认的持久化方案(注意如果开启了AOF,则优先用AOF)。
当满足一定条件时,会把当前内存里的数据写入磁盘,生成一个快照文件dump.rdb。
Redis重启会通过加载dump.rdb文件恢复数据。
1.2 RDB触发
1、自动触发RDB
a)配置规则触发
redis.conf配置文件中,搜索SNAPSHOTTING,这部分配置项中定义了数据保存到磁盘的触发频率:
save 900 1 #900秒内至少有一个key被修改(包括添加)
save 300 10 #400秒内至少有10个key被修改
save 60 10000 #60秒内至少有10000个key被修改
满足以上任意一个就会触发。
如果不需要rdb方案,可以注释save或者配置成空字符串""。
用lastsave命令可以查看最近一次成功生成快照的时间。
查看redis.config中配置的rdb文件位置和目录(默认在安装根目录下):
#文件路径
dir ./
#文件名称
dbfilename dump.rdb
#是否以LZF压缩rdb文件
rdbcompression yes
#开启数据校验
rdbchecksum yes
除了根据配置触发生成RDB,RDB还有两种自动触发方式:
b) shutdown,服务器正常关闭时会触发
c) flushall,删除所有数据时,会触发。rdb文件会被清空。
2、手动触发RDB
如果需要重启服务或迁移数据,就需要手动触发RDB快照保存。
Redis提供了两条命令:
a) save
save在生成快照时,会阻塞当前Redis服务器,Redis不能处理其他命令。
如果内存中的数据比较多,会造成Redis长时间的阻塞,生产环境不建议使用这个命令。
为了解决这个问题,Redis提供了第二种方式。
b) bgsave
执行bgsave时,Redis会在后台异步进行快照操作,写快照的同时还可以响应客户端请求。
具体操作是Redis进程执行fork操作创建子进程,RDB持久化的过程由子进程负责,完成后自动结束。
不会记录fork之后产生的数据(所以会存在部分数据丢失的情况)。
阻塞只发生在fork阶段创建子线程的时候,一般时间很短。
(PS:我们常说redis是单线程的,并不是指redis只会有一个线程,而是指redis处理请求(增删改查)时只会使用一个线程去执行,就比如redis在执行其他操作的时候,可能会开启多个进程或线程,如持久化:redis执行BGSAVE指令)
3、RDB实现数据的恢复
1、shutdown持久化
添加键值
redis> set k1 1
redis> set k2 2
redis> set k3 3
redis> set k4 4
redis> set k5 5
停止服务器,触发RDB
redis> shutdown
备份dump.rdb文件
cp dump.rdb dump.rdb.bak
启动服务器
/usr/local/soft/redis-6.0.9/src/redis-server /usr/local/soft/redis-6.0.9/redis.conf
查看数据都在:
redis> keys *
2、模拟数据丢失
模拟数据丢失(删库跑路了),触发save
redis> flushall
停止服务器
redis> shutdown
查看数据,啥都没有了:
redis> keys *
3、通过备份文件恢复数据
停止服务器:
redis> shutdown
重命名备份文件:
mv dump.rdb.bak dump.rdb
启动服务器:
/usr/local/soft/redis-6.0.9/src/redis-server /usr/local/soft/redis-6.0.9/redis.conf
查看数据:
redis> keys *
数据通过备份的rdb文件得到了恢复。
4、RDB文件的优势和劣势
优势:
1)RDB是一个非常紧凑(经过了compact压缩)的文件,它保存了redis在某个时间点上的数据集。
这种文件非常适合用于进行备份和恢复。
2)生成RDB文件时,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
3)RDB是基于快照的方式,在恢复大数据集时的速度比AOF的恢复速度快
劣势:
1)RDB方式数据无法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,频繁执行成本太高。
2)在一定的间隔时间做一次备份,所以如果redis意外down掉,而非正常shutdown的话,就会丢失最后一次快照之后的所有修改(数据有丢失)。
如果数据比较重要,希望将损失降到最小,则可以使用AOF方式进行持久化。
二、AOF
redis默认不开启AOF,AOF采用日志的形式来记录每个操作,并追加到文件中。
开启后,执行更改Redis数据的命令时,就会把命令写入到每个AOF文件里。
Redis重启时会根据日志文件的内容,把写指令从前到后执行一次,以完成数据的恢复工作。
1、AOF配置
配置文件 redis.conf
#开关
appendonly no
#文件名
appendfilename "appendonly.aof"
参数appendonly默认为no,Redis默认只开启RDB持久化,开启AOF需要修改为yes。
appendfilename是aof的文件名,路径也是通过dir参数配置。
问题:AOF是数据实时持久化到磁盘吗?
由于操作系统的缓存限制,AOF数据并没有真正写入磁盘,而是进入了系统的硬盘缓存。
问题:什么时候把缓冲区的内容写入到AOF文件?
参数: appendfsync everysec
此参数用于配置AOF的持久化策略(从硬盘缓存写到磁盘),默认everysec。
- no:由操作系统决定何时写入磁盘,Linux 默认 30s 写入一次数据至磁盘(不推荐)
- everysec:每秒钟写入一次磁盘,最多丢失一秒的数据(默认)
- always:每条 Redis 操作命令都会写入磁盘,最多丢失一条数据(谨慎使用)
通常选择everysec,每秒执行一次刷盘,兼顾安全和效率。
问题:文件越来越大,怎么办?
由于AOF持久化是Redis不断的把写命令记录到AOF文件,随着Redis不断的使用,AOF的文件会越来越大。
AOF文件越大,占用服务器内存就越大,并且会导致AOF恢复数据需要的时间越长。
例如计数器增加100万次,100万个命令都记录进去了,但是最终结果只有1个。
为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过了所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。
可以使用命令bgrewriteaof来重写。
AOF文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件去替换原来的AOF文件。
#重写触发机制
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
参数 auto-aof-rewrite-percentage:
默认为100。aof自动重写配置,当目前aof文件的大小超过上一次重写的aof文件大小的此百分之比,那么就进行重写。即当aof文件增长到一定大小时,Redis能够调用bgrewriteof对日志文件进行重写。
当前AOF文件大小是上次日志重写得到AOF文件大小的两倍(设置为100)时,自动启动新的日志重写过程。
参数auto-aof-rewrite-min-size:
默认为64M,设置允许重写的最小aof文件大小限制,避免达到了约定百分比但文件还是很小的情况仍然进行重写。
问题:重写过程中,AOF文件被更改了怎么办?
重写AOF过程中,同时有新增加的写命令,会先写到重写缓存中,等到AOF重写完成后,再将这部分追加的内容写入AOF。
2、AOF数据恢复
如上配置开启AOF,开启之后变动的数据,在重启redis后就可以进行AOF文件的恢复了。
3、AOF优势与劣势
优势:
1)AOF持久化的方法提供了多种的同步频率,就算使用默认的同步频率每秒同步一次,Redis最多也就丢失1秒的数据。
缺点:
1)对于相同数据,AOF文件通常比RDB文件体积更大。(RDB存的是数据快照,AOF是日志)
2)虽然AOF提供多种同步的频率,默认每秒同步一次的频率也有较高性能。但在搞并发情况下,RDB比AOF消耗资源更少,性能更好。
三、RDB与AOF对比
对于RDB和AOF两种持久化方式,我们应该如何选择呢?
如果可以忍受一小段时间内数据的丢失,毫无疑问使用RDB是最好的,定时生成RDB快照便于进行数据库备份,并且RDB恢复数据集的速度也比AOF恢复速度更快。
否则就使用AOF重写。但是一般情况下不建议单独使用某一种持久化机制,而是两种一起用。
这种情况下,当redis重启时会优先载入AOF文件来恢复原始数据,通常AOF文件保存的数据集比RDB保存的数据集要完整。
概扩就是,希望数据最小丢失,使用AOF。可以允许部分丢失,追求速度,使用RDB。