redis演练(5) redis持久化

何谓持久化,就是媳妇让你,持久一些。
html

说白了持久化:就是将内存中的数据保存到磁盘上的过程(数据库也算磁盘的特殊表现),以保证宕机或断电后,能够继续访问。java中常见的持久化框架,如Hibernate,ibatis,jdbc都是持久化实现方式的一种,固然普通文件保存功能也算。java

拿memcached来讲,memcached保存的信息,没有进行持久化,因此只能存活一个进程生命期,下次从新启动,数据所有丢失。这算memcached的一个缺点吧。redis提供了持久化支持,并且提供了2种持久化方案。linux

《redis演练系列》,立足于案例展现,经过形象,对比,图示的方式,达到知识梳理过程。redis

本章的主要梗概。数据库

  • redis两种持久化方案对比缓存

  • redis两种持久化方案参数说明
    安全

  • 演练RDB的触发时机bash

  • 演练AOF服务器

  • RDB VS AOFapp

1.redis两种持久化方案对比

redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。RDB,AOF就至关于redis持久界的2个亲兄弟,相互配合,相互提携。固然也会争抢些资源。
RDB,简而言之,就是在不一样的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;
AOF,则是换了一个角度来实现持久化,那就是将redis执行过的全部写指令记录下来,在下次redis从新启动时,只要把这些写指令从前到后再重复执行一遍,就能够实现数据恢复了。

RDB将服务器包含的全部数据库数据以二进制文件的形式保存到硬盘里面。

下图,是具体操做步骤。具体详情参见【http://www.cnblogs.com/luogankun/p/3986403.html】


221732277642628.png

AOF,英文是Append Only File,即只容许追加不容许改写的文件。AOF方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。有点数据库软件联机日志的影子。

二者对比

221833475454922.png

redis两种持久化方案参数说明

涉及到文件保存,通常要考虑如下几个问题,不只仅限于redis。

  • 保存时机:何时触发。取决于数据一致性和效率的平衡

  • 保存目标对象:日志,二进制...

  • 保存目录:本地目录,仍是共享目录

  • 是否压缩:节省空间

  • 是否校验:考虑安全

  • 保存失败处理机制:异常报告

  • 开启线程数:决定速度,但会影响其余功能

  • 保存文件限制:超过大小,不容许;和不容许上传*.exe文件等

带着这些问题,去扣相关的RDB参数,和AOF参数,问题就简单多了。


RDB
# 存 DB 到磁盘:
#
#   格式:save <间隔时间(秒)> <写入次数>
#
#   根据给定的时间间隔和写入次数将数据保存到磁盘
#
#   下面的例子的意思是:
#   900 秒后若是至少有 1 个 key 的值变化,则保存
#   300 秒后若是至少有 10 个 key 的值变化,则保存
#   60 秒后若是至少有 10000 个 key 的值变化,则保存
#
#   注意:你能够注释掉全部的 save 行来停用保存功能。
#   也能够直接一个空字符串来实现停用:
#   save ""

save 900 1
save 300 10
save 60 10000

# 默认状况下,若是 redis 最后一次的后台保存失败,redis 将中止接受写操做,
# 这样以一种强硬的方式让用户知道数据不能正确的持久化到磁盘,
# 不然就会没人注意到灾难的发生。
#
# 若是后台保存进程从新启动工做了,redis 也将自动的容许写操做。
#
# 然而你要是安装了靠谱的监控,你可能不但愿 redis 这样作,那你就改为 no 好了。
stop-writes-on-bgsave-error yes

# 是否在 dump .rdb 数据库的时候使用 LZF 压缩字符串
# 默认都设为 yes
# 若是你但愿保存子进程节省点 cpu ,你就设置它为 no ,
# 不过这个数据集可能就会比较大
rdbcompression yes

# 是否校验rdb文件
rdbchecksum yes

# 设置 dump 的文件位置
dbfilename dump.rdb

# 工做目录
# 例如上面的 dbfilename 只指定了文件名,
# 可是它会写入到这个目录下。这个配置项必定是个目录,而不能是文件名。
dir ./
AOF

    #默认状况下Redis会异步的将数据导出到磁盘上。这种模式对许多应用程序已经足够了,  
    #可是若是断电或者redis进程出问题就会致使一段时间内的更新数据丢失(取决与配置项)  
    #  
    #这种只增文件是可选的可以提供更好的体验的数据持久化策略。  
    #举个例子,若是使用默认的配置数据fsync策略,在服务器意外断电的状况下redis只会丢失一秒中内的更新数据,  
    #或者当redis进程出问题但操做系统运转正常时,redis只会丢失一个数据更新操做。  
    #  
    #AOF 和 RDB 持久化方式能够同时启动而且无冲突。  
    #若是AOF开启,启动redis时会加载aof文件,这些文件可以提供更好的保证。  
    #请在 http://redis.io/topics/persistence 获取更多数据持久化信息。  
      
    appendonly no  
      
    # 只增文件的文件名称。(默认是appendonly.aof)  
    # appendfilename appendonly.aof  
      
    #调用fsync()函数会通知操做系统真正将数据写入磁盘,而不是等待缓冲区中有更多数据。  
    #有些操做系统会将数据输出到磁盘,有些操做系统只是ASAP。  
    #  
    #redis支持三种不一样的方式:  
    #  
    #no:不调用,之等待操做系统来清空缓冲区当操做系统要输出数据时。很快。  
    # always: 每次更新数据都写入仅增日志文件。慢,可是最安全。  
    # everysec: 每秒调用一次。折中。  
    #  
    #默认是每秒中一次,由于它每每是在速度和数据安全二者之间的折中选择。  
    #若是你能够接受让操做系统去自动清空缓存,你能够将这项配置下降到'no'(若是你能够接受一段时间的数据丢失,默认的rdb就足够了),  
    #这彻底取决与你。若是你想要一个更好的体验或者从相反的角度,使用'always',这样会很慢,可是比'everysec'安全些。  
    #  
    #请在下面的文章中获取更多细节知识:  
    #  http://antirez.com/post/redis-persistence-demystified.html  
    #  
    #若是你不是很清楚这三项之间的区别,或者不知道哪一种适合你的机器,就是用默认吧。  
      
    # appendfsync always  

    appendfsync everysec  

    # appendfsync no 


      
    #当AOF策略设置为'always'或者'everysec'的时候,后台的保存进程会进行不少磁盘I/O操做,  
    #在某些linux结构中redis会在调用sync()方法时阻塞很长时间。记住,如今还没办法解决这个问题,即便在不一样进程中进行调用也会block。  
    #  
    #使用以下配置可能会缓解这个问题,这样会在存储大数据或者BIGREWRITEAOF的时候不会在主进程中调用fsync()方法。  
    #  
    # 这表示,若是另一个子进程在进行保存操做,redis的表现如同配置为‘appendfsync no’。  
    #在实际应用中,这表示在最坏的情景下(使用linux默认配置)可能会丢失30秒日志。  
    #   
    #若是你有特殊的状况能够配置为'yes'。可是配置为'no'是最为安全的选择。  
    no-appendfsync-on-rewrite no  
      
      
    #自动重写只增文件。  
    #redis能够自动盲从的调用‘BGREWRITEAOF’来重写日志文件,若是日志文件增加了指定的百分比。  
    #   
    #它是这样工做的:每次rewrite后redis会记录日志文件的大小。(若是重启后没有重写后的大小,就默认用日志文件大小)  
    #  
    # 这个基准日志大小和当前日志大小作比较。若是当前大小比指定的百分比,重写机制就会被触发。  
    #同时,你也要制定一个重写下线,用来避免增加百分比够了,可是日志文件还很小的状况。  
    #  
    #指定百分比为0能够注掉自动重写日志文件功能。       
    auto-aof-rewrite-percentage 100  

    auto-aof-rewrite-min-size 64mb

#redis在启动的时候能够加载被截断的AOF文件,默认启用;    (3.0之后才支持)

aof-load-truncated yes     



2.演练RDB的触发时机


#   900 秒后若是至少有 1 个 key 的值变化,则保存
#   300 秒后若是至少有 10 个 key 的值变化,则保存
#   60 秒后若是至少有 10000 个 key 的值变化,则保存
#   注意:你能够注释掉全部的 save 行来停用保存功能。
#   也能够直接一个空字符串来实现停用:
#   save ""
save 900 1
save 300 10
save 60 10000

采用默认的RDB配置

redis.conf

save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./

2.1演练“重启redis,键值丢失”

[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156

192.168.163.156:6379> flushdb
OK
192.168.163.156:6379> set blog "blog.51cto.com"
OK
#为键赋值
192.168.163.156:6379> get blog
"blog.51cto.com"
192.168.163.156:6379> exit
[root@hadoop2 redis]# ps -ef |grep redis
root      2546     1  0 07:42 ?        00:00:05 /usr/local/redis/bin/redis-server 192.168.163.156:6379       
root      3235  2517  0 08:54 pts/0    00:00:00 grep redis
[root@hadoop2 redis]# kill -9 2546
#重启redis
[root@hadoop2 redis]# bin/redis-server  redis.conf 
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
# blog键值丢失
192.168.163.156:6379> get blog
(nil)

这个结果,是否是很是出人意外。看来“江湖上都传言,redis断电键值不丢失”有点问题。

其实,没问题。是上面的演练存在不足,数据量没有达到触发时机要求。继续。

2.2演练“重启redis,键值不丢失”

[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> set blog "blog.51cto.com"
OK
#借助自带测试工具,发送1w请求,触发RDB保存
[root@hadoop2 redis]# bin/redis-benchmark  -r 10000 -h 192.168.163.156
====== PING_INLINE ======
  100000 requests completed in 0.83 seconds
  50 parallel clients
  3 bytes payload
  keep alive: 1

99.77% <= 1 milliseconds
...
# 确认  键值还存在
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> get blog
"blog.51cto.com"
192.168.163.156:6379> exit
#关闭 redis服务
[root@hadoop2 redis]# ps -ef |grep redis
root      3241     1  3 08:54 ?        00:00:19 bin/redis-server 192.168.163.156:6379
root      3351  2517  0 09:05 pts/0    00:00:00 grep redis
[root@hadoop2 redis]# kill -9 3241
#重启redis服务
[root@hadoop2 redis]# bin/redis-server  redis.conf 
#确认重启后,blog键值依然存在
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> get blog
"blog.51cto.com"

看来“江湖上都传言,redis断电键值不丢失”,是有前提条件的。

3.演练AOF

 修改redis.conf 开启AOF 关闭RDB

save 900 1
save 300 10
save 60 10000
save ""
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 16mb
aof-load-truncated yes

3.1演练重启redis,键值是否丢失

192.168.163.156:6379> set blog "blog.51cto.com"
OK
192.168.163.156:6379> exit
[root@hadoop2 redis]# pkill redis
#重启
[root@hadoop2 redis]# bin/redis-server  redis.conf 
[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
#键值未丢失
192.168.163.156:6379> get blog
"blog.51cto.com"

结论:托AOF的福,键值没有丢失,和RDB不一样。缘由是二者的触发时机不一样。

这时候,确认下生产AOF文件

#仅仅存了一条记录
[root@hadoop2 redis]# ll
-rw-r--r--. 1 root root    67 9月   3 10:31 appendonly.aof
#查看日志内容(为文本文件)
[root@hadoop2 redis]# cat appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$4
blog
$14
blog.51cto.com

3.2演练重启AOF重写效果

经过查看日志内容,能够确认存放的是操做命令日志。这势必致使文件大小增加过快,这和RDB文件不一样。RDB存储的是二进制文件,并且是某时刻的快照,存储的自己就是面向内存结果。稍后会提供例子演示下RDB的内容。

准备测试数据

[root@hadoop2 redis]# bin/redis-cli  -h  192.168.163.156
#顺序操做键值屡次
192.168.163.156:6379> set year 2001
OK
192.168.163.156:6379> incr year
(integer) 2002
192.168.163.156:6379> incr year
(integer) 2003
192.168.163.156:6379> incr year
(integer) 2004
192.168.163.156:6379> incr year
(integer) 2005
192.168.163.156:6379> incr year
(integer) 2006
192.168.163.156:6379> incr year
(integer) 2007
192.168.163.156:6379> incr year
(integer) 2008
192.168.163.156:6379> incr year
(integer) 2009
192.168.163.156:6379> incr year
(integer) 2010
192.168.163.156:6379> get year
"2010"
# get没有输出到AOF日志
[root@hadoop2 redis]# cat appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$4
blog
$14
blog.51cto.com
*2
$6
SELECT
$1
0
*3
$3
set
$4
year
$4
2001
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year
*2
$4
incr
$4
year

#接下来,借助benchmark工具,批量插入数据,触发AOF文件重写
[root@hadoop2 redis]# bin/redis-benchmark  -r 20000 -h 192.168.163.156

#appendonly.aof文件变化过程(11M->27M -->32M->33M->42M->8.5M.
...
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 11M 9月   3 11:03 appendonly.aof
-rw-r--r--. 1 root root 27M 9月   3 11:03 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 32M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 33M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 36M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 42M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 44M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 8.5M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 11M 9月   3 11:04 appendonly.aof
[root@hadoop2 redis]# ll appendonly.aof  -h
-rw-r--r--. 1 root root 15M 9月   3 11:04 appendonly.aof

从42M 忽然变成了8.5M,明显发生了AOF重写操做。

以year为目标,确认下AOF重写发生了什么。

wKiom1fKP_uyEDCCAAAdXFCG35Q953.png

重写先后,发现将屡次操做的结果,转换为一个等价的命令,大大下降了存储空间。

1.咱们也可使用bgrewriteaof来手动触发AOF的自动重写。

2 .调用 BGSAVE 能手动触发快照保存,保存快照。

但线上环境要注意,阻塞状况。


4.AOF VS RDB.

两种持久化方式,不是水火不容,而是相互扶持,相融以沫。

官方文档,建议二者同时开启

同时开启两种持久化(redis.conf)

save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
dbfilename dump.rdb
dir ./

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 16mb
aof-load-truncated yes

4.1比较2种方式的文件存储

1.删除rdb,aof文件
2.重启redis-server
#3.批量发送1w条请求
[root@hadoop2 redis]# bin/redis-benchmark  -r 10000 -h 192.168.163.156
#4. 比较2个文件大小
[root@hadoop2 redis]# ll -h
总用量 29M
-rw-r--r--. 1 root root  192 9月   3 10:58 1
-rw-r--r--. 1 root root  28M 9月   3 11:26 appendonly.aof
-rw-r--r--. 1 root root 457K 9月   3 11:26 dump.rdb

4.2 演练aof文件损坏

[root@hadoop2 redis]# bin/redis-server  redis.conf 
[root@hadoop2 redis]# bin/redis-cli  -h 192.168.163.156
192.168.163.156:6379> set blog "blog.51cto.com"
OK
192.168.163.156:6379> set subject "redis"
OK

192.168.163.156:6379> set year 2016
OK
192.168.163.156:6379> keys *
1) "year"
2) "subject"
3) "blog"

手动修改下appendonly.aof 文件

wKiom1fKRZDSLFBqAAAydEx5rcU042.png

使用redis-check-aof 验证下,果真不出所料“文件有问题”

[root@hadoop2 redis]# bin/redis-check-aof 
Usage: bin/redis-check-aof [--fix] <file.aof>
[root@hadoop2 redis]# bin/redis-check-aof  appendonly.aof 
0x               0: Expected \r\n, got: 0a00
AOF analyzed: size=112, ok_up_to=0, diff=112
AOF is not valid

...查看启动日志(WARRING 暂时先放着)

4690:M 03 Sep 11:42:12.213 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
4690:M 03 Sep 11:42:12.213 # Server started, Redis version 3.2.3
4690:M 03 Sep 11:42:12.213 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
4690:M 03 Sep 11:42:12.214 # Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

客户端链接失败

[root@hadoop2 redis]# bin/redis-cli  -h 192.168.163.156
Could not connect to Redis at 192.168.163.156:6379: Connection refused

修复aof文件

[root@hadoop2 redis]# bin/redis-check-aof
Usage: bin/redis-check-aof [--fix] <file.aof>
[root@hadoop2 redis]# bin/redis-check-aof --fix appendonly.aof
0x               0: Expected \r\n, got: 0a00
AOF analyzed: size=112, ok_up_to=0, diff=112
This will shrink the AOF from 112 bytes, with 112 bytes, to 0 bytes
Continue? [y/N]: y

Successfully truncated AOF

#修复的结果是清空了AOF文件。

重启成功了,但遗憾的是数据全丢失了。

bin/redis-server  redis.conf

[root@hadoop2 redis]# cat appendonly.aof

bin/redis-cli  -h  192.168.163.156
192.168.163.156:6379> keys *
(empty list or set)

固然,演示AOF文件出问题,这是个比较严重的问题。可见备份的重要性。


AOF方式的另外一个好处,咱们经过一个“场景再现”来讲明。某同窗在操做redis时,不当心执行了FLUSHALL,致使redis内存中的数据所有被清空了,这是很悲剧的事情。不过这也不是世界末日,只要redis配置了AOF持久化方式,且AOF文件尚未被重写(rewrite),咱们就能够用最快的速度暂停redis并编辑AOF文件,将最后一行的FLUSHALL命令删除,而后重启redis,就能够恢复redis的全部数据到FLUSHALL以前的状态了。是否是很神奇,这就是AOF持久化方式的好处之一。可是若是AOF文件已经被重写了,那就没法经过这种方法来恢复数据了。

前人,曾静曰过的。难道有问题。因而我从新实验了下。

此次我加快了速度,马上关闭redis服务,以及使用vi命令直接修改aof文件。结果倒是能够将数据恢复。

这个演示不补贴了。


正是有了持久化,才使redis向“存储”靠近了一大步,数据可靠性提供了保证。

友情提示,演练文章,最好配合官方理论说明性文档一同观看,效果显著。

相关文章
相关标签/搜索