在数据库(如mysql)和缓存(如redis)的发展中,都会相互借鉴对方的长处来弥补自身的不足。好比mysql做为持久化数据库,为了提升数据的访问速度,会使用缓存技术,当一条sql查询完成后,mysql会使用sql生成一个key,并将这个sql查询的结果缓存到这个key上,若是运行相同的sql,服务器直接从缓存中去获取结果,就不须要再去解析、优化、执行sql了。同时,redis做为缓存,为了解决宕机带了的数据丢失问题,也增长了持久化机制。mysql
Redis支持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出形成的数据丢失问题,当下次重启时利用以前持久化的文件便可实现数据恢复,理解掌握持久化机制对于Redis运维很是重要。linux
今天咱们就聊一聊redis的持久化问题。本期也是面试高频问题,同时也是实际生产必须考虑的问题。面试
默认状况下,只开启RDB。RDB是二进制文件。redis
RDB方式也叫快照方式,这种方式会在必定的触发时机下,将当前redis的内存快照保存到磁盘上的dump.rdb文件中。这个过程当中,主要执行一个命令bgsave
。sql
在必定的条件下触发bgsave
执行数据库
Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,若是存在bgsave
命令直接返回。vim
父进程执行fork操做建立子进程,fork操做过程当中父进程会阻塞,不能响应其余客户端请求。经过info stats
命令查看latest_fork_usec选项,能够获取最近一个fork操做的耗时,单位为微秒。Fork的做用是复制一个与当前进程同样的进程。新进程的全部数据(变量、环境变量、程序计数器等)数值都和原进程一致,可是是一个全新的进程,并做为原进程的子进程。缓存
父进程fork完成后,bgsave
命令返回“Background saving started”信息并再也不阻塞父进程,能够继续响应其余客户端命令。安全
子进程建立RDB文件dump.rdb,根据父进程内存生成临时快RDB文件。bash
使用临时RDB文件对原有RDB文件的原子替换。执行lastsave
命令能够获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项
子进程退出。
################################ SNAPSHOTTING ################################
#900s内,若是至少有一个1key进行了修改,就进行持久化操做
save 900 1
#300s内,若是至少有一个10key进行了修改,就进行持久化操做
save 300 10
#60s内,若是至少有一个10000key进行了修改,就进行持久化操做
save 60 10000
#持久化若是出错,是否还须要继续工做
stop-writes-on-bgsave-error yes
#是否压缩rdb文件,须要消耗一些cpu资源
rdbcompression yes
#保存rdb文件的时候,进行错误的检查校验
rdbchecksum yes
#持久化的文件名字
dbfilename dump.rdb
#rdb文件保存的目录
dir ./
复制代码
触发RDB持久化过程分为手动触发和自动触发。
经过redis-cli
登陆redis后,可使用save
和bgsave
两个命令触发RDB持久化。
save
命令:阻塞当前Redis服务器,直到RDB过程完成为止,对于内存比较大的实例会形成长时间阻塞,线上环境不建议使用。
bgsave
命令:Redis进程执行fork操做建立子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,通常时间很短。
显然bgsave命令是针对save阻塞问题作的优化。所以Redis内部全部的涉及RDB的操做都采用bgsave的方式,而save命令已经废弃。
除了执行命令手动触发以外,Redis内部还存在自动触发RDB的持久化机制。
save m n
的触发条件时,redis会自动执行bgsave
。bgsave
,执行完成以后会将rdb文件发送给slave。shutdown
和flushall
命令时,redis会自动执行bgsave
。能够在redis-cli的命令行执行config set save " "
关闭RDB的持久化机制。
rdb文件会自动恢复。在redis客户端命令行经过config get dir
获取 redis 的安装目录,将备份文件 (dump.rdb) 移动到 安装目录并启动服务便可,redis就会自动加载文件数据至内存了。
Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。根据数据量大小与结构和服务器性能不一样,这个时间也不一样。RDB自己是二进制文件,恢复很是快。一般将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中须要花费20~30秒钟。
127.0.0.1:6379> config get dir #获取redis的目录
1) "dir"
2) "/usr/local/bin" # 将dump.rdb文件放在这个目录下,从新启动redis,就能够自动将数据恢复
复制代码
表明Redis在某个时间点上的数据快照。很是适用于备份,全量复制等场景。好比每6小时执行bgsave备份,并把RDB文件拷贝到远程机器或者文件系统中(如hdfs),用于灾难恢复(对数据完整性和一致性要求不高)
RDB是二进制保存,Redis加载RDB恢复数据远远快于AOF的方式(适合大规模的数据恢复)
RDB方式没办法作到实时持久化/秒级持久化。由于bgsave每次运行都要执行fork操做建立子进程,属于重量级操做(内存中的数据被克隆了一份,大体2倍的膨胀性须要考虑),频繁执行成本太高(影响性能)
RDB文件使用特定二进制格式保存,Redis版本演进过程当中有多个格式的RDB版本,存在老版本Redis服务没法兼容新版RDB格式的问题(版本不兼容)
在必定间隔时间作一次备份,因此若是redis意外down掉的话,就会丢失最后一次快照后的全部修改。
默认状况下,aof是关闭的。AOF命令写入的内容直接是文本协议格式,能够经过vim查看文件内容。
以独立日志的方式记录每次写命令,重启时再从新执行AOF文件中的命令达到恢复数据的目的。AOF的主要做用是解决了数据持久化的实时性,目前已是Redis持久化的主流方式。掌握AOF持久化机制,对兼顾数据安全性和性能很是有帮助。通俗一点的理解就是以日志的形式来记录每一个写操做,将Redis执行过的全部写指令记录下来(读操做不记录),只许追加文件但不能够改写文件,redis启动之初会读取该文件从新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工做。
aof的持久化有三步:命令写入(append)、文件同步(sync)、文件重写(rewrite)。
Rewrite原理 : AOF文件持续增加而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename)。遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操做,并无读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点相似。
############################## APPEND ONLY MODE ###############################
# 默认不开启aop持久化机制,由于RDB对于通常的业务已经够用了
appendonly no
# aof持久化文件名称
appendfilename "appendonly.aof"
# 不执行sync, 彻底依赖操做系统的刷写,通常30秒一次。性能最好,可是持久化没有保障,不推荐
# appendfsync no
# 每次有写命令执行,就会执行一次sync,将命令追加到aof日志文件。保证彻底持久化,不会丢数据,性能也是最差的,不推荐
# appendfsync always
# 每秒钟执行一次sync,将命令追加到aof日志文件。在性能和持久化之间作了折中,推荐。也是默认配置
appendfsync everysec
# 默认不会对aof文件使用BGREWRITEAOF命令进行重写(重写会合并命令,减少aof文件占用的空间)
no-appendfsync-on-rewrite no
# 当aof文件占用的空间超过上一次记录的100%时,而且aof文件每增长64M,就会执行重写(两个条件同时知足)
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 加载aof文件时,若是文件自己有问题(如文件结尾),是否继续加载。yes:继续加载,no:加载出现错误,中止加载,须要修复aof文件后才能加载,这是不能重启redis
aof-load-truncated yes
复制代码
这里须要注意的是触发sync的配置和rewrite的配置。
AOF的appendfsync触发机制是上面配置的三个参数决定的:no、always、everysec。能够根据对性能和持久化的实时性要求,具体配置。若是不知道哪一种合适,就使用默认的everysec,可能会有1s的数据丢失。
aof文件的重写过程的触发,由上面配置的rewrite参数决定。能够手动触发和自动触发。
经过redis-cli
登陆redis后,可使用bgrewriteaof
命令触发aof的重写机制。
根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数肯定自动触发时机,当两个条件同时知足时,就会触发重写。
redis启动时,首先判断aof功能是否开启,若是开启而且存在aof持久化文件,则只会使用aof文件进行数据恢复,而不会使用rdb文件进行数据恢复。
使用aof文件恢复时,AOF文件可能存在结尾不完整的状况,好比机器忽然掉电致使AOF尾部文件命令写入不全。Redis为咱们提供了aof-load-truncated配置来兼容这种状况,默认开启。加载AOF时,当遇到此问题时会忽略并继续启动。
若是关闭aof-load-truncated配置,当aof文件不完整时,则redis会启动失败,这时使用客户端链接也是失败的:
[root@redis ~]# redis-cli -p 6379
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected> exit
[root@redis ~]#
复制代码
对于错误格式的AOF文件,能够先进行备份,而后采用redis安装目录下的redis-check-aof
命令修复aof文件,修复后使用linux的命令diff -u
对比数据的差别,找出丢失的数据,有些能够人工修改补全。
[root@redis ~]# redis-check-aof --fix appendonly.aof
0x a4: Expected \n\r, got:6461
AOF analyzed: size=185, ok_up_to=139, diff=46
This will shrink the AOF form 185 bytes, with 46 bytes, to 139 bytes
Continue? [y/N]: y # 输入y,赞成修改
Successfully truncated AOF
[root@redis ~]#
复制代码
一、RDB持久化方式可以在指定的时间间隔内对数据进行快照存储,默认开启。
二、AOF持久化方式记录每次对服务器写操做,当服务器重启的时候会从新执行这些命令来恢复原始的数据。AOF持久化会追加保存每次写的操做到文件末尾, Redis还能对AOF文件进行后台重写(rewiter),使得AOF文件的体积不至于过大。默认不开启。
三、若是每次重启机器,都有单独的服务将mysql中的数据加载到redis中,也能够不使用任何持久化。
四、同时开启两种持久化方式
五、性能建议
save 900 1
这条规则。auto-aof-rewrite-min-size 64mb
)过小了,能够设到5G以上;默认超过原大小100%大小重写能够改到适当的数值。完成,收工!
【传播知识,共享价值】,感谢小伙伴们的关注和支持,我是【诸葛小猿】,一个彷徨中奋斗的互联网民工!!!