redis的持久化之RDB和AOF模式(三)


RDB模式

RDB是Redis默认开启的持久化模式,持久化方式为指定时间(默认5分钟),定时同步内存中的数据到磁盘中做持久化存储,也就是同步到指定目录下的dump.rdb文件,Redis服务在重启时候会重新加载该文件的数据到内存

RDB相关配置

save <时间(秒/s)> <更新次数>,在指定时间内达到更新次数,则持久化到rdb文件一次。如果想关闭RDB同步,则把save ""放开,其它几个开头加**#**屏蔽

# save ""
save 900 1		#900秒内执行1次set操作则持久化一次
save 300 10		#300秒内执行10次set操作则持久化一次
save 60 10000	#60秒内执行10000次set操作则持久化一次

指定持久化文件的名称和文件位置

dbfilename dump.rdb  #文件名称,可自定义
dir ./			# 文件所在目录位置,可修改为指定目录

是否压缩存储到磁盘中的快照,默认开启压缩Yes。Redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。

rdbcompression yes  

RDB优缺点

优点

  1. 保存了某个时间点上的数据,适合做冷备,定时同步到远端服务器,线上挂了可以恢复
  2. 对redis性能影响小,通过fock了一个子进程做持久化,不会阻塞主进程,也不需要主进程做任何磁盘IO操作
  3. RDB在进行数据恢复的速度比AOF要快

缺点

  1. RDB生成快照的时候,fock的子进程会把数据写入到临时文件,最后再把临时文件替换之前的备份rdb文件,这个过程内存中的数据被克隆了一份,大致2倍的膨胀性,可能几毫秒或者几秒,如果刚好是秒杀期间就gg
  2. 在指定时间内做一次备份,如果redis挂掉,意味着可能丢失这个时间间隔内的数据

RDB的手动触发

save命令
该命令会阻塞当前redis服务进程,执行save命令期间,不能接收其它打到的命令,直到RDB持久化过程完成。如果线上这么操作,可是很致命,相当于redis当前停止服务

bgsave命令
该命令会在后台异步执行快照操作,此时redis服务正常接收其它打到的命令,服务正常提供。所以,redis内部或者手动触发基本都是使用bgsave

RDB模式的演示

修改配置文件,120秒内set4次持久化一次,重启redis服务
# cd /home/tool/redis-5.0.5
# vi redis.conf
save 120 4
# service redis stop
# service redis start

进入客户端,set几个值
# redis-cli
127.0.0.1:6379> set username toegg
OK
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> set sex 1
OK
127.0.0.1:6379> set user_id 1001
OK
等待一分钟后,再set
127.0.0.1:6379> set work docter
OK

获取所有keys,关闭redis服务
127.0.0.1:6379> keys *
1) "user_id"
2) "age"
3) "sex"
4) "username"
5) "work"
127.0.0.1:6379> SHUTDOWN
not connected> QUIT
# ps aux |grep rediss
root      18473  0.0  0.2 103300  2024 pts/0    S+   04:14   0:00 grep redis

查看 / 目录下的dump.rdb文件
# cat /dump.rdb
REDIS0009▒      redis-ver5.0.5▒
▒edis-bits▒@▒ctime®/▒^used-mem▒P
aof-preamble▒▒▒user_id▒▒age▒sexusernametoeggworkdocker

重启redis服务,进入客户端,获取所有元素,元素都还在
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "user_id"
2) "work"
3) "username"
4) "sex"
5) "age"
127.0.0.1:6379> exit

复制 / 目录下的rdb文件到 dump1.rdb 做储备文件
# cp /dump.rdb /dump1.rdb

进入客户端,清空所有元素,关闭服务
# redis-cli
127.0.0.1:6379> flushall
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

查看 / 目录下的dump.rdb文件,发现已为空
# cat /dump.rdb

重启服务,进入客户端,获取所有元素,发现所有元素已经清空
# service redis stop
# service redis start
# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

复制刚才的储备文件,覆盖掉/下的dump.rdb,再重启服务
# cp /dump1.rdb /dump.rdb
cp: overwrite `dump.rdb'? y
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"
2) "sex"
3) "age"
4) "user_id"
5) "work"

操作步骤如下:

  1. 修改配置文件,60秒内修改4次则持久化一次,重启redis服务

  2. 进入客户端,set几个相关值,过1分钟后,看指定RDB文件的 / 目录下是否会生成一个dump.rdb文件。再set第五个work的元素,然后执行SHUTDOWN关闭redis服务,是为了验证通过SHUTDOWN关闭服务,SHUTDOWN会触发RDB快照

  3. 查看 / 目录下的dump.rdb文件,set的几个值已在文件中,内容部分是乱码是编码问题,忽略

  4. 重启redis服务,再进入客户端,获取所有元素,发现刚才set的元素都在,即重启,redis服务正常从dump.rdb加载数据到内存

  5. 复制当前的rdb文件做储备,等下用

  6. 进入客户端,执行flushall清空所有元素,关闭服务

  7. 查看 / 目录下下的dump.rdb,发现已经为空,得出flushall也会触发RDB快照

  8. 重启redis服务,再进入客户端,获取所有元素,发现都不在了

  9. 复制刚才的储备文件,覆盖掉/下的dump.rdb,再重启服务

  10. 进入客户端,发现一开始set的值已经加载回内存


AOF模式

Redis默认不开启,它是可以保证数据的高可用性,即最大限度的避免数据丢失。AOF是以日志文件的形式,把每个写指令以追加方式记录到文件中。Redis重启会根据日志文件的指令内容都执行一遍,实现数据恢复

AOF相关配置

开启AOF,把 no 改为 yes

appendonly yes

指定文件名,可自定义修改

appendfilename "appendonly.aof"

数据同步到文件的触发方式,默认是每1秒同步。
always:每次发生数据变化立刻写入,这里会影响性能但是数据完整
everysec:默认配置,每1秒写入一次
no:不同步,相当于关闭了写入

# appendfsync always
appendfsync everysec
# appendfsync no

重写触发机制,aof文件大小达到指定大小,就会触发重写,相当于移除冗余指令。
第一个参数是当前AOF文件大小和最后一次重写后的大小之间的比率等于100%,才会触发重写

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

AOF的重写机制

AOF 的运作方式是不断地将命令追加到文件的末尾,随着写入命令的不断增加, AOF 文件的体积也会变得越来越大,冗余数据越来越多。比如set了同个key100次 , 那么仅仅是为了保存这个key的当前值,却有100条指令记录,冗余了99条。为了处理这种情况, Redis 支持不影响服务的情况下,执行 BGREWRITEAOF 命令,fock了子进程对AOF文件重写,包含当前数据集所需最少命令。

重写触发条件

  1. 没有bgsave命令,RDB / AOF持久化在执行
  2. 没有其它BGREWRITEAOF在执行
  3. 当前AOF文件大小大于aof_rewrite_min_size,默认是64m(这个太小了,根据自身调整)
  4. AOF文件大小是上次重写rewrite后大小的(auto-aof-rewrite-percentage),默认是100%,一倍

重写步骤:

  1. Redis执行fock()子进程,父进程启用重写缓冲区
  2. 子进程开始直接从数据库中读取键现在的值,然后用一条命令去记录键值对,写入到临时文件。对于所有其它新执行的写入命令,父进程将它们写到重写缓冲区中,同时也写入现有的旧的AOF文件,保证了Redis服务的正常进行和持久化
  3. 子进程完成AOF重写之后,会向父进程发送一个完成信号,父进程会把重写缓冲区,即是重写过程新执行的写入命令全部追加到新的AOF文件,这个时候就和服务器当前数据保持一致了。
  4. 最后,父进程对新的AOF文件进行改名,原子的覆盖原有的AOF文件,完成新旧两个AOF文件的替换

AOF文件格式修复

实际开发中,可能因为某些原因导致 appendonly.aof 文件格式异常,这样会导致Redis启动数据还原失败。
修复方式,执行以下命令

# cd /home/tool/redis-5.0.5/src
# redis-check-aof --fix appendonly.aof

AOF优缺点

优点

  1. AOF每1秒异步fsync记录一次,丢失数据最多就1秒,数据的实时性高
  2. 对日志文件进行操作的时候是以append-only的方式去追加写,少了很多磁盘寻址的开销

缺点

  1. 一样的数据,AOF文件比RDB要大得多,数据恢复速度就会慢
  2. aof开启后,redis的写qps比rdb支持的低,因为1秒fsync一次,当然,性能还是没问题

AOF模式的演示

修改AOF启用,重启redis服务
# vi redis.conf
appendonly yes
# service redis start

设置值,然后关闭redis服务
127.0.0.1:6379> set username toegg
OK
127.0.0.1:6379> keys *
1) "username"
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

查看appendonly.aof,文件是会在当前目录下生成
# cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$8
username
$5
toegg

重启服务,进入客户端,获取所有元素,发现已加载回数据
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"
127.0.0.1:6379> flushall
OK
127.0.0.1:6379> exit

复制 appendonly.aof文件到 appendonly1.aof 做储备文件
cp appendonly.aof appendonly1.aof

进入客户端,清空所有元素,关闭服务
# redis-cli
127.0.0.1:6379> flushall
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

查看appendonly.aof,发现多了指令flushall
# cat appendonly.aof

重启服务,进入客户端,获取所有元素,发现元素已被清空
# service redis start
# redis-cli
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

复制刚才的储备文件,覆盖掉appendonly.aof,再重启服务,数据恢复
# cp appendonly1.aof appendonly.aof
cp: overwrite `appendonly.aof'? y
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"
127.0.0.1:6379> SHUTDOWN
not connected> QUIT

损坏appendonly.aof的格式,在文件末尾加上1111,启动服务
# vi appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$8
username
$5
toegg
1111
# service redis start
5349:M 24 May 2020 04:11:02.470 # Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>

修复文件格式,再重启服务,已经能正常启动。获取所有元素,数据正常加载
# redis-check-aof --fix appendonly.aof
0x              66: Expected prefix '*', got: '1'
AOF analyzed: size=108, ok_up_to=102, diff=6
This will shrink the AOF from 108 bytes, with 6 bytes, to 102 bytes
Continue? [y/N]: y
Successfully truncated AOF
# service redis start
# redis-cli
127.0.0.1:6379> keys *
1) "username"

操作步骤如下:

  1. 修改配置文件,启用AOF,重启redis服务

  2. 进入客户端,set一个值,关闭redis服务

  3. 查看当前目录的appendonly.aof文件,set的值已在文件中

  4. 重启redis服务,再进入客户端,获取所有元素,发现刚才set的元素都在,即重启,redis服务正常从appendonly.aof加载数据到内存

  5. 复制当前的aof文件做储备,等下用

  6. 进入客户端,执行flushall清空所有元素,关闭服务

  7. 查看appendonly.aof,发现文件最后有flushall指令,这里得出flushall也会记录到aof文件

  8. 重启redis服务,再进入客户端,获取所有元素,发现都不在了

  9. 复制刚才的储备文件,覆盖掉appendonly.aof,再重启服务,数据已恢复

  10. 进入客户端,发现一开始set的值已经加载回内存

  11. 故意在appendonly.aof末尾加上1111,造成文件格式异常,启动服务,显示读取文件报错

  12. 使用命令redis-check-aof --fix appendonly.aof修正,重新启动,可以正常启动,数据也正常加载


总结:

  1. Redis默认开启RDB模式,指定间隔时间内,执行指定次数写操作则持久化到磁盘。它的恢复速度快,但是数据的一致性和完整性较差
  2. AOF模式需要手动开启,秒级持久化,保证数据完整性,但文件内容较大,恢复速度慢
  3. AOF针对文件大小不断变大,提供了重写机制
  4. 启动加载流程,优先加载AOF,再加载RDB
  5. 注意不要用flushall,会写入rdb或者appendonly,会清掉数据
  6. 最好的话,两者都用,RDB做冷备,AOF做热备,稳健服务器
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章