CodeAshen's blog CodeAshen's blog
首页
  • Spring Framework

    • 《剖析Spring5核心原理》
    • 《Spring源码轻松学》
  • Spring Boot

    • Spring Boot 2.0深度实践
  • Spring Cloud

    • Spring Cloud
    • Spring Cloud Alibaba
  • RabbitMQ
  • RocketMQ
  • Kafka
  • MySQL8.0详解
  • Redis从入门到高可用
  • Elastic Stack
  • 操作系统
  • 计算机网络
  • 数据结构与算法
  • 云原生
  • Devops
  • 前端
  • 实用工具
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
  • Reference
GitHub (opens new window)

CodeAshen

后端界的小学生
首页
  • Spring Framework

    • 《剖析Spring5核心原理》
    • 《Spring源码轻松学》
  • Spring Boot

    • Spring Boot 2.0深度实践
  • Spring Cloud

    • Spring Cloud
    • Spring Cloud Alibaba
  • RabbitMQ
  • RocketMQ
  • Kafka
  • MySQL8.0详解
  • Redis从入门到高可用
  • Elastic Stack
  • 操作系统
  • 计算机网络
  • 数据结构与算法
  • 云原生
  • Devops
  • 前端
  • 实用工具
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
  • Reference
GitHub (opens new window)
  • MySQL8.0详解与实战

  • MySQL面试指南

  • Redis从入门到高可用

    • 第01章-初识Redis
    • 第02章-API理解和使用
    • 第03章-Redis客户端
    • 第04章-Redis其他功能
    • 第05章-Redis持久化
      • 2.1 RDB 介绍
      • 2.2 RDB 触发的三种方式
        • save(同步)
        • bgsave(异步)
        • 自动
      • 2.3 rdb 触发机制
      • 3.1 AOF 介绍
      • 3.2 AOF 的三种策略
      • 3.3 AOF 重写
        • AOF 重写介绍
        • aof 重写的优点
        • aof 重写实现的两种方式
      • 3.4 AOF相关配置
      • 5.1 fork 操作
      • 5.2 子进程开销和优化
      • 5.3 AOF 追加阻塞
    • 第06章-Redis主从复制
    • 第07章-Redis Sentinel
    • 第08章-Redis Cluster
    • 第09章-缓存设计与优化
    • 第10章-Cache Cloud
  • Elastic-Stack

  • 数据库
  • Redis从入门到高可用
CodeAshen
2023-02-10
目录

第05章-Redis持久化

# 一、持久化的作用

redis 所有数据保持在内存中,对数据的更新将异步地保存到磁盘上。

主流数据库的持久化方式:

持久化方式 说明 数据库
快照 数据库某时刻的完整备份 MySQL Dump
Redis RDB
写日志 将数据库的变化操作记录在日志中,可以重放日志中的操作恢复数据 MySQL Binlog
Hbase HLog
Redis AOF

Redis 持久化有 RDB 和 AOF 两种策略

# 二、RDB

# 2.1 RDB 介绍

image-20210603174625696

  • Redis 在某一时刻记录此时内存中完整数据的一个快照,保存在 RDB 文件中
  • 在启动重新载入 RDB 文件,就可以恢复数据到内存中
  • RDB 文件也是主从复制的一个媒介

# 2.2 RDB 触发的三种方式

# save(同步)

redis 客户端发送 save 命令,服务端就会执行 rdb 操作。

image-20210603180124647

save 命令是一个同步命令,会等带服务端操作完成返回,在此之前服务端不能响应客户端的其他命令。

image-20210603180525847

save 命令的文件策略:如果有老的 rdb 文件,save 命令会生成一个临时 rdb 文件(此时有两个 rdb 文件),然后覆盖掉老的 rdb 文件。

时间复杂度:O(n)

# bgsave(异步)

redis 客户端发送 bgsave 命令,服务端收到命令后直接返回 "Background saving started"。然后在 redis 服务端中,会 fork 出一个子进程,在子进程中执行 rdb 操作,操作完成后告知主进程成功。

bgsave 是异步的,所以执行 bgsave 操作时服务端可以正常响应客户端的其他命令。bgsave 的文件策略和时间复杂度同 save。

image-20210603180735447

save 和 bgsave 对比:

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

# 自动

不需要客户端操作,根据配置自动执行 rdb 操作。

image-20210603182632417

rdb相关配置

# 自动rdb配置
save 900 1      # 每 900 秒有 1 个 key 改变
save 300 10     # 每 300 秒有 10 个 key 改变
save 60 10000   # 每 60 秒有 10000 个 key 改变

dbfilename dump.rdb               # 指定 rbd 文件的名称
dir ./                            # 工作目录,rdb、aof、日志文件 存在此目录
stop-writes-on-bgsave-error yes   # 如果 bgsave 发生错误是否停止写入
rdbcompression yes                # rdb 文件是否采用压缩的格式
rdbchecksum yes                   # 是否对 rdb 文件进行校验和检验
1
2
3
4
5
6
7
8
9
10

rdb 配置最佳实践

#### 不开启自动保存 ####

# 由于 redis 单线程,通常一台机器上启动好几个 redis 实例,可以根据端口号区分 rdb 文件属于哪个实例
dbfilename dump-${port}.rdb

# 自定义工作目录
dir /bigdiskpath

stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
1
2
3
4
5
6
7
8
9
10
11

# 2.3 rdb 触发机制

  • 全量复制:主从复制的时候会生成 rdb 文件
  • debug reload:redis 提供 debug 级别的重启,会生成 rdb 文件
  • shutdown:执行 shutdown save 会生成 rdb 文件

# 三、AOF

# 3.1 AOF 介绍

RDB 持久化的问题:

  • 耗时耗性能:

    image-20210604145455351

  • 不可控,丢失数据:

    image-20210604145708231

为了解决上述问题RDB的问题,redis 还提供了 AOF 持久化方式。如下图所示,redis 写命令都会追加到 aof 文件中,重启 redis 后加载 aof 文件,恢复数据。

image-20210604150016150

# 3.2 AOF 的三种策略

  • always:每一条命令都刷到 aof 文件中
  • everysec(默认):每秒把缓冲区中的命令刷到 aof 文件中
  • no:由操作系统决定何时将缓冲区中命令刷到 aof 文件中

image-20210604151348099

image-20210604151506860

image-20210604151642397

三种策略对比:

命令 优点 缺点
always 不丢失数据 IO 开销较大,一般的 sata 盘只有几百 TPS
everysec 每秒一次 fsync 丢 1 秒数据 丢 1 秒数据
no 不用管 不可控

# 3.3 AOF 重写

# AOF 重写介绍

aof 文件记录 redis 的写入命令,随着写入命令越来越多,aof 文件将越来越大。为了解决这个问题,redis 提供了 aof 重写机制。

aof 重写会将写入命令中重复的、无效的、过时的等命令进行优化,使生成的 aof 文件很小。

image-20210604155011373

# aof 重写的优点

  • 减少硬盘占用量
  • 加速恢复速度

# aof 重写实现的两种方式

  1. bgrewriteaof 命令:类似于 bgsave ,fork 出子进程异步进行 aof 重写
  2. AOF 重写配置

bgrewriteaof 命令

image-20210604160539972

AOF 重写配置

配置名 含义
auto-aof-rewrite-min-size AOF 文件重写需要的尺寸(即当 AOF 文件超过多大时开始重写)
auto-aof-rewrite-percentage AOF 文件增长率(比如配置 100,这次 200M 重写了,下次就是 400M 重写)

redis 中还有两个统计数据

  • aof_current_size:AOF 当前尺寸(单位:字节)
  • aof_base_size:AOF 上次启动和重写的尺寸(单位:字节)

当同时满足以下条件时,自动触发 aof 重写

  • aof_current_size > auto-aof-rewrite-min-size
  • (aof_current_size - aof_base_size) / aof_base_size > auto-aof-rewrite-percentage

AOF 重写流程:

image-20210604162310804

  1. 无论是执行 bgrewriteaof 命令还是自动触发,AOF 重写最终本质都会执行 bgrewriteaof 操作
  2. 主进程会 fork 出一个子进程,来执行 aof 操作
  3. aof_buf 记录了现有的内存数据,将这些数据更新到旧的 aof 文件中(内存回溯)
  4. aof_rewrite_buf 记录了重写期间的写命令,会记录在一个新的aof文件中,最后合并到旧aof文件中

推荐参考:Redis 之 AOF 重写及其实现原理 (opens new window)

# 3.4 AOF相关配置

appendonly yes                           #是否开启aof
appendfilename "appendonly-${port}.aof"  #aof文件名
appendfsync everysec                     #aof刷盘策略
dir/bigdiskpath                          #工作目录
no-appendfsync-on-rewrite yes            #aof重写的时候不记录aof命令(是否可以容忍重写期间丢数据)
auto-aof-rewrite-percentage 100          #aof重写增长率
auto-aof-rewrite-min-size 64mb           #aof重写尺寸
aof-load-truncated yes                   #是否加载被截断的aof文件(例如刷入aof文件途中宕机了)
1
2
3
4
5
6
7
8

# 四、RDB 和 AOF 选择

RDB 和 AOF 对比

命令 RDB AOF
启动优先级 低 高
体积 小 大
恢复速度 快 慢
数据安全性 丢数据 根据策略决定
轻重 重 轻

RDB 最佳策略

  • “关”
  • 集中管理
  • 主从,从开?

AOF 最佳策略

  • “开”:缓存和存储
  • AOF重写集中管理
  • everysec

最佳策略

  • 小分片
  • 缓存或者存储
  • 监控(硬盘、内存、负载、网络)
  • 足够的内存

# 五、持久化开发运维问题

# 5.1 fork 操作

  • 同步操作:Fork 操作只是做内存页的拷贝,而不是做整个内存的拷贝,所以说,大部分情况下速度是非常快的,但是如果本身的 fork 操作比较慢,或者是卡在了某个地方,那么它就会阻塞 redis 的主线程。
  • 与内存量息息相关:内存越大,耗时越长(与机器类型有关)
  • info:latest fork usec:该参数用来查上一次持久化的执行时间,用来辅助对持久化文件内存相关信息进行监控

改善 fork:

  • 优先使用物理机或者高效支持 fork 操作的虚拟化技术
  • 控制 Redis 实例最大可用内存:maxmemory
  • 合理配置 Linux 内存分配策略:vm.overcommit_memory=1
  • 降低 fork 频率:例如放宽 AOF 重写自动触发时机,不必要的全量复制

# 5.2 子进程开销和优化

  1. CPU
    • 开销:RDB 和 AOF 文件生成,属于 CPU 密集型
    • 优化:不做 CPU 绑定,不和 CPU 密集型部署
  2. 内存
    • 开销:fork 内存开销,copy-on-write。
    • 优化:echo never > /sys/kernel/mm/transparent_hugepage/enabled
  3. 硬盘
    • 开销:AOF 和 RDB 文件写入,可以结合 iostat、iotop 分析
    • 优化:
      • 不要和高硬盘负载服务部署一起 : 存储服务、消息队列等
      • no-appendfsync-on-rewrite = yes
      • 根据写入量决定磁盘类型:例如 ssd
      • 单机多实例持久化文件目录可以考虑分盘

# 5.3 AOF 追加阻塞

image-20210604171702424

如果我们使用 AOF 进行持久化,那么一般会使用每秒刷盘的策略。主线程将数据加载到缓冲区,同时它还有一个 AOF 同步线程,去负责每秒同步刷盘操作。主线程还会负责一项工作,主线程会对比上次 AOF 同步的时间,如果上次同步时间在 2 秒之内,主线程就会返回;如果距离上次同步时间超过了 2 秒,主线程会阻塞,直到同步完成。实际上,这也是为了达到保证 AOF 同步安全的一种策略,所以为了达到这一目的,它会一直阻塞直到达到同步完成。

但是,这里会产生两个问题:

  1. 主线程是不能阻塞的,因为主线程要负责日常命令的处理,是非常宝贵的资源
  2. 每秒刷盘的策略可能不只会丢失 1 秒,而是可能会丢失 2 秒的数据

AOF 阻塞定位

定位 AOF 阻塞有两重方式,查看 redis 日志和执行 info Persistence 命令。

方式一:redis 日志

image-20210604172244123

在 redis 日志中,有这么一段,它会告诉你,你的异步 AOF 同步可能花了太长时间了,你的磁盘是不是有问题,而且这个过程有可能拖慢你的 redis。

方式二:命令

> info Persistence
1

image-20210604172353667

编辑 (opens new window)
上次更新: 2023/06/04, 12:34:19
第04章-Redis其他功能
第06章-Redis主从复制

← 第04章-Redis其他功能 第06章-Redis主从复制→

最近更新
01
第01章-RabbitMQ导学
02-10
02
第02章-入门RabbitMQ核心概念
02-10
03
第03章-RabbitMQ高级特性
02-10
更多文章>
Theme by Vdoing | Copyright © 2020-2023 CodeAshen | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式