您的位置:首页 > 数据库 > Redis

Redis持久化方式RDB和AOF

2017-06-10 20:20 645 查看

Redis 持久化

RDB(快照)

    优点 

rdb是可进行压缩的二进制文件,表示Redis在某一个时间点的数据快照。非常使用与备份,灾难恢复等场景.比如使用定时任务执行bgsave并备份rdb到server或其他文件系统中,用于恢复数据.

rdb加载速度快于AOF方式

    缺点

RDB不可以做到实时持久化,容易造成数据丢失,假如频繁使用bgsave强行实时持久化,会非常影响性能,因为创建fork子进程也是有阻塞产生的

RDB使用特定的二进制保存,随着redis的不断更新,会有多个格式的RDB版本,会产生兼容问题

  2. AOF(追加)

    优点

比RDB要可靠,可以定制不同的fsync策略(appendfsync everysec/no/always),默认是appendfsync everysec,每秒fsync一次,意味着最多丢失1s的数据

AOF是一个纯追加的文件,遇到宕机基本也不会影响磁盘上的aof日志文件

档aof太大时,redis会自动进行重写(重写在一个新的文件,与此同时reids会继续往旧的aof文件追加日志信息,当新文件写完时会用新文件覆盖旧文件,之后日志信息开始往新文件追加)

    缺点

相同数据集,aof文件要大于rdb文件

AOF速度稍慢与RDB

RDB 

 RDB持久化是把当前进程数据生成的快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发

  1.手动触发,使用save和bgsave命令

save:阻塞当前redis服务器,直到持久化完成为止,对于内存较大的实例会造成长时间的阻塞,线上环境禁止使用,已经被废弃.

root@e7576f2fbb11:/# redis-cli save
OK
root@e7576f2fbb11:/# redis-cli info|grep save        #查看持久化相关信息
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1497083505
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
root@e7576f2fbb11:/# tail -n 4 /var/log/redis/redis-server.log
61:C 10 Jun 08:20:46.257 * DB saved on disk
61:C 10 Jun 08:20:46.258 * RDB: 0 MB of memory used by copy-on-write
29:M 10 Jun 08:20:46.316 * Background saving terminated with success
29:M 10 Jun 08:31:45.676 * DB saved on disk            ###运行redis-cli save对应的redis服务日志


bgsave: redis进程执行fork操作创建子进程,RDB持久化由这个子进程负责,完成后自动结束.阻塞仅仅会发生在fork阶段,时间非常非常的短,bgsave是对save的优化.

root@e7576f2fbb11:/# redis-cli bgsave
Background saving started
root@e7576f2fbb11:/# redis-cli info|grep fork
latest_fork_usec:771                  #####最近一次fork子进程阻塞用的时间us
root@e7576f2fbb11:/# redis-cli info|grep save     #####获取持久化相关信息
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1497084106             ####最后一个RDB时间
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
root@e7576f2fbb11:/# tail -n 4 /var/log/redis/redis-server.log    ####使用bgsave持久化redis服务产生的日志
29:M 10 Jun 08:41:46.346 * Background saving started by pid 77
77:C 10 Jun 08:41:46.380 * DB saved on disk
77:C 10 Jun 08:41:46.381 * RDB: 0 MB of memory used by copy-on-write
29:M 10 Jun 08:41:46.385 * Background saving terminated with success


  2.自动触发

    2.1 通过reids.conf配置动触发bgsave

    2.2 当从节点执行全量复制操作时,主节点自动执行bgsave生成bgsave RDB文件并发送给从节点.

    2.3 当使用redis-cli shutdown关闭redis服务时,如果没有开启AOF持久化功能则也会自动执行bgsave

root@e7576f2fbb11:/# grep 'save' /etc/redis/redis.conf
#   save <seconds> <changes>
#   Will save the DB if both the given number of seconds and the given
#   In the example below the behaviour will be to save:
#   Note: you can disable saving completely by commenting out all "save" lines.
#   It is also possible to remove all the previously configured save
#   points by adding a save directive with a single empty string argument
#   save ""
save 900 1        ###900s内至少一次改动,自动触发bgsave
save 300 10        ###300s内至少10次改动,自动触发bgsave
save 60 10000      ###60s内至少10000次改动,自动触发bgsave
# save ""        ###如果最后一行是save ""则上面自动触发bgsave规则会失效


  3.bgsave运作流程

执行bgsave命令后,redis主进程判断当前是否存在正在执行的(AOF或者RDB)子进程,如果存在则直接返回bgsave命令.

root@e7576f2fbb11:/# redis-cli bgsave;redis-cli bgsave
Background saving started
(error) ERR Background save already in progress

父进程fork子进程过程中,父进程会短暂的阻塞,通过redis-cli info|grep fork可以获得最近一个fork的操作耗时,单位为us,微秒.

父进程fork子进程成功后,返回Background saving started,并停止阻塞主进程,可以继续响应其它指令.

子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原有文件进行原子替换。执行lastsave命令可以获取最后一次RDB生成的时间.

子进程发送信号给父进程表示完成,父进程更新统计信息.redis-cli info可以查看redis状态.

  4.RDB文件相关信息

  

root@e7576f2fbb11:/# egrep -i "filename|dir" /etc/redis/redis.conf
# line as value of a configuration directive, you'd better put includes
# interfaces using the "bind" configuration directive, followed by one or
#   points by adding a save directive with a single empty string argument
# The filename where to dump the DB
dbfilename dump.rdb          #RDB文件保存的文件名,默认采取压缩
# The working directory.
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
# The Append Only File will also be created inside this directory.
# Note that you must specify a directory here, not a file name.
dir /var/lib/redis          ###RDB文件保存目录


在redis正常运行过程中如果默认的RDB存储路径磁盘写满或不能正常写时,可以使用config set dbfilename newfilename和config set dir newdir动态改变默认的存储路径.

root@e7576f2fbb11:/# redis-cli -h 127.0.0.1 -p 6379  config set dir /var/lib/
OK
root@e7576f2fbb11:/# redis-cli -h 127.0.0.1 -p 6379  config set filename newfilename.rdb
(error) ERR Unsupported CONFIG parameter: filename
root@e7576f2fbb11:/# redis-cli -h 127.0.0.1 -p 6379  config set dbfilename newfilename.rdb
OK
root@e7576f2fbb11:/# redis-cli bgsave
Background saving started
root@e7576f2fbb11:/# ls -l /var/lib/newfilename.rdb
-rw-r--r-- 1 root root 34 Jun 10 09:28 /var/lib/newfilename.rdb
root@e7576f2fbb11:/# date
Sat Jun 10 09:29:14 UTC 2017
root@e7576f2fbb11:/#
root@e7576f2fbb11:/# redis-check-dump /var/lib/newfilename.rdb        #####使用redis-check-dump 工具检测RDB文件是否有问题.
==== Processed 3 valid opcodes (in 17 bytes) ===================================
CRC64 checksum is OK


AOF

AOF(append only file)持久化:使用独立的日志的方式记录每次写的命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的.AOF的主要作用是解决了数据持久化的实时性.

如果要开启AOF需要修改redis.conf配置:appendonly yes(默认不开启:appendonly no)

通过定义appendfilename和dir修改aof文件名和保存路径.

AOF工作流程:

所有的写入命令追加到缓冲区中(redis是单线程响应方式,如果实时追加到硬盘,会影响性能.同时也是fsync策略起作用的前提)

AOF缓冲区根据对应的fsync策略向硬盘做同步操作

随着AOF文件越来越大,需要定期AOF文件进行重写,达到"压缩"文件的目的

重启redis时,可以加载AOF文件进行数据恢复.

文件同步

  redis提供多种缓冲区同步文件策略,由参数appendfsync控制,不同值含义如下:

html,body { margin: 0; padding: 0 }
body { padding: 20px }
h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite,code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var,dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption,tbody,tfoot,thead,tr,th,td { margin: 0; padding: 0; border: 0; font-weight: normal; font-style: normal; font-size: 100%; line-height: 1; font-family: inherit }
table { border-collapse: collapse; border-spacing: 0 }
ol,ul { list-style: none }
q::before,q::after,blockquote::before,blockquote::after { content: "" }
html { font-size: 100% }
a:focus { outline: thin dotted }
a:hover,a:active { outline: 0 }
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section { display: block }
audio,canvas,video { display: inline-block }
audio:not([controls]) { display: none }
sub,sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline }
sup { top: -0.5em }
sub { bottom: -0.25em }
img { border: 0 }
button,input,select,textarea { font-size: 100%; margin: 0; vertical-align: baseline }
button,input { line-height: normal }
button::-moz-focus-inner,input::-moz-focus-inner { border: 0; padding: 0 }
button,input[type="button"],input[type="reset"],input[type="submit"] { cursor: pointer }
input[type="search"] { }
input[type="search"]::-webkit-search-decoration { }
textarea { overflow: auto; vertical-align: top }
html,body { background-color: #ffffff }
body { margin: 0; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; line-height: 18px; color: #404040 }
.container { width: 940px; margin-left: auto; margin-right: auto }
.container::before,.container::after { display: table; content: "" }
.container::after { clear: both }
.container-fluid { position: relative; min-width: 940px; padding-left: 20px; padding-right: 20px }
.container-fluid::before,.container-fluid::after { display: table; content: "" }
.container-fluid::after { clear: both }
.container-fluid>.sidebar { float: left; width: 220px }
.container-fluid>.content { margin-left: 240px }
a { color: #0069d6; text-decoration: none; line-height: inherit; font-weight: inherit }
a:hover { color: #00438a; text-decoration: underline }
.pull-right { float: right }
.pull-left { float: left }
.hide { display: none }
.show { display: block }
.row { margin-left: -20px }
.row::before,.row::after { display: table; content: "" }
.row::after { clear: both }
p { font-size: 13px; font-weight: normal; line-height: 18px; margin-bottom: 9px }
p small { font-size: 11px; color: #bfbfbf }
h1,h2,h3,h4,h5,h6 { font-weight: bold; color: #404040 }
h1 small,h2 small,h3 small,h4 small,h5 small,h6 small { color: #bfbfbf }
h1 { margin-bottom: 18px; font-size: 30px; line-height: 36px }
h1 small { font-size: 18px }
h2 { font-size: 24px; line-height: 36px }
h2 small { font-size: 14px }
h3,h4,h5,h6 { line-height: 36px }
h3 { font-size: 18px }
h3 small { font-size: 14px }
h4 { font-size: 16px }
h4 small { font-size: 12px }
h5 { font-size: 14px }
h6 { font-size: 13px; color: #bfbfbf; text-transform: uppercase }
ul,ol { margin: 0 0 18px 25px }
ul ul,ul ol,ol ol,ol ul { margin-bottom: 0 }
ul { list-style: disc }
ol { list-style: decimal }
li { line-height: 18px; color: #808080 }
ul.unstyled { list-style: none; margin-left: 0 }
dl { margin-bottom: 18px }
dl dt,dl dd { line-height: 18px }
dl dt { font-weight: bold }
dl dd { margin-left: 9px }
hr { margin: 20px 0 19px; border: 0; border-bottom: 1px solid #eee }
strong { font-style: inherit; font-weight: bold }
em { font-style: italic; font-weight: inherit; line-height: inherit }
.muted { color: #bfbfbf }
blockquote { margin-bottom: 18px; border-left: 5px solid #eee; padding-left: 15px }
blockquote p { font-size: 14px; font-weight: 300; line-height: 18px; margin-bottom: 0 }
blockquote small { display: block; font-size: 12px; font-weight: 300; line-height: 18px; color: #bfbfbf }
blockquote small::before { content: "— " }
address { display: block; line-height: 18px; margin-bottom: 18px }
code,pre { padding: 0 3px 2px; font-family: Monaco, Andale Mono, Courier New, monospace; font-size: 12px }
code { padding: 1px 3px }
pre { background-color: #f5f5f5; display: block; padding: 8.5px; margin: 0 0 18px; line-height: 18px; font-size: 12px; border: 1px solid rgba(0, 0, 0, 0.15); white-space: pre-wrap }
form { margin-bottom: 18px }
fieldset { margin-bottom: 18px; padding-top: 18px }
fieldset legend { display: block; padding-left: 150px; font-size: 19.5px; line-height: 1; color: #404040 }
form .clearfix { margin-bottom: 18px }
form .clearfix::before,form .clearfix::after { display: table; content: "" }
form .clearfix::after { clear: both }
label,input,select,textarea { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; line-height: normal }
label { padding-top: 6px; font-size: 13px; line-height: 18px; float: left; width: 130px; text-align: right; color: #404040 }
form .input { margin-left: 150px }
input[type="checkbox"],input[type="radio"] { cursor: pointer }
input,textarea,select,.uneditable-input { display: inline-block; width: 210px; height: 18px; padding: 4px; font-size: 13px; line-height: 18px; color: #808080; border: 1px solid #ccc }
input[type="checkbox"],input[type="radio"] { width: auto; height: auto; padding: 0; margin: 3px 0; line-height: normal; border: none }
input[type="file"] { background-color: #ffffff; padding: initial; border: initial; line-height: initial }
input[type="button"],input[type="reset"],input[type="submit"] { width: auto; height: auto }
select,input[type="file"] { height: 27px; line-height: 27px }
select[multiple] { height: inherit }
textarea { height: auto }
.uneditable-input { background-color: #ffffff; display: block; border-color: #eee; cursor: not-allowed }
:-moz-placeholder { color: #bfbfbf }
::-webkit-input-placeholder { color: #bfbfbf }
input,textarea { }
input:focus,textarea:focus { outline: 0; border-color: rgba(82, 168, 236, 0.8) }
input[type="file"]:focus,input[type="checkbox"]:focus,select:focus { outline: 1px dotted #666 }
form div.clearfix.error { background: #fae5e3; padding: 10px 0; margin: -10px 0 10px }
form div.clearfix.error>label,form div.clearfix.error span.help-inline,form div.clearfix.error span.help-block { color: #9d261d }
form div.clearfix.error input,form div.clearfix.error textarea { border-color: #c87872 }
form div.clearfix.error input:focus,form div.clearfix.error textarea:focus { border-color: #b9554d }
form div.clearfix.error .input-prepend span.add-on,form div.clearfix.error .input-append span.add-on { background: #f4c8c5; border-color: #c87872; color: #b9554d }
table { width: 100%; margin-bottom: 18px; padding: 0; border-collapse: separate; font-size: 13px; border: 1px solid #ddd }
table th,table td { padding: 10px 10px 9px; line-height: 18px; text-align: left }
table th { padding-top: 9px; font-weight: bold; vertical-align: middle; border-bottom: 1px solid #ddd }
table td { vertical-align: top }
table th+th,table td+td { border-left: 1px solid #ddd }
table tr+tr td { border-top: 1px solid #ddd }
table tbody tr:first-child td:first-child { }
table tbody tr:first-child td:last-child { }
table tbody tr:last-child td:first-child { }
table tbody tr:last-child td:last-child { }
.zebra-striped tbody tr:nth-child(2n+1) td { background-color: #f9f9f9 }
.zebra-striped tbody tr:hover td { background-color: #f5f5f5 }
.zebra-striped .header { cursor: pointer }
.zebra-striped .header::after { content: ""; float: right; margin-top: 7px; border-width: 0 4px 4px; border-style: solid; border-color: #000 transparent; visibility: hidden }
.zebra-striped .header:hover::after { visibility: visible }
footer { margin-top: 17px; padding-top: 17px; border-top: 1px solid #eee }
.page-header { margin-bottom: 17px; border-bottom: 1px solid #ddd }
.page-header h1 { margin-bottom: 8px }
.close { float: right; color: #000000; font-size: 20px; font-weight: bold; line-height: 13.5px; opacity: 0.2 }
.close:hover { color: #000000; text-decoration: none; opacity: 0.4 }
pre { padding: 0; margin: 10px 0px 10px; overflow: auto }
pre code { margin: 5px; padding: 0px; display: block; line-height: 18px }
.center { text-align: center }
.left { text-align: left }
.right { text-align: right }
body { font-family: "Geneva", Arial, sans-serif; font-size: 13px; margin: 10px }
a,a:visited { color: #09c }
a:hover { color: #336699; text-decoration: none }
h1 { margin: 0px 0px 10px; font-weight: bold }
h2 { border-bottom: 2px dotted #ccc; margin: 5px 0px 15px }
h6 { color: #09c }
blockquote { font-family: "Georgia", Courier New, courier, sans-serif; background: #efefef; padding: 5px 10px; border: solid 1px #ddd; margin: 15px; color: #333 }
ul,ol { margin-bottom: 15px }
li { padding: 3px }
code { background-color: #f1f1f1; color: #336699 }
pre { background-color: #f1f1f1 }
pre>code { margin: 0px; padding: 5px; border: 0px; background-color: #f1f1f1 }
可配置值说明
always命令写入aof_buf后调用fsync同步操作同步到aof文件,fsync同步完成后线程返回
everysec命令写入aof_buf后调用系统write操作,write完成后线程返回,fsync操作由专门线程每秒调用一次 (建议配置)
no命令写入aof_buf后调用系统write操作,不对aof文件做fsync同步,同步硬盘由操作系统负责,通常最长同步周期30秒
系统调用write和fsync说明

write 操作会触发延迟写机制.Linux在内核提供页缓冲区用来提高IO性能.write操作在写入系统缓冲区后直接返回.同步硬盘操作依赖于系统调度的机制,比如当缓冲区页空间写满或达到特定时间周期时触发.同步文件之前,如果此时系统宕机,缓冲区数据会丢失.

fsync这对单个文件操作,做强制磁盘同步,fsync将阻塞知道写入硬盘完成后返回,保证数据持久化.

重写机制

  随着不断的追加写入,aof文件越来越大,此时重写机制会压缩文件大小.重写指的是:把redis进程内的数据转化为写命令同步到新AOF文件的过程.

  重写使aof文件变小原因:

过期的数据不会写入

多余的命令不会写入

多条命令的合并(lpush list a lpush list b lpush c====>lpush list a b c)  

  重写的触发

手动调用 bgrewriteaof命令

自动触发 根据配置文件中auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机

auto-aof-rewrite-min-size: 表示重写aof时,文件的最小体积,default64MB(重写优先条件,必须满足)

auto-aof-rewrite-min-percentage: 表示当前aof文件大小和上次重写后aof文件大小的比值.

  重写运作流程

执行bgrewriteaof请求如果当前正字执行aof,直接返回,如果在执行bgsave则推迟到bgsave完成后再执行

redis调用fork产生一个子进程(开销同RDB)

主进程持续把新的变动写到aof_buf并仍然沿用appendfsync策略同步到磁盘,即旧的aof文件,由于fork使用写时复制技术,子进程只能共享fork操作时的内存数据,所以新的变动同时也要在aof_rewrite_buf存一份,防止新的aof文件生成期间丢失这部分数据

根据规则重写aof文件(新)

新aof文件写入完成后,子进程通知父进程,父进程更新信息.

父进程把aof_rewrite_buf写入新的aof文件 

新aof文件替换老的aof文件



重启加载

1. AOF持久化开启且存在AOF文件时,优先加载AOF文件

2. AOF关闭或AOF文件不存在时,加载RDB文件(前提是RDB存在,不存在也会启动)

3.加载AOF/RDB文件成功后,rdis启动成功

4. AOF/RDB存在错误时,启动失败
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: