Redis是将数据存储到内存中.我们在玩游戏的时候,通常会感到电脑卡.因为游戏占用了很多的内存.但是我们重启电脑后,电脑就不再卡了.是因为重启释放了内存资源.那我们将Redis存储到内存中,如果不进行数据的持久化(说白了就是将内存的数据存储到硬盘中),重启计算机或者redis服务突然挂掉就会造成数据的丢失.

持久化方式

  1. 快照 : 相当于给数据库拍一张照片,将所有的数据都拷贝出来.做一个完整的备份.例如mysql中的dump,redis中的RDB都类似于快照这种方式.
  2. 记录日志 : 将数据库中的更新记录在日志中,将数据恢复的时候.只需要把日志拿出来.将日志的命令重新执行一遍.得到某时某店的完整数据变化.例如mysql中的Binlog,redis中的AOF.

RDB

什么是RDB

  在redis执行命令将内存中完整的数据保存到一个二进制的RDB文件.redis重启,可以通过夹在RDB文件进行数据的恢复.

触发机制

  一共有六种触发机制,save,bgsave,自动生成,主从复制,debug reloadshut down.

save

  通过命令save开始进行数据备份.但是save是同步执行的.也就是说当你开始进行save后如果接着客户端get key,必须等save结束后才能继续执行后面的命令.

bgsave

  通过命令bgsave开始进行数据备份,bgsave是异步任务.当执行命令后,会立刻返回ok,然后redis通过linux的fork()开启新的子进程进行数据备份.子进程去创建RDB文件,生成成功后会返回主进程dgsave successful.执行fork的速度是非常快的,所以相当于异步,但也不能完全算是异步.因为fork如果慢的话也会阻塞主进程.此时访问redis会正常放回结果,无需等待.

自动生成

  在默认的redis.conf中有默认的自动触发生成文件的配置.三条配置位save 900 1,save 300 10,`save 60 10000.当满足上述任一一个条件后,会自动进行文件备份.当900s 改变了一条;当300s改变了10条,当60s改变了10000条.

  是无法控制redis的修改量,因为请求/用户一多,必然会造成大批量的修改.也就是无法控制生成文件的频率.频繁对大文件写入文件肯定是非常消耗资源和硬盘的.不是一种很好的方式.

# 默认配置
save 900 1
save 300 10
save 10 10000
# rdb文件名
dbfilename dump.rbd
# 存放路径位当前路径
dir ./
# dbsave出现错误是否停止写入
stop-writes-on-bgsave-error yes
# rdb文件是否采用压缩格式
rdbcompression yes
# 是否对rdb文件进行检验
rdbchecksum yes

# 建议
1. 不配置save
2. 修改文件存放路径

主从复制

  当redis进行主从复置的时候会.祝服务器会生成rdb文件.

debug reload

  debug reload 不讲数据进行清空的重启

shutdown

  shutdown 关闭会自动执行shutdown save生成rdb文件

save vs bgsave
IO类型是否阻塞优点缺点
save同步不消耗额外资源阻塞客户端命令
bgsave异步是(发生在fork)不阻塞客户端命令(fork不出问题)消耗额外资源

文件策略

  savedbsave生成的文件都会以新的替换旧的.在执行过程中会生成一个临时文件,执行完成后会替换掉老的文件.

测试

  1. save是否会阻塞

    # 修改新的配置
    cp redis_6379.conf redis_rdb.conf
    vim redis_rdb.conf
    # 添加
    # save 900 1
    # save 300 10
    # save 60 10000
    stop-writes-on-bgsave-error yes
    rdbcompression yes
    rdbchecksum yes
    dbfilename dump-6379.rdb
    
    # 保存启动服务
    redis-server redis_rdb.conf
    # 脚本批量生成1000万条数据
    127.0.0.1:6379> dbsize
    (integer) 10000000
    # 查看使用内存959.66MB
    127.0.0.1:6379> info memory
    # Memory
    used_memory:1006277712
    used_memory_human:959.66M
    # 设置qvbilam
    127.0.0.1:6379> set qvbilam angel
    OK
    # 打开第二个端口执行save.第一个端口执行get
    # get和save都在等待...很慢...
    [root@bogon test]# redis-cli
    127.0.0.1:6379> save
    OK
    (152.59s)
    127.0.0.1:6379> get qvbilam
    "angel"
    (150.63s)
    # 可以看到等待了150s!!!
    # 文件压缩1006277712->317777896
    -rw-r--r--. 1 root root 317777896 6月  27 11:42 dump-6379.rdb
  2. bgsave是否开启子进程.是否阻塞

    # 查看当前redis进程
    [root@bogon data]# lsof -i:6379
    COMMAND     PID USER   FD   TYPE  DEVICE 
    redis-ser 62792 root    6u  IPv6 3904775  
    redis-ser 62792 root    7u  IPv4 3904776   
    redis-ser 62792 root    8u  IPv4 3905341
    redis-ser 62792 root    9u  IPv4 3909079     
    redis-cli 62883 root    3u  IPv4 3905340  
    redis-cli 63494 root    3u  IPv4 3909078  
    
    # bgsave 立即返回
    127.0.0.1:6379> bgsave
    Background saving started
    # 另一个client立刻返回
    127.0.0.1:6379> get qvbilam
    "angel"
    # 多了一个进程
    [root@bogon data]# lsof -i:6379
    COMMAND     PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
    redis-ser 62792 root    6u  IPv6 3904775      0t0  TCP *:6379 (LISTEN)
    redis-ser 62792 root    7u  IPv4 3904776      0t0  TCP *:6379 (LISTEN)
    redis-ser 62792 root    8u  IPv4 3905341  
    redis-ser 62792 root    9u  IPv4 3909079   
    redis-cli 62883 root    3u  IPv4 3905340   
    redis-cli 63494 root    3u  IPv4 3909078    
    redis-ser 66969 root    8u  IPv4 3905341  
    redis-ser 66969 root    9u  IPv4 3909079 
    # 还在执行,可以看到临时文件还没有替换dump
    -rw-r--r--. 1 root root 317777896 6月  27 11:42 dump-6379.rdb
    -rw-r--r--. 1 root root 259260459 6月  27 11:59 temp-66969.rdb
    # 执行结束
    -rw-r--r--. 1 root root 317777896 6月  27 11:59 dump-6379.rdb
    
    # 看日志
    46    62792:M 27 Jun 2019 11:35:43.499 * DB loaded from disk: 0.722 seconds
    47    62792:M 27 Jun 2019 11:35:43.500 * Ready to accept connections
    48    62792:M 27 Jun 2019 11:42:16.608 * DB saved on disk
    49    62792:M 27 Jun 2019 11:56:35.613 * Background saving started by pid 66969
    50    66969:C 27 Jun 2019 11:59:30.522 * DB saved on disk
    51    66969:C 27 Jun 2019 11:59:30.544 * RDB: 0 MB of memory used by copy-on-write
    52    62792:M 27 Jun 2019 11:59:30.649 * Background saving terminated with success
  3. save自动生成配置文件

    # 修改save配置
    vim config/redis_rdb.conf
    # 修改或添加
    save 60 5  //50秒内修改5次自动保存
    # 保存重启服务
    redis-server config/redis_rdb.conf
    # 查看rdb文件时间
    6月  27 11:59 dump-6379.rdb
    # 快速修改5条
    127.0.0.1:6379> set q w
    OK
    127.0.0.1:6379> set w e
    OK
    127.0.0.1:6379> set e r
    OK
    127.0.0.1:6379> set r t
    OK
    127.0.0.1:6379> set t f
    OK
    # 查看日志满足5条,自动备份
    12:13:36.875 * 5 changes in 60 seconds. Saving...
    12:13:36.886 * Background saving started by pid 70373
    # rdb文件时间
    6月  27 12:14 temp-70373.rdb

RDB缺点

  RDB方式的缺点:耗时,耗性能,不可控制,数据容易丢失.例如:在第一步执行多个写入命令,第二步骤满足RDB自动创建条件,开始写文件,第三部再次执行多个写入命令个,第四部出现宕机.那么第三部到第四部之间的数据写入就会丢失.就算用脚本定时执行.也无法保证出现宕机的情况.

AOF

  相当于记录每次的命令到日志.比如在客户端执行一条增删改命令,就在日志文件中追加该命令.当使用RDB出现宕机的情况,就可以采用AOF对数据进行完整的恢复.当redis重启后,将AOF文件载入从而进行数据的恢复.写文件的机制是将命令写到硬盘的缓冲区.redis再通过内部命令刷新到磁盘.从而提高写入的效率(因为直接写入到磁盘效率很慢).

三种策略

配置说明优点缺点
always每条命令都会刷新到磁盘中不丢失数据IO开销很大
everysec(推荐)将每秒产生的命令刷新到磁盘中,默认值是1秒每秒进行sync,只丢失一秒间产生的数据丢一秒数据(如果一秒内写入量很大)
No(不推荐)根据操作系统决定,不需要去管不用管不可控,也不知道丢多少数据

AOF重写

  原生的AOF就是将每条命令都执行,假如有一个ke执行自增+1,一下加了1万次.那么在AOF中就相当于写了1万条的自增,这是非常占用资源,而且恢复速度也会因为执行1万次而变慢的.当使用了AOF重写就解决了这样的问题.AOF重写实现有两种方式.即gbrewirteaofAOF重写配置.AOF重写并不是真的将原来的AOF文件进行归类重写.其实就是将内存的数据进行一次回溯,回溯成AOF文件.

gbrewirteaof

  实现方式:创建子进程对AOF重写的过程,类似于bgsave重写RDB.

重写配置说明

  当达到两个条件才会进行AOF重写,必须是同时满足才会尽心!

  1. aof_corrent_size > auto-aof-rewrite-min-size,当前文件尺寸大于配置中设置的AOF文件最小大小.就满足条件1
  2. (aof_corrent_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage,当前文件大小减去重启前(上次重写)的大小就等于增长了AOF的大小.再用增长的大小除以上次重写的大小就是增长率.当增长率大于配置中的增长率.就属于满足条件2.
配置名说明
auto-aof-rewrite-min-sizeAOF文件大小,达到多少开始重写
auto-aof-rewrite-percentageAOF文件增长多少倍后进行重写
统计名说明
aof_corrent_sizeAOF当前大小(字节)
aof_base_sizeAOF上次启动和重写的尺寸

重写配置

# 开启AOF功能的使用,默认no
appendonly yse
# 设置AOF文件名
appendfilename "appendonly-6379.aof"
# 每秒同步策略
appendfsync everysec
# 在AOF操作时候是否不进行append,建议yse
# yes,对性能好.但是会造成数据丢失
# no,非常消耗性能
no-appendfsync-on-rewrite yes
# 设置重写增长率和最小尺寸
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# 如果AOF不完整或有问题,重启加载是否忽略重写的错误
aof-load-truncated yes

测试

# redis启动不建议暂停服务再修改配置.
# 获取动态配置
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "no"
# 设置动态配置
127.0.0.1:6379> config set appendonly yes
OK
# 对配置重写
127.0.0.1:6379> config rewrite
OK

# 执行字符串修改操作 
127.0.0.1:6379> set name_zcx sb
OK
127.0.0.1:6379> set name_zcx pig
OK
127.0.0.1:6379> set name_zcx dog
OK
# 生成配置的文件
222 6月  27 17:32 appendonly-6379.aof
# 查看aof文件
$3
set
$8
name_zcx
$3
pig
*3
$3
set
$8
name_zcx
$3
dog
# $n 是指下面的操作有多少个字节
# *3 修改了三次

RDB vs AOF

  当开启了RDB又开启了AOF.在redis挂掉重启后会优先加载APF.因为AOF数据级别高,保存的的数据比RDB更新.

RDBAOF
启动优先级
文件大小小(压缩二进制文件)大(日志类型文件)
恢复速度
数据安全性丢数据根据配置的策略决定
操作轻重
建议
Last modification:February 18th, 2020 at 10:18 pm