乐趣区

关于后端:redis持久化机制

[toc]

为什么有长久化机制背景

通过 redis 操作数据时,更多的时候是通过内存和 cpu 打交道,所以会特地快,然而内存有个毛病就是,一断电内存中的数据就没有了,那 redis 作者还是想尽可能的不失落内存中的数据,所以 redis 也有本人的长久化机制。

aof 机制

redis 执行完命令,会将执行胜利的命令写入 aof 日志,当 redis 宕机后,复原数据能够通过 aof 日志从新执行命令即可。

如何配置 AOF?

默认状况下,Redis 是没有开启 AOF 的,能够通过配置 redis.conf 文件来开启 AOF 长久化,对于 AOF 的配置如下:

# appendonly 参数开启 AOF 长久化 默认不开启
appendonly no

# AOF 长久化的文件名,默认是 appendonly.aof
appendfilename "appendonly.aof"

# AOF 文件的保留地位和 RDB 文件的地位雷同,都是通过 dir 参数设置的
dir ./

# 写回策略
# 每次执行命令保留一次
# appendfsync always
# 每秒保留一次
appendfsync everysec
# 由操作系统决定何时保留
# appendfsync no

# aof 重写期间是否同步
no-appendfsync-on-rewrite no

# 重写触发配置
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

# 加载 aof 出错如何解决
aof-load-truncated yes

# 文件重写策略
aof-rewrite-incremental-fsync yes

aof 写回策略

因为 redis 写 aof 日志到磁盘具备危险:

  1. 命令执行完,aof 日志还没来得及写入磁盘,宕机了,那么这个时间段内的数据不能被复原。
  2. 因为写入 aof 日志是应用主线程,如果写入磁盘数据变慢,会影响上面的命令操作。

所以开发者将 aof 日志写回磁盘的策略提取进去,不便不同场景来不同应用

  • Always 同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
  • Everysec 每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
  • No 操作系统管制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

写回策略视状况而定,如果你的零碎要求数据一点也不能丢,对性能没有太高的要求 能够抉择 Always, 如果零碎能够承受失落一点数据,那么最好抉择 Everysec,No 不举荐,可能会产生本人控制不了的后果。

aof 重写机制

因为 redis aof 日志一直地 append 会越来越大,影响效率;

  1. 影响插入效率,命令执行的效率;
  2. 应用 aof 日志复原的耗费的工夫也会变;

所以有了重写日志机制

大略逻辑:将雷同键的操作,移除之前的,保留最新的一条(革除冗余命令)

aof 重写过程

一个拷贝,两处日志

  1. 拷贝:主线程 fork 子过程,将主线程的内存拷贝一份(这时候只是拷贝数据结构和指针,真正开拓内存空间是在 主线程执行写命令的时候
  2. 两处日志:主线程执行写操作命令时,会同时写入 aof 日志的缓存区和新的 aof 重写日志的缓存区,缓存区的数据都会刷入到各自的磁盘文件中,如果 aof 重写日志同步完后,重命名而后替换原来的 aof 文件

留神上图的不是子线程,而是子过程!

应用 子过程 ,而不是 子线程 是为了缩小对资源的竞争

redis 利用 aof 还原数据的过程

  1. 建设无网络连接的伪客户端
  2. 读取 aof 文件一条命令
  3. 伪客户端执行命令
  4. 反复(2,3)直到全副执行结束

rdb 机制(快照)

RDB 是 Redis 用来进行长久化的一种形式,是把以后内存中的数据集快照写入磁盘,也就是 Snapshot 快照(数据库中所有键值对数据)。复原时是将快照文件间接读到内存里。RDB 文件是一个通过压缩的二进制文件,由多个局部组成。

触发形式

手动执行命令和主动执行命令

如何保留和载入

保留命令
SAVE

save 命令会阻塞 redis 服务器过程,这时 redis 会回绝其余命令,直到 save 命令完结

BGSAVE

bgsave 命令会 fork 一个子线程,用来执行保留 rdb 日志操作,父过程依然能够执行命令

自动性距离保留

redis save 策略配置

save 900 1:示意 900 秒(15 分钟)内至多有 1 个 key 的值发生变化,则执行
save 300 10:示意 300 秒(5 分钟)内至多有 1 个 key 的值发生变化,则执行
save 60 10000:示意 60 秒(1 分钟)内至多有 10000 个 key 的值发生变化,则执行
save "":该配置将会敞开 RDB 形式的长久化

redis 当中会有 saveparams 数组 保留下策略,redis 会有一个定时工作(默认 100ms)去查看保留条件是否满足,满足则执行 bgsave 命令

redis 记录 rdb 快照时,如何不阻塞主线程?

个别咱们拍照时,如果有人晃动了,那照片也得从新拍,所以拍照时必要保障被拍照的人静止,也就是内存中的数据不变。

redis 保留快照也是这样,先说保留快照的过程:

当进行快照记录时,主线程会 fork 出子过程,fork 会阻塞主线程,子过程和主线程此时共享一块内存空间,主线程能够持续接受命令,执行命令,子过程对内存中的数据进行日志记录,然而这就会有一个问题,子过程不能对正在批改的数据进行日志记录(如果数据始终变动,那岂不是每次记录还得校验下每块数据是否有变动,大大降低记录的效率,这感觉有点像 java 的 list 汇合,遍历时不容许对汇合中的数据做删除,增加操作)

你可能会想到,能够用 bgsave 防止阻塞 啊。这里我就要说到一个常见的误区了,防止阻塞和失常解决写操作并不是一回事。此时,主线程确实没有阻塞,能够失常接管申请,然而,为了保障快照完整性,它只能解决读操作,因为不能批改正在执行快照的数据。

redis 的作者利用了操作系统提供的 COW (copy on write)技术,当主线程对某一块数据进行操作(增删改)时,这时主线程会复制一份正本进去,子线程的数据地址批改为新的正本的地址,这样主线程和子过程就会不影响,既主线程能够接受命令,子过程进行日志记录啦。

载入 rdb 文件

redis 启动默认会主动载入 rdb 日志,载入时服务器会始终处于阻塞状态,直到载入实现

载入的优先级

因为个别 aof 的日志更加全面(更新频率通常比 rdb 高),所以 redis 会优先加载 aof 日志,如果开启 aof 优先应用 aof 日志还原数据库数据

aof 敞开时,会采纳 rdb 文件复原日志

bgsave 命令和 save bgsave bgrewriteaof 命令之间执行的关系
  • bgsave 和 save 不能同时执行,因为 save 会阻塞服务器过程
  • bgsave 和 bgsave 也不能同时进行,因为 bgsave 会 fork 出子过程,可能会有资源竞争状况
  • bgsave 和 bgrewriteaof,按情理不影响,然而出于性能思考,不倡议呈现两个过程大量写操作。

搭建

docker 形式搭建 redis(版本为 7.0.5)

当时在/etc/redis/ 放 redis.conf 文件 能够在 redis.conf 文件下载

启动遗记指定 redis.conf 文件 还得半天没有呈现 aof 日志 因为 aof 默认是敞开的

docker run -p 6379:6379 --name myredis -v /usr/local/docker/redis/redis.conf:/etc/redis/redis.conf -v /usr/local/docker/redis/data:/data -d registory.dongshanxia.top:35000/redis:latest redis-server /etc/redis/redis.conf --appendonly yes

查看 aof 文件内容

cat appendonly.aof.1.incr.aof

查看 rdb 文件内容 打印进去的是十六进制 能够应用 onlinehexeditor 转换

od -A x -t x1c -v dump.rdb

redis 开启混合长久化

redis 和 mysql 比照

mysql: 在事务提交时,数据写入缓存池,redo log 文件写入磁盘才算事务完结,mysql 服务宕机时,会利用 redo log 复原 已提交事务 然而未写入磁盘的数据。先写日志,再写磁盘

redis: aof 先执行命令,再写 aof 日志(益处就是 1. 防止谬误命令被记录,导致复原数据有问题,2. 不会阻塞命令执行操作)先写磁盘,再写日志

援用《redis 设计与实现》

                                  欢送关注 ggball blog 公众号

本文由 mdnice 多平台公布

退出移动版