11<h3 style =" padding-bottom :6px ; padding-left :20px ; color :#ffffff ; background-color :#E74C3C ;" >Redis持久化</h3 >
22
3+ ![ persistence] ( https://i.loli.net/2019/02/13/5c63bb6ce9d5f.jpeg )
4+
35Redis 是一种基于内存的数据库,一旦断电、重启,Redis 中的数据将不复存在。Redis 提供了 RDB 和 AOF 两个持久化的方式。当 Redis 实例重启时,可以使用已持久化的数据(文件)来还原内存数据集。
46
57
@@ -8,18 +10,144 @@ Redis 是一种基于内存的数据库,一旦断电、重启,Redis 中的
810
911<h3 style =" padding-bottom :6px ; padding-left :20px ; color :#ffffff ; background-color :#E74C3C ;" >RDB</h3 >
1012
11- ** RDB** 的全称是 * Redis DataBase* ,Redis 数据库。这种持久化方式是将当前Redis内存中的数据生成快照文件保存到硬盘,简单粗暴。
13+ ** RDB** 的全称是 * Redis DataBase* ,Redis 数据库。这种持久化方式是将当前Redis内存中的数据生成 ** 快照(Snapshot)** 文件保存到硬盘,简单粗暴。RDB也是Redis默认开启的持久化方式。
14+
15+
16+
17+ ##### 触发持久化
18+
19+ ![ save] ( https://i.loli.net/2019/02/13/5c63c0174e045.png )
20+
21+ 在之前已经废弃的 ` save ` 命令来实现RDB持久化数据,` save ` 命令持久化时会一直阻塞,直到持久化完成。数据量越大,持久化过程带来的阻塞时间就越长。
22+
23+ ![ bgsave] ( https://i.loli.net/2019/02/13/5c63c02cc0753.png )
24+
25+ 现在可以使用 ` bgsave ` 命令来代替 ` save ` 。bg就是background,使用 ` bgsave ` 方式RDB持久化时,Redis工作进程会 fork 一个子进程,该子进程专门来负责耗时的RDB持久化,而工作进程会继续工作,阻塞时间只发生在短暂的 fork 阶段。
26+
27+
28+
29+ 除了主动触发命令外,Redis还是提供了自动触发RDB持久化命令 ` bgsave <seconds> <changes> ` ,该命令表示在seconds秒内,Redis内存数据修改的次数达到changes次时,将触发RDB持久化。比如 ` bgsave 7200 10 ` 表示在2个小时内,数据被更改10次时将自动触发RDB持久化。
30+
31+ (注意changes计数并不包含查询语句,当然被操作的key一定存在,否则也不会进行计数)
32+
33+ 作者现在测试使用的是 ` 4.0.9 ` 版本,Redis在此版本默认开启的参数是 ` save 900 1 ` 、` save 300 10 ` 、` save 60 10000 ` ,更加实际情况可自定义更改。
34+
35+
36+
37+ ##### 数据快照存储
38+
39+ 首先,工作目录默认为当前Redis目录,那么持久化的RDB数据快照将存储在该目录,可通过 ` dir ./ ` 参数进行修改。生成的数据存储快照名称默认为 ` dump.rdb ` ,可通过 ` dbfilename dump.rdb ` 参数进行修改。RDB持久化先生存一个临时快照,待数据持久化完成,这个临时快照会替换原快照,以防持久化过程出现问题。
40+
41+ RDB存储快照默认是使用LZF算法压缩功能,压缩后的文件体积将大大减少。压缩文件但并不是十全十美,RDB快照压缩时也会消耗CPU,数据量越大,消耗CPU资源就越多,但官网还是极力推荐我们开始此功能。
42+
43+ RDB持久化时可能出现权限问题、存储空间不够用等问题,Redis 默认开启` stop-writes-on-bgsave-error yes ` 参数,意味着出现 error时,Redis将停止向快照文件写入数据。
44+
45+ 在Redis保存/恢复数据时,并不是一股脑进行保存/恢复,默认会对RDB快照文件进行检查,性能会受到影响(大约10%),因此可以禁用它以获得最大的性能。(推荐开启)
46+
47+
48+
49+ ---
50+
51+ <h3 style =" padding-bottom :6px ; padding-left :20px ; color :#ffffff ; background-color :#E74C3C ;" >AOF</h3 >
52+
53+ ** AOF** 的全称是 * Append Only File* ,仅附加文件,类似于MySQL的binlog。这种持久化方式是通过保存写命令来记录操作日志,在数据恢复时,重新执行已记录的写命令,来达到数据恢复。
54+
55+
56+
57+ ##### AOF原理
58+
59+ ![ AOF] ( https://i.loli.net/2019/02/13/5c63dd9d9f120.png )
60+
61+ 默认情况下,AOF是关闭的,可以通过修改 ` appendonly no ` 为 ` appendonly yes ` 来开启 AOF 持久化。内存的Output的带宽远大于磁盘Input的带宽,如果内存瞬时将大量的数据写入磁盘,必然发生IO堵塞,对于单线程工作的Redis也将会在性能上大打折扣。所以所有的写命令并不会直接写入AOF文件,而是先将写命令存储至AOF Buffer缓冲区,最后在同步至AOF文件。
62+
63+ 生成的AOF文件名,默认为 ` appendonly.aof ` ,可以修改 ` appendfilename "appendonly.aof" ` 参数来更改生成的AOF文件名。
64+
1265
1366
67+ 从缓冲区同步至磁盘,Redis提供了三种同步方式:
1468
15- 在之前的、已经废弃的 ` save ` 命令来实现RDB持久化数据,因为Redis是单线程工作的, ` save ` 命令持久化时会一直阻塞,直到持久化完成。数据量越大,持久化带来的阻塞时间就越长。
69+ ** always: ** 写命令被追加到AOF缓存后,调用系统fsync函数将缓冲区的数据同步至磁盘,最后返回
1670
17- 现在可以使用 ` bgsave ` 命令来代替 ` save ` 。bg就是background,使用 ` bgsave ` 方式RDB持久化时,Redis工作进程会 fork 一个子进程,该子进程专门来负责RDB持久化,而工作进程会继续工作,阻塞时间只发生。
71+ ** everysec: ** 写命令被追加到AOF缓存后,调用系统write函数,在write函数执行完成,然后返回,会触发系统将对缓冲区的数据进行同步至磁盘
1872
73+ ** no:** 写命令被追加到AOF缓存后,调用系统write函数,然后返回,后续的同步由系统负责
1974
75+ 其中 ` everysec ` 不仅是默认的方式,也是推荐的方式。
76+
77+
78+
79+ ##### AOF重写机制
80+
81+ AOF持久化文件存储的是Redis写命令,这比仅仅是数据的存储文件要大了很多,而且像如下的命令就可以考虑做很多优化:
82+
83+ ``` shell
84+ 127.0.0.1:6379> set user:10001 Kevin
85+ OK
86+ 127.0.0.1:6379> del user:10001
87+ (integer) 1
88+ 127.0.0.1:6379> set user:10002 Jack
89+ OK
90+ 127.0.0.1:6379> del user:10002
91+ (integer) 1
92+ 127.0.0.1:6379> set user:10003 Tony
93+ OK
94+ 127.0.0.1:6379> del user:10003
95+ (integer) 1
96+ ```
97+
98+ 上述命令都是些命令,最终是空数据,如果都存储到AOF文件,不仅增大文件体积,而且在恢复数据时会有很多不必要的执行命令。AOF重写机制对持久化的命令做了优化。
99+
100+ 在AOF重写机制中,首先遍历数据库,如果数据库为空库,则跳过该库。对于非空的数据库,则遍历所有的key,如果key过期则跳过该key,如果key有过期时间则设置key的过期时间。对于不同类型的数据,用不同的、最简单的写命令来保存,比如下面的命令:
101+
102+ ``` shell
103+ # 假设一开始 user 对应的 value 为空
104+ lpush user kevin
105+
106+ lpush user jack
107+
108+ lpush user tony
109+
110+ rpop user
111+
112+ lpop user
113+ ```
114+
115+ 可以重写成:
116+
117+ ``` shell
118+ lpush user jack
119+ ```
120+
121+ 这样大大减少了不必要的命令,在存储AOF文件时,文件的体积也会大大减少,而且恢复数据的效率也会大大提升。
122+
123+
124+
125+ AOF的重写机制并不是随机触发的,默认是当前写入AOF文件大小较上次重写后文件大小增长了 ` 100% ` 时就触发重写机制。比如上次重写后的文件大小是1G,经过一段时间,AOF文件体积增长了 ` 1G ` ,那么增长率就是 ` 100% ` ,就会触发AOF重写。可以通过设置 ` auto-aof-rewrite-percentage 100 ` 来调节文件增长率的触发阈值。
126+
127+ 如果AOF的文件较少,不足以影响太大性能,所以没必要重写AOF文件。可以通过 ` auto-aof-rewrite-min-size 64mb ` 来设置AOF文件重写的最小阈值。
128+
129+
130+
131+ ` aof-load-truncated yes ` 参数表示,在Redis恢复数据时,最后一条命令可能不完整,开启则表示忽略最后一条不完整的命令。
20132
21133
22134
23135---
24136
25- <h3 style =" padding-bottom :6px ; padding-left :20px ; color :#ffffff ; background-color :#E74C3C ;" >AOF</h3 >
137+ <h3 style =" padding-bottom :6px ; padding-left :20px ; color :#ffffff ; background-color :#E74C3C ;" >RDB和AOF对比</h3 >
138+
139+ RDB开始压缩后,生成一个体量更小、更紧凑的二进制文件,占有空间小。RDB不仅有着较快的数据恢复能力,而且可以直接复制RDB文件至其他Redis实例进行回复数据,有着良好的容灾体验。RDB适用于定时复制、全量复制、快速恢复的场景,由于RDB文件生成时间长,数据有存储延迟,不适用于近实时持久化的场景。
140+
141+
142+
143+ AOF以追加命令的方式,持续的、近实时的写入文件(秒级别)。而且,在一定程度时,AOF不断的重写持久化文件,不断的优化。特别是在数据完整性上要比RDB好很多,例如,使用默认的数据同步策略,Redis在发生服务器断电等重大事件时,可能只丢失一秒钟的写入时间,或者在Redis进程本身发生错误但操作系统仍在正常运行时丢失一次写入时间。所以AOF比较适合对数据实时性和数据完整性要求比较高的场景。AOF相较于RDB,缺点是文件相对较大,而且恢复数据时因为要执行全部的写命令,所以数据恢复比较慢,特别在是在被依赖的应用系统高负载的情况下,较长时间的数据恢复,对后端系统是不可容忍的。
144+
145+
146+
147+ 但AOF和RDB持久性可以同时启用,不会出现问题。如果在启动时启用了AOF,redis将加载AOF,即具有更好的持久性保证的文件。而且在较新的版本还支持混合模式。
148+
149+
150+
151+ #### RDB-AOF混合持久化
152+
153+ Redis从 ` 4.0 ` 开始支持RDB-AOF混合持久化,默认是关闭状态,可以通过 ` aof-use-rdb-preamble yes ` 开启。AOF文件在重写之后,将生成一份记录已有数据的RDB快照文件,再生成一份记录最近写命令的AOF文件,作为对RDB快照的补充。这样的混合持久化模式,将兼具RDB和AOF的双优特性。
0 commit comments