从上篇 RedisTemplate 可没你想的那么简单 完结后,整个 Redis 的客户端相关的就弄完了,主要是
Jedis
、Lettuce
、RedisTemplate
三篇。有不熟悉的好哥哥能够去个人文章那里翻翻,说不定就会有不同的收获。今天的这篇的话是关于 Redis 持久化相关的第一篇,后续应该会有几篇关于持久化的,好哥哥们好好看,主要是要动手操做起来。固然若是只是为了应付面试的话能够大概的看看,可是仍是建议这一块相关的东西系统的看看。看完记得点赞加关注哟。
面试
Redis 系列第一篇 初识 Redis 中就有提到说 Redis 是一个基于内存的非关系性数据库。那所谓内存数据库,就是将数据库中的内容保存在内存中,这与传统的MySQL
,Oracle
等关系型数据库直接将内容保存到硬盘中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写效率)。可是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的数据将会所有丢失。
为了解决这个缺点,Redis 提供了将内存数据持久化到硬盘,以及用持久化文件来恢复数据库数据的功能。Redis 支持两种形式的持久化,一种是RDB
快照(snapshotting),另一种是AOF
(append-only-file)。redis
RDB
持久化是把当前进程数据生成快照保存到硬盘的过程。可以在指定时间间隔内对数据进行快照存储,默认状况下,Redis 将数据快照保存在dump.rdb
这个二进制的文件中。触发RDB
持久化过程分为手动触发和自动触发。算法
上面有提到触发分为手动触发和自动触发。手动触发又分红了两种方式,第一种使用save
,第二种使用bgsave
。shell
save
会阻塞当前 Redis 服务器,直到RDB
过程完成为止,对于内存比较大的实例会形成长时间阻塞,线上环境不建议使用。命令以下:数据库
127.0.0.1:6379> save
OK
复制代码
上面提到了就是save
是一个阻塞操做。假设在生产环境中使用这个命令,若是数据量够大,那么会使 Redis 服务器阻塞的时间很是长,致使 Redis 服务的不可用。bgsave
就是用来解决这个问题的,bgsave
执行时,Redis 进程会执行fork
操做建立子进程,RDB 持久化过程由子进程负责,完成后自动结束。阻塞只发生在 fork 阶段,通常时间很短。数组
127.0.0.1:6379> bgsave
Background saving started
复制代码
整个过程以下:
服务器
命令 | save | bgsave |
---|---|---|
类型 | 同步 | 异步 |
是否阻塞 | 是 | 只有在 fork 是阻塞的 |
优势 | 没有额外的内存消耗 | 不会阻塞服务器 |
缺点 | 阻塞服务器 | 须要 fork 建立子进程,额外消耗内存 |
除了执行命令手动触发以外,Redis 内部还存在自动触发RDB
的持久化机制。触发的逻辑是 Redis 在 N 秒内有 M 个键被改动,好哥哥们能够经过修改配置文件来实现对RDB
的自动触发。默认配置以下:markdown
## 表示 900 秒内若是至少有 1 个 key 的值变化,则触发
save 900 1
## 表示300 秒内若是至少有 10 个 key 的值变化,则触发
save 300 10
## 表示60 秒内若是至少有 10000 个 key 的值变化,则触发
save 60 10000
复制代码
其余 RDB 相关配置:网络
## bgsave写入错误是否中止写入
stop-writes-on-bgsave-error yes
## 是否对rdb文件使用压缩格式
rdbcompression yes
## 是否对rdb文件校验
rdbchecksum yes
## rdb持久化名称
dbfilename dump.rdb
## rdb持久化存放目录
dir ./
复制代码
Redis 服务器维护了一个状态结构,其中包括save条件的数组(saveparams)
、计数器(dirty)
、上次保存时间(lastsave)
。前面咱们在 redis.conf
配置文件中进行了关于save
的配置,解析成条件的数组后就是下面的样子:
当服务器成功执行一次修改操做,那么计数器(dirty)
就会加 1。而lastsave
属性记录上一次执行save
或bgsave
的时间,Redis 服务器还有一个周期性操做函数 severCron
,默认每隔 100 毫秒就会执行一次,该函数会遍历并检查 saveparams
数组中的全部保存条件,只要有一个条件被知足,那么就会执行 bgsave
命令。 执行完成以后,计数器(dirty)
更新为 0 ,lastsave
也更新为执行命令的完成时间。app
假设哪天有哪位好哥哥执行了FLUSHALL
命令(千万别再生产上使用这个命令哦),把全部数据都清了,这时不要慌将备份文件dump.rdb
(前提是你的快照生成的时机在FLUSHALL
以前) 移动到 Redis 安装目录并启动服务便可,Redis 就会自动加载文件数据至内存了。Redis 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工做完成为止。获取 Redis 的安装目录可使用下面的命令。
config get dir
复制代码
看这个文件我已经快瞎了,因此我在解释前面都加了行号(够贴心了吧,这还不点赞加关注吗)。
➜ go-redis-parser od -A x -t x1c -v ./teststub/dumpV9.rdb
000000 52 45 44 49 53 30 30 30 39 fa 09 72 65 64 69 73
R E D I S 0 0 0 9 372 \t r e d i s
000010 2d 76 65 72 05 35 2e 30 2e 35 fa 0a 72 65 64 69
- v e r 005 5 . 0 . 5 372 \n r e d i
000020 73 2d 62 69 74 73 c0 40 fa 05 63 74 69 6d 65 c2
s - b i t s 300 @ 372 005 c t i m e 302
000030 71 8a 8d 5d fa 08 75 73 65 64 2d 6d 65 6d c2 30
q 212 215 ] 372 \b u s e d - m e m 302 0
000040 e0 0f 00 fa 0c 61 6f 66 2d 70 72 65 61 6d 62 6c
340 017 \0 372 \f a o f - p r e a m b l
000050 65 c0 00 fe 00 fb 06 00 f9 00 00 01 73 01 61 f9
e 300 \0 376 \0 373 006 \0 371 \0 \0 001 s 001 a 371
000060 03 0e 02 6c 69 01 11 11 00 00 00 0d 00 00 00 02
003 016 002 l i 001 021 021 \0 \0 \0 \r \0 \0 \0 002
000070 00 00 01 61 03 01 62 ff f9 00 02 03 73 65 74 02
\0 \0 001 a 003 001 b 377 371 \0 002 003 s e t 002
000080 01 62 01 61 f9 00 0f 06 73 74 72 65 61 6d 01 10
001 b 001 a 371 \0 017 006 s t r e a m 001 020
000090 00 00 01 6d 70 b5 4a 7e 00 00 00 00 00 00 00 00
\0 \0 001 m p 265 J ~ \0 \0 \0 \0 \0 \0 \0 \0
0000a0 40 52 52 00 00 00 18 00 03 01 00 01 02 01 84 6e
@ R R \0 \0 \0 030 \0 003 001 \0 001 002 001 204 n
0000b0 61 6d 65 05 83 61 67 65 04 00 01 02 01 00 01 00
a m e 005 203 a g e 004 \0 001 002 001 \0 001 \0
0000c0 01 87 4c 61 6d 62 65 72 74 08 1d 01 05 01 02 01
001 207 L a m b e r t \b 035 001 005 001 002 001
0000d0 f2 33 8c 00 04 00 01 84 4a 61 63 6b 05 1a 01 05
362 3 214 \0 004 \0 001 204 J a c k 005 032 001 005
0000e0 01 02 01 f2 9c ad 00 04 00 01 83 54 6f 6d 04 1e
001 002 001 362 234 255 \0 004 \0 001 203 T o m 004 036
0000f0 01 05 01 ff 03 81 00 00 01 6d 70 b5 f8 1a 00 01
001 005 001 377 003 201 \0 \0 001 m p 265 370 032 \0 001
000100 05 67 72 6f 75 70 00 00 00 00 f9 00 0c 04 7a 73
005 g r o u p \0 \0 \0 \0 371 \0 \f 004 z s
000110 65 74 15 15 00 00 00 12 00 00 00 04 00 00 01 61
e t 025 025 \0 \0 \0 022 \0 \0 \0 004 \0 \0 001 a
000120 03 f2 02 01 62 03 f3 ff f9 03 0d 01 68 11 11 00
003 362 002 001 b 003 363 377 371 003 \r 001 h 021 021 \0
000130 00 00 0d 00 00 00 02 00 00 01 61 03 01 61 ff ff
\0 \0 \r \0 \0 \0 002 \0 \0 001 a 003 001 a 377 377
000140 0e e0 f7 31 2f 37 16 df
016 340 367 1 / 7 026 337
000148
复制代码
这是一个 version 9
的 RDB
文件,主要表达内容以下:
在第 000000
前 9 个字节是一个魔数,5 个字节 REDIS 和 4 个字节的版本号 0009。
通用字符串字段,用于向 RDB
添加状态,Version 7
加入的,向后兼容。AUX
字段由键和值两个字符串组成。主要有如下字段:
000050
的 fe(0xfe)
,fb(0xfb)
是 10 进制的 254 和 251,在 RDB 中国分别对应SELECT_DB
和RESIZE_DB
。 每个 SELECTDB
后都会紧跟着RESIZEDB
,后者表示的是当前数据库hashtable
键大小的提示,每次切换数据库时提早读到,避免没必要要的rehash
。
这里的话就列举基础数据类型
000050
的 00(0x00)
是 10 进制的 0,表示String
类型的对象,01 指key
是一个字节长度:s
, value
也是一个字节长度:a
。
000060
的0e(0x0e)
是 10 进制的 14,表示List
类型的对象。 2 个字节长度的key
是li
,接下来分别是一个长度的items
:a
和 b
000070
的002
,表示 Set 类型对象,3 个长度 set
,两个members
:a
和 b
000100
的0c
是 10 进制的 12,以ziplist
结构存储的Sortedse
t 类型,4 个长度的key:zset
,接下来的 4 表示:4 个元素,zset
会将member
和score
一块儿保存,因此,就是 2 组members
;分别是:{memeber:"a",score:1}
、{member:"b",score:2}
。
000120
的0d(13)
是RDB_TYPE_HASH_ZIPLIST
,表示是ziplist
存储的hash
类型数据,1 个长度的 key:h
。 key
后面的 2,存着 hash
结构的 field
和 value
;在 field
和 value
前面的 1,分别是指各自的长度,都是 a
。
000130
的ff(255) EOF
,在全部数据写完结束后,会以一个EOF
结尾。
从Version 5
开始,若是在配置文件中开启rdbchecksum yes
(上面解释过这个配置),会在RDB
文件的结尾处,用 8 个字节记录,经过CRC64
算法计算的整个文件内容的校验和。
RDB
文件保存在dir
配置指定的目录下,文件名经过dbfilename
配置指定。能够经过执行config set dir{newDir}
和config setdbfilename{newFileName}
运行期动态执行,当下次运行时RDB
文件会保存到新目录。config set dir{newDir}
在线修改文件路径到可用的磁盘路径,以后执行bgsave
进行磁盘切换,一样适用于AOF
持久化文件。RDB
文件作压缩处理,压缩后的文件远远小于内存大小,默认开启,能够经过参数config set rdbcompression{yes|no}
动态修改。RDB
会消耗CPU
,可是能大幅下降文件的大小,方便保存到硬盘或经过网络发送给从节点,所以线上建议开启。RDB
文件是单一紧凑的二进制文件,比较适合作冷备,全量复制的场景。能够将一个时间内产生的RDB
文件复制到本地或者存储到云端,这样能够产生多个不一样时间段内的数据备份,从而达到容灾恢复。RDB
对 Redis 对外提供的读写服务,影响很是小,可让 Redis 保持高性能,由于 Redis 主进程只须要fork
一个子进程,让子进程执行磁盘IO
操做来进行RDB
持久化便可。AOF
(下篇会弄它)持久化机制来讲,直接基于 RDB 数据文件来重启和恢复 Redis 进程,更加快速,由于RDB
存储的就是数据,而AOF
存储的是操做命令。RDB
持久化丢失的数据可能会比AOF
多。由于RDB
是按照时间保存的快照,因此若是在这个时间段内没有执行RDB
操做,那这段时间的数据就丢失了。RDB
持久化一般都要fork
一个子进程来执行。当数据量较大时,fork
的过程是比较耗时的。RDB
没法实现实时或者秒级持久化。本期就到这啦,有不对的地方欢迎好哥哥们评论区留言,另外求关注、求点赞