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:
rdb_bgsave_in_progress:
rdb_last_save_time:
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:
rdb_current_bgsave_time_sec:-
root@e7576f2fbb11:/# tail -n /var/log/redis/redis-server.log
:C Jun ::46.257 * DB saved on disk
:C Jun ::46.258 * RDB: MB of memory used by copy-on-write
:M Jun ::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
- root@e7576f2fbb11:/# redis-cli bgsave;redis-cli bgsave
- 父进程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控制,不同值含义如下:
.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{zoom:1;margin-left:-20px;}.row:before,.row:after{display:table;content:"";zoom:1;*display:inline;}
.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:'\2014 \00A0';}
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;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
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 #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;white-space:pre;white-space:pre-wrap;word-wrap:break-word;}
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;*padding:0 0 5px 145px;*line-height:1.5;}
form .clearfix{margin-bottom:18px;zoom:1;}form .clearfix:before,form .clearfix:after{display:table;content:"";zoom:1;*display:inline;}
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;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
input[type=checkbox],input[type=radio]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:none;}
input[type=file]{background-color:#ffffff;padding:initial;border:initial;line-height:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
input[type=button],input[type=reset],input[type=submit]{width:auto;height:auto;}
select,input[type=file]{height:27px;line-height:27px;*margin-top:4px;}
select[multiple]{height:inherit;}
textarea{height:auto;}
.uneditable-input{background-color:#ffffff;display:block;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
:-moz-placeholder{color:#bfbfbf;}
::-webkit-input-placeholder{color:#bfbfbf;}
input,textarea{-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1);}
input:focus,textarea:focus{outline:0;border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 3px rgba(0, 0, 0, 0.1),0 0 8px rgba(82, 168, 236, 0.6);}
input[type=file]:focus,input[type=checkbox]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:1px dotted #666;}
form div.clearfix.error{background:#fae5e3;padding:10px 0;margin:-10px 0 10px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}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;-webkit-box-shadow:0 0 3px rgba(171, 41, 32, 0.25);-moz-box-shadow:0 0 3px rgba(171, 41, 32, 0.25);box-shadow:0 0 3px rgba(171, 41, 32, 0.25);}form div.clearfix.error input:focus,form div.clearfix.error textarea:focus{border-color:#b9554d;-webkit-box-shadow:0 0 6px rgba(171, 41, 32, 0.5);-moz-box-shadow:0 0 6px rgba(171, 41, 32, 0.5);box-shadow:0 0 6px rgba(171, 41, 32, 0.5);}
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;*border-collapse:collapse;font-size:13px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}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{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
table tbody tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
table tbody tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
table tbody tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
.zebra-striped tbody tr:nth-child(odd) 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;-webkit-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);-moz-box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);box-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}.page-header h1{margin-bottom:8px;}
.close{float:right;color:#000000;font-size:20px;font-weight:bold;line-height:13.5px;text-shadow:0 1px 0 #ffffff;filter:alpha(opacity=20);-khtml-opacity:0.2;-moz-opacity:0.2;opacity:0.2;}.close:hover{color:#000000;text-decoration:none;filter:alpha(opacity=40);-khtml-opacity:0.4;-moz-opacity:0.4;opacity:0.4;}
pre {
padding: 0;
margin: 10px 0px 10px;
overflow: auto; /*--If the Code exceeds the width, a scrolling is available--*/
overflow-Y: hidden; /*--Hides vertical scroll created by IE--*/
}
pre code {
margin: 5px; /*--Left Margin--*/
padding: 0px;
display: block;
line-height: 18px;
}
.center { text-align:center}
.left {text-align:left}
.right {text-align:right}
-->
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存在错误时,启动失败