天增的博客
首页
博客
  • 分布式解决方案
  • Java并发工具包
  • redis
  • LeetCode
  • 系统设计
  • JVM体系
Github (opens new window)
Rss (opens new window)
  • zh-CN
  • en-US
首页
博客
  • 分布式解决方案
  • Java并发工具包
  • redis
  • LeetCode
  • 系统设计
  • JVM体系
Github (opens new window)
Rss (opens new window)
  • zh-CN
  • en-US
  • redis
  • Redis为什么这么快
    • redis单线程的问题
  • Redis基本数据结构
    • String的底层实现
    • List的底层实现
    • Hash的底层实现
    • Set的底层实现
    • ZSet的底层实现
  • Redis分布式缓存
    • 缓存击穿
    • 缓存穿透
    • 缓存雪崩
    • 缓存预热
  • Redis的分布式锁
    • 看门狗模式
    • Redlock
  • Redis集群
    • Redis数据淘汰策略
    • redis持久化
      • 执行流程
      • 怎么防止AOF文件越来越大?
      • 执行流程
    • Redis数据删除策略
  • topic
  • redis
  • Redis集群
  • redis持久化
2022-04-28
目录

redis持久化

# redis持久化

因为Redis是一个内存数据库,所有的数据都保存在内存里面,一旦发生关机或者重启,内存中的数据都会丢失,所以为了重启的时候能够及时的恢复数据,redis提供了持久化机制。

在运行正常期间根据策略生成持久化文件,在机器重启后,能够根据持久化文件恢复内存中的数据。即使redis有主从同步的模式,主节点挂掉之后可以让从节点变成主节点,但是如果整个机房都发生停电,那么从节点和从节点内存中的数据都会丢失。

# 策略

持久化策略 大概原理 优缺点 配置方法
AOF 记录所有的操作命令,
并以文本的形式追加到文件中
文件大,恢复慢,性能影响大,但实时性高,丢失数据最少,持久化保存的数据更加完整 默认关闭
redis.conf中appendonly设置为true
RDB 当前进程数据生成快照保存到硬盘 文件小,恢复快,不影响性能,实时性低,兼容性差(老版本redis不兼容新版本的RDB文件) 默认开启,满足一定条件就会触发RDB文件的生成
也可以执行SAVE和BGSAVE手动触发
混合持久化
(Redis 4.0 之后新增)
在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,
再将后续的操作命令以 AOF 的格式存入文件
Redis 可以更快的启动,同时结合 AOF 的优点,又减低了大量数据丢失的风险。
AOF 文件中添加了 RDB 格式的内容,会使得 AOF 文件的可读性会很差,不容易阅读
默认关闭,通过redis.conf中的aof-use-rdb-preamble开启

# AOF持久化

img

# 执行流程

AOF的持久化主要是在Redis执行命令之后,将命令添加到aof_buf的末尾,然后在每次事件结束时根据appendfsync的配置,来决定是否将aof_buf缓冲区的内容写入和保存到AOF文件中。

基于性能考虑一般生产环境的配置都是everysec

appendfsync 参数有三个选项:

  1. always:每处理一个命令都将 aof_buf 缓冲区中的所有内容写入并同步到AOF 文件,即每个命令都刷盘。
  2. everysec:将 aof_buf 缓冲区中的所有内容写入到 AOF 文件,如果上次同步 AOF 文件的时间距离现在超过一秒钟, 那么再次对 AOF 文件进行同步, 并且这个同步操作是异步的,由一个后台线程专门负责执行,即每秒刷盘1次。
  3. no:将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 但并不对 AOF 文件进行同步, 何时同步由操作系统来决定。即不执行刷盘,让操作系统自己执行刷盘。

# 怎么防止AOF文件越来越大?

为了防止AOF文件越来越大,可以通过执行BGREWRITEAOF命令,会fork子进程出来,读取当前数据库的键值对信息,生成所需的写命令,写入新的AOF文件。在生成期间,父进程继续正常处理请求,执行修改命令后,不仅会将命令写入aof_buf缓冲区,还会写入重写aof_buf缓冲区。当新的AOF文件生成完毕后,子进程父进程发送信号,父进程将重写aof_buf缓冲区的修改命令写入新的AOF文件,写入完毕后,对新的AOF文件进行改名,原子地(atomic)地替换旧的AOF文件。

BGREWRITEAOF命令

BGREWRITEAOF命令用于异步执行一个 AOF 文件重写操作。重写会创建一个当前 AOF 文件的体积优化版本。

即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。

注意: 从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。

# AOF文件追加阻塞?

修改命令添加到aof_buf之后,如果配置是everysec那么会每秒执行fsync操作,调用write写入磁盘一次,但是如果硬盘负载过高,fsync操作可能会超过1s,Redis主线程持续高速向aof_buf写入命令,硬盘的负载可能会越来越大,IO资源消耗更快,所以Redis的处理逻辑是会对比上次fsync成功的时间,如果超过2s,则主线程阻塞直到fsync同步完成,所以最多可能丢失2s的数据,而不是1s。

# RDB持久化

RDB持久化指的是在满足一定的触发条件时(在一个的时间间隔内执行修改命令达到一定的数量,或者手动执行SAVE和BGSAVE命令),对这个时间点的数据库所有键值对信息生成一个压缩文件dump.rdb,然后将旧的删除,进行替换。

# 执行流程

实现原理是fork一个子进程,然后对键值对进行遍历,生成rdb文件,在生成过程中,父进程会继续处理客户端发送的请求,当父进程要对数据进行修改时,会对相关的内存页进行拷贝,修改的是拷贝后的数据。(也就是COPY ON WRITE,写时复制技术,就是当多个调用者同时请求同一个资源,如内存或磁盘上的数据存储,他们会共用同一个指向资源的指针,指向相同的资源,只有当一个调用者试图修改资源的内容时,系统才会真正复制一份专用副本给这个调用者,其他调用者还是使用最初的资源,在CopyOnWriteArrayList的实现中,也有用到,添加或者插入一个新元素时过程是,加锁,对原数组进行复制,然后添加新元素,然后替代旧数组,解锁)

img

    //CopyOnWriteArrayList的添加元素的方法
public boolean add(E e) {
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
    Object[] elements = getArray();
    int len = elements.length;
    Object[] newElements = Arrays.copyOf(elements, len + 1);
    newElements[len] = e;
    setArray(newElements);
    return true;
  } finally {
    lock.unlock();
  }
}

# 混合持久化(Redis4.0+)

# 执行流程

混合持久化同样也是通过bgrewriteaof命令完成的,不同的是当开启混合持久化时,fork出的子进程先将当前内存中的键值对信息全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。

简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据。

# Redis的数据恢复策略

优先级: 混合持久化 > AOF > RDB

  1. 如果配置了混合持久化,那么根据混合持久化文件进行恢复数据。(Redis4.0+)
  2. 只配置 AOF ,重启时加载 AOF 文件恢复数据。
  3. 同时配置了 RDB 和 AOF ,启动时只加载 AOF文件恢复数据,如果AOF文件损坏,那么根据RDB文件恢复数据。
  4. 只配置 RDB,启动时加载RDB持久化文件恢复数据

# Redis持久化策略该如何进行选择

(因为混合持久化是Redis 4.0之后支持的,目前一般生成环境使用的Redis版本可能都还较低,所以这里的策略选择主要是针对AOF持久和RDB持久化进行技术选型。)

以下是几种持久化方案选择的场景:

# 1.不需要考虑数据丢失的情况

那么不需要考虑持久化。

# 2.单机实例情况下

可以接受丢失十几分钟及更长时间的数据,可以选择RDB持久化,对性能影响小,如果只能接受秒级的数据丢失,只能选择AOF持久化。

# 3.在主从环境下

因为主服务器在执行修改命令后,会将命令发送给从服务器,从服务进行执行后,与主服务器保持数据同步,实现数据热备份,在master宕掉后继续提供服务。同时也可以进行读写分离,分担Redis的读请求。

# 那么在从服务器进行数据热备份的情况下,是否还需要持久化呢?

需要持久化,因为不进行持久化,主服务器,从服务器同时出现故障时,会导致数据丢失。(例如:机房全部机器断电)。如果系统中有自动拉起机制(即检测到服务停止后重启该服务)将master自动重启,由于没有持久化文件,那么master重启后数据是空的,slave同步数据也变成了空的。应尽量避免“自动拉起机制”和“不做持久化”同时出现。

所以一般可以采用以下方案:

主服务器不开启持久化,使得主服务器性能更好。

从服务器开启AOF持久化,关闭RDB持久化,并且定时对AOF文件进行备份,以及在凌晨执行bgaofrewrite命令来进行AOF文件重写,减小AOF文件大小。(当然如果对数据丢失容忍度高也可以开启RDB持久化,关闭AOF持久化)

# 4.异地灾备

一般性的故障(停电,关机)不会影响到磁盘,但是一些灾难性的故障(地震,洪水)会影响到磁盘,所以需要定时把单机上或从服务器上的AOF文件,RDB文件备份到其他地区的机房。

‍

最近更新
01
以 root 身份启动 transmission-daemon
12-13
02
Debian系统安装qbittorrent-nox
12-09
03
LXC Debain12安装zerotier并实现局域网自动nat转发
07-29
更多文章>
Theme by Vdoing | Copyright © 2015-2024 天增 | 苏ICP备16037388号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式