【Redis学习笔记】09 Redis 数据持久化

1. 持久化概述

Redis 是一个内存数据库,如果没有持久化功能,当 Redis 重启、宕机、掉电等情况发送时,所有存储在内存中的数据就会丢失,这种情况在某些应用场景下时不允许发生的,例如:(1)将 Redis 作为数据库使用;(2)将 Redis 作为缓存服务器,但是缓存被穿透后会对性能造成较大影响,所有缓存同时失效会导致缓存雪崩,从而使服务无法响应。

如果不使用持久化,那么当 Redis 重启后,所有的数据都会丢失

# Redis 重启之前有很多的 key
127.0.0.1:6379> KEYS *
1) "k3"
2) "k1"
3) "text"
4) "coupons"
5) "num1"
6) "k5"
7) "k2"
8) "k4"
127.0.0.1:6379> exit
# 当 Redis 重启之后,所以有的 key 全部丢失了
~]# systemctl restart redis-6379.service
~]# redis-cli 
127.0.0.1:6379> KEYS *
(empty list or set)

这时我们就希望 Redis 能将数据从内存以某种形式同步到磁盘中,使得重启后可以根据硬盘中的记录恢复数据,这一过程就是持久化。

Redis 支持 RDB 和 AOF 两种方式的持久化。前者会根据指定的规则定时将内存中的数据存储到磁盘上,后者在每次执行命令后将写数据的命令本身记录下来。两种持久化方式可以单独使用,也可以同时使用。

2. RDB 持久化

RDB 方式就类似快照,当符合一定触发条件的时候,Redis 会自动将内存中的所以有数据打一个快照,并存储在磁盘中

2.1. RDB 持久化优点

1. 压缩格式,RDB 文件紧凑
2. 全量备份,非常适合用于进行备份和灾难恢复
3. RDB 在恢复大数据集的数据时比 AOF 的恢复速度要快

2.2. RDB 持久化缺点

1. 不是实时的,可能会丢数据
2. 操作比较重量(看 RDB 持久化原理)

2.3. RDB 持久化原理

  1. 当 RDB 满足触发条件时,Redis 会调用系统函数 fork(),创建一个子进程进行持久化
  2. 子进程将数据集写入到一个临时的 rdb文件中,当子进程完成对临时 rdb 文件的写入时,Redis 用新的 rdb 文件替换原来旧的 rdb 文件,并将旧的 rdb 文件删除

2.4. RDB 触发方式

命令 概述
save 触发方式 该命令会阻塞当前 Redis 服务器,执行 save 命令期间,Redis 不能处理其他命令,直到 RDB 过程完成为止
bgsave 触发方式 执行该命令时,Redis 会在后台异步进行快照操作,快照同时还可以响应客户端请求
配置文件自动触发 save m n:表示 m 秒内数据集存在 n 次修改时,自动触发 bgsave。
stop-writes-on-bgsave-error 默认值为 yes。当启用了 RDB 且最后一次保存数据失败,Redis 是否停止接收数据。
rdbcompression 默认值为 yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。
rdbchecksum 默认值为 yes。在存储快照后,我们还可以让 Redis 使用 CRC64 算法来进行数据校验,但是这样做会增加大约 10% 的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。
dbfilename 设置快照的文件名,默认时 dump.rdb
dir 设置快照文件的存放路径,这个配置项一定是一个目录,而不能是文件名。

2.5. save 和 bgsave 对比

命令 save bgsave
IO 类型 同步 异步
阻塞? 是(阻塞发生在 fork)
复杂度 O(n) O(n)
优点 不会消耗额外内存 不阻塞客户端命令
缺点 阻塞客户端命令 需要 fork,消耗内存

2.6. 配置 RDB 参数

2.6.1. 普通参数

# 这里save后面第一参数表示时间(秒),第二参数表示改变量,合在一起的意思是多少秒内发生多少改变量后才保存一次
save 900 1
save 300 10
save 60 10000

# 保存快照数据使用的文件名
dbfilename redis.rdb

# 快照文件保存的路径
dir /data/redis/6379

为什么有 3 个 save 呢?是为了保障在不同情况下数据保存文件的最小化

2.6.2. 高级参数

# 后台备份进程出错时,主进程停不停止写入?主进程不停止容易造成数据不一致
stop-writes-on-bgsave-error yes

# 导出的rdb文件是否压缩,如果rdb的大小很大的话建议这么做
rdbcompression yes

# 导入rdb恢复数据时,要不要检验rdb的完整性,验证版本是不是一致
rdbchecksum yes

2.7. RDB 持久化操作

RDB 持久化不是实时保存数据,需要一个过程

2.7.1. 配置 RDB 持久化

~]# cat /opt/redis/6379/etc/6379.conf
daemonize yes
bind 127.0.0.1 192.168.66.51
port 6379
pidfile /opt/redis/6379/pid/6379.pid
logfile /opt/redis/6379/logs/6379.log
dir /data/redis/6379
dbfilename 6379.rdb
save 900 1
save 300 10
save 60 10000

修改完成配置文件之后,重新启动 Redis

systemctl restart redis-6379.service

2.7.2. 创建测试数据是否生成rdb文件

# 1. 创建测试数据
~]# redis-cli 
127.0.0.1:6379> KEYS *
(empty list or set)
127.0.0.1:6379> SET k1 v1
OK
127.0.0.1:6379> SET k2 v2
OK
# 2. 观察并未生成 rdb 文件
 ~]# ll /data/redis/6379/
total 0

# 3. 手动执行 bgsave
127.0.0.1:6379> BGSAVE
Background saving started

# 4. 再次观察,发现生成了 rdb 文件
~]# ll /data/redis/6379/
total 4
-rw-r--r-- 1 redis redis 111 Mar 10 17:38 6379.rdb
# 5. 批量创建数据,触发生成 rdb 文件
~]# for i in {1..15000};do redis-cli set k_${i} v_${i}; echo "${i} is ok";done

# 6. 观察,发现生成了新的 rdb 文件
~]# ll /data/redis/6379/6379.rdb 
-rw-r--r-- 1 redis redis 103273 Mar 10 17:43 /data/redis/6379/6379.rdb

# 7. 查看日志,可以看到触发了 save 300 10
~]# tailf /opt/redis/6379/logs/6379.log 
2076:M 10 Mar 2022 17:43:56.065 * 10 changes in 300 seconds. Saving...
2076:M 10 Mar 2022 17:43:56.066 * Background saving started by pid 9185
9185:C 10 Mar 2022 17:43:56.190 * DB saved on disk
9185:C 10 Mar 2022 17:43:56.191 * RDB: 4 MB of memory used by copy-on-write
2076:M 10 Mar 2022 17:43:56.213 * Background saving terminated with success
2076:M 10 Mar 2022 17:48:57.109 * 10 changes in 300 seconds. Saving...
2076:M 10 Mar 2022 17:48:57.110 * Background saving started by pid 17187
17187:C 10 Mar 2022 17:48:57.474 * DB saved on disk
17187:C 10 Mar 2022 17:48:57.474 * RDB: 2 MB of memory used by copy-on-write
2076:M 10 Mar 2022 17:48:57.551 * Background saving terminated with success

# 8. 执行shutdown命令
127.0.0.1:6379> SHUTDOWN
not connected> 

# 9. 观察日志
~]# tailf /opt/redis/6379/logs/6379.log
2076:M 10 Mar 2022 17:52:33.694 # User requested shutdown...
2076:M 10 Mar 2022 17:52:33.694 * Saving the final RDB snapshot before exiting.
2076:M 10 Mar 2022 17:52:33.705 * DB saved on disk
2076:M 10 Mar 2022 17:52:33.705 * Removing the pid file.
2076:M 10 Mar 2022 17:52:33.705 # Redis is now ready to exit, bye bye...

# 启动 redis
~]# systemctl start redis-6379
# 获取有多少个key,可以发现数据没有丢失
~]# redis-cli dbsize
(integer) 15002

2.8. RDB 持久化结论

  1. 配置了dir 和 dbfilename 参数,但是没配置save参数时:
    a. shutdown 不会持久化保存数据
    b. 可以手动执行 bgsave 命令进行持久化
  2. 配置 save 参数时:
    a. shutdown/kill/pkill 均会自动触发 bgsave 持久化保存数据
    b. pkill -9/kill -9 不会触发持久化(慎用)
  3. 恢复数据时:
    a.持久化数据文件要和配置文件中定义的路径和名称一样才能被识别
    b. RDB 持久化只有一个数据文件,迁移和备份只要这一个 rdb 文件即可

注意:RDB 高版本兼容低版本,低版本不能兼容高版本,例如:3.X的 rdb 文件可以导入到 5.X 的版本中,但是 5.X 的 rdb 文件不能导入到 3.X 的版本中

3. AOF 持久化

AOF 会记录服务执行的所有写操作命令,并在服务启动时,通过重新执行这些命令来还原数据集

3.1. AOF 持久化优点

1. AOF的策略是每秒钟或者每次发生写操作的时候都会同步,因此即使服务器故障,最多只会丢失1秒的数据。 
2. AOF存储的是Redis命令,并且是直接追加到aof文件后面,因此每次备份的时候只要添加新的数据进去就可以了。
3. 如果AOF文件比较大了,那么Redis会进行重写,只保留最小的命令集合。

3.2. AOF 持久化缺点

1. AOF文件因为没有压缩,因此体积比RDB大。 
2. AOF是在每秒或者每次写操作都进行备份,因此如果并发量比较大,效率可能有点慢。
3. AOF文件因为存储的是命令,因此在灾难恢复的时候Redis会重新运行AOF中的命令,速度不及RDB。

3.3. AOF 持久化流程

3.4. AOF 持久化操作

3.4.1. 配置 AOF 持久化

# 2. 修改配置文件内容
 ~]# cat /opt/redis/6379/etc/6379.conf
daemonize yes
bind 127.0.0.1 192.168.66.51
port 6379
pidfile /opt/redis/6379/pid/6379.pid
logfile /opt/redis/6379/logs/6379.log
dir /data/redis/6379
appendonly yes
appendfilename "6379.aof"
appendfsync everysec
# 为了方便观察 AOF 持久化关闭 RDB处就会
#dbfilename 6379.rdb
#save 900 1
#save 300 10
#save 60 10000

# 3. 清理数据目录中的 rdb 文件
~]# ll /data/redis/6379/
total 4
-rw-r--r-- 1 redis redis 379 Mar 12 13:18 6379.rdb
~]# rm -f /data/redis/6379/6379.rdb 
~]# ll /data/redis/6379/
total 0

# 4. 重写启动redis
~]# systemctl restart redis-6379.service

3.4.2. 批量创建 key 并观察 aof 文件

# 1. 批量创建 15000 个 key
~]# for i in {1..15000};do redis-cli set k_${i} v_${i}; echo "${i} is ok";done
~]# ll -h /data/redis/6379/
total 512K
-rw-r--r-- 1 redis redis 508K Mar 12 13:35 6379.aof

3.4.3. 重启服务数据是否丢失

# 1. 关闭 Redis
~]# redis-cli 
127.0.0.1:6379> DBSIZE
(integer) 15000
127.0.0.1:6379> SHUTDOWN
not connected> 

# 2. 启动 Redis
~]# systemctl start redis-6379

# 3. 查看数据是否丢失
~]# redis-cli 
127.0.0.1:6379> DBSIZE
(integer) 15000

3.4.4. 观察 aof 文件内容

aof 文件中会记录 Redis 的所有更命令。删除、新增 key 都会记录在 aof 文件中,当 Redis 重启后,会将 aof 文件中的 命令还原到 Redis 中,从而保证数据的持久化。

~]# tail -10 /data/redis/6379/6379.aof 
k_14999
$7
v_14999
*3
$3
set
$7
k_15000
$7
v_15000

3.5. AOF 重写机制

redis是如何解决aof文件持续增大的问题的?

AOF 的特点就是记录服务运行过程中中产生的所有命令,如果又有 del 命令,当 AOF 文件的大小达到限制是,会触发内部的压缩命令,将 del 命令删除以及 del 之前创建的相关 key 从文件中删除,当服务再次重启时,重新执行这些命令来还原数据

执行的命令        aof记录            redis的数据       
set k1 v1        set k1 v1          k1                
set k2 v2        set k1 v1          k1 k2
                 set k2 v2          
set k3 v3        set k1 v1          k1 k2 k3
                 set k2 v2
                 set k3 v3      
del k1           set k1 v1          k2 k3
                 set k2 v2
                 set k3 v3
                 del k1
del k2           set k1 v1          k3
                 set k2 v2
                 set k3 v3
                 del k1
                 del k2
实际有意义的只有一条记录:
set k3

官方配置文件中内容:

# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.

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

配置的aof文件大小为64m,默认就是64m,当文件超过64m时,redis有自己的重写策略,会把aof中的删除命令全部删掉,保证文件的大小,也可以根据实际生产把文件大小给大。

4. AOF 和 RDB 读取实验

4.1. 实验背景

aof和rdb同时存在,redis重启会读取哪一个数据?

4.2. 实验步骤

# 1. 创建测试数据,并手动保存 rdb 文件
set k1 v1
set k2 v2
bgsave    # rdb 保存, k1 v2

# 2. 移动 rdb 文件
mv 6379.rdb /opt

# 3. 清空aof文件
flushall

# 4. 再次创建测试数据
set k3 v3
set k4 v4  # aof 保存 k3 k4

# 5. 移动 aof 文件
mv 6379.aof /opt

# 6. 停止 Redis, 清理持久化文件
redis-cli shutdown
rm -f /data/redis/6379/*

# 7. 移动之前的 rdb 和 aof 文件到持久化目录
mv /opt/redis.aof  /data/redis/6379
mv /opt/redis.rdb  /data/redis/6379

# 8. 启动服务,并查看 key
systemctl start redis

4.3. 实验结论

当 aof 和 rdb 同时存在时,重启 Redis 会优先读取 aof 的内容

5. 如何选择 RDB 还是 AOF

官网推荐:https://redis.io/topics/persistence
1. 开启混合模式
2. 开启aof
3. 不开启RDB,不设置触发器
4. rdb采用定时任务的方式定时备份
5. 可以从库开启RDB进行备份
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容