Redis 是内存数据库,它是基于内存进行读写的,这也是它效率高的重要原因之一。
如果不将它的数据设置过期,那么它将会一直保存在内存中,除非手动将其移除或者手动关闭redis服务进程。数据才会从内存中消失。这个时候如果没有对数据进行持久化操作,我们的数据将会永久性的丢失。所以redis为我们提供了数据的持久化方式,这样当我们的reids服务器在不可逆情况下产生宕机时,重启后数据仍能够被重新读取到redis服务中。
Redis提供了两种数据持久化的方式
- RDB(Redis DataBase)
- AOF(Append Only File)
RDB
RDB持久化是在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失。
注意:子进程的持久化基于磁盘的IO操作并不影响redis服务的内存存储操纵,两者会始终保持高度一致,此过程并不会发生数据不一致问题。
fork
Fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量,环境变量,程序计数器等),数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
这也是保证数据一致性的重要原因。
RDB方式持久化的相关配置
################################ SNAPSHOTTING ################################
#
# Save the DB on disk:
#
# 持久化操作设置 900秒内触发一次请求进行持久化,300秒内触发10次请求进行持久化操作,60s内触发10000次请求进行持久化操作
save 900 1
save 300 10
save 60 10000
# 持久化出现错误后,是否依然进行继续进行工作
stop-writes-on-bgsave-error yes
# 使用压缩rdb文件 yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁盘空间
rdbcompression yes
# 是否校验rdb文件,更有利于文件的容错性,但是在保存rdb文件的时候,会有大概10%的性能损耗
rdbchecksum yes
# dbfilename的文件名
dbfilename dump.rdb
# dbfilename文件的存放位置
dir ./
持久化操作
-
通过配置文件自动触发
# 持久化操作设置 900秒内触发一次请求进行持久化,300秒内触发10次请求进行持久化操作,60s内触发10000次请求进行持久化操作 save 900 1 save 300 10 save 60 10000
-
通过
save
或bgsave
手动触发127.0.0.1:6379> save # 此方法是阻塞式的,不是以fork的方式来进行复制,而是主进程来进行持久化。 OK 127.0.0.1:6379> bgsave # 此方法将会在后台以异步的方式进行 Background saving started
-
服务关闭时自动触发
redis服务读取快照
只需要获取dump.rdb文件的目录所在处,再移动至redis.server的安装目录启动即可(dump.rdb一般保存在安装目录)
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"
127.0.0.1:6379> exit
[root@localhost ~]# cd /usr/local/bin
[root@localhost bin]# ls
dump.rdb redis-benchmark redis-check-rdb redis-sentinel
myconf redis-check-aof redis-cli redis-server
优缺点
1、适合大规模的数据恢复,速度快
2、适合对数据完整性和一致性要求不高
3、在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改
4、Fork的时候,内存中的数据被克隆了一份,这时会有两倍内存占用
AOF
AOF持久化是以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件,但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
AOP的相关配置
############################## APPEND ONLY MODE ###############################
# 是否使用AOF持久化方式
appendonly no
# appendfilename的文件名
appendfilename "appendonly.aof"
# 持久化策略
# appendfsync always # always 同步持久化:每次请求追加,
appendfsync everysec # everysec 异步持久化:每秒追加。
# appendfsync no # no 不持久化
# 持久化时(RDB的save | aof重写)是否可以运用Appendfsync,用默认no即可,保证数据安全性
no-appendfsync-on-rewrite no
# 设置重写的基准值
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 指定当发生AOF文件末尾截断时,加载文件还是报错退出
aof-load-truncated yes
# 开启混合持久化,更快的AOF重写和启动时数据恢复
aof-use-rdb-preamble yes
开启AOF持久化方式
在配置文件中手动设置
# 是否使用AOF持久化方式
appendonly yes
读取appendonly.aof
- 将appendonly.conf文件放在redis.server的安装目录即可(一般默认即为此处)
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"
使用appendonly.aof进行数据恢复
使用此命令进行恢复
redis-check-aof --fix appendonly.aof
重启redis服务
AOF的重写
当服务开启后,AOF根据同步策略会对请求进行追加至appendonly.aof文件中,而达到指定的数据量大小时。为了减少资源浪费,redis会自动触发重写。
AOF的重写触发后,将会fork一个新的子进程,然后遍历处redis内存中的所有数据,根据数据进行set写入临时文件中,再用临时文件替换原来的appendonly.aof文件。
触发重写条件
命令触发
bgrewriteaof
自动触发
(通过配置文件配置)
# 设置重写的基准值
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
优缺点
- 如果持久化策略设置为always同步,相对数据安全性比RDB方式更高,但是运行效率比RDB更低。
- 数据量相同时,AOF的占用内存会比RDB更大
- AOF方式进行持久化时会持续化IO,占用系统资源和fork时会对主线程短时间的IO阻塞。
总结
-
RDB通过快照的方式,每次fork一个新的子进程来对内存的数据写入临时文件,再替换原来的dump.rdb文件。
-
AOF通过日志的方式,记录每次的写操作,当数据量达到一定量级时,触发重写机制,fork出一个新的线程,将内存中的数据写入临时文件,替换原有的appendonly.aof。
-
不管事RDB形式还是AOF形式,他们都应该是通过fork出一个新的子进程的方式来进行持久化的,即命令为
bgsaveof
或者byrewriteaof
。 -
同时开启两种持久化方式
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
- RDB 的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有
AOF可能潜在的Bug,留着作为一个万一的手段。
-
性能建议
- 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留 save 900 1 这条规则。
- 如果Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。
- 如果不Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也可以,能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB文件,载入较新的那个,微博就是这种架构。