【Redis】-- 持久化

文章目录

  • [1. Redis持久化机制](#1. Redis持久化机制)
    • [1.1 RDB(Redis DataBase) -- 定期备份](#1.1 RDB(Redis DataBase) -- 定期备份)
      • [1.1.1 手动触发(save/bgsave)](#1.1.1 手动触发(save/bgsave))
        • [1.1.1.1 save](#1.1.1.1 save)
        • [1.1.1.1 bgsave(background)](#1.1.1.1 bgsave(background))
      • [1.1.2 自动触发(bgsave)](#1.1.2 自动触发(bgsave))
      • [1.1.3 RDB的优缺点](#1.1.3 RDB的优缺点)
    • [1.2 AOF(Append Only File) -- 实时备份](#1.2 AOF(Append Only File) -- 实时备份)
      • [1.2.1 AOF工作流程](#1.2.1 AOF工作流程)
      • [1.2.2 重写机制(rewrite)](#1.2.2 重写机制(rewrite))
        • [1.2.2.1 手动触发](#1.2.2.1 手动触发)
        • [1.2.2.2 自动触发](#1.2.2.2 自动触发)
        • [1.2.2.3 AOF重写流程](#1.2.2.3 AOF重写流程)
    • [1.3 混合持久化](#1.3 混合持久化)

1. Redis持久化机制

先来回顾一下MySQL的事务的四大特性(ACID):

  1. 原子性: 一个事务中的所有操作要么全部成功,要么全部失败。
  2. 一致性: 数据库中的数据满足业务的预期要求。
  3. 持久性: 进程/主机重启之后,数据是否存在。(把数据存储在硬盘上 -----> 持久, 把数据存储在内存中 ---->不持久)。
  4. 隔离性:允许多个事务并发执行,但是各个事务之间不受任何影响。

Redis是一个内存数据库,是把数据存储在内存上的,但是为了数据持久化,还要想办法将数据存储在硬盘上。当我们要插入一条数据的时候,需要把数据同时写入内存和硬盘。当我们查询数据的时候,直接从内存中读取,这样就能保证Redis快的特性,还能保证数据的持久化。

硬盘中的数据只是在redis重启的时候,用来恢复内存数据的。

虽然说要在内存和硬盘上都写入数据,但是具体怎么写入可以保证整体的效率更高一些?

Redis有两种持久化的机制:RDB、AOF。

1.1 RDB(Redis DataBase) -- 定期备份

RDB持久化是把当前Redis中的数据生成一个快照保存到硬盘上的过程。

RDB持久化生成快照的触发机制有两种:手动触发、自动触发。

1.1.1 手动触发(save/bgsave)

通过redis客户端,执行特定的命令,来触发快照的生成。

1.1.1.1 save

使用save命令时,redis会阻塞其他客户端的命令,全力以赴的生成快照。

几乎不使用这种方式,阻塞服务是非常不可取的,如果数据量很大,生成快照备份的时间就会很长,这就意味着redis服务将长时间不可用,非常危险~~

1.1.1.1 bgsave(background)

执行bagsave命令时,并不会影响redis服务器处理其他客户端的请求和命令。

  1. 执行bgsave命令,Redis父进程判断是否有其他进行正在执行RDB/AOF子进程,如果有就直接返回。
  2. 如果没有,父进程会执行fork命令创建出来一个子进程。
  3. 父进程继续执行客户端的请求和命令。
  4. 子进程会创建RDB文件,根据父进程的内存生成临时快照文件,当这个快照生成完毕之后,再删除之前的rdb文件,把新生成的临时rdb文件名改成刚才的dump.rdb,完成对原有的RDB文件的替换,意思就是自始至终,rdb文件只有一个。
  5. 子进程执行完成之后,会发送信号给父进程。

查看生成的 .rdb文件:

bash 复制代码
root@iZ2ze4j894d3dddy89j3laZ:~# dir /var/lib/redis
dump.rdb

dump.rdb 文件时rdb机制生成的镜像文件,该文件是一个二进制的文件,它把内存中的数据以压缩(虽然压缩会消耗一定的CPU资源,但是能节省内存空间)的形式,保存在这个二进制文件中。

注意千万不要随意修改这个文件!!!

Redis服务器重启时,就会尝试加载这个rdb文件,如果发现这个文件的格式错误,就可能会加载数据失败。虽然不去主动的修改这个rdb文件,但是一些操作(网络传输)也可能会导致这个文件被破坏。

Redis提供了rdb文件的检查工具:

bash 复制代码
root@iZ2ze4j894d3dddy89j3laZ:~# redis-check-rdb /var/lib/redis/dump.rdb
[offset 0] Checking RDB file /var/lib/redis/dump.rdb
[offset 27] AUX FIELD redis-ver = '6.0.16'
[offset 41] AUX FIELD redis-bits = '64'
[offset 53] AUX FIELD ctime = '1757684664'
[offset 68] AUX FIELD used-mem = '871616'
[offset 84] AUX FIELD aof-preamble = '0'
[offset 93] Checksum OK
[offset 93] \o/ RDB looks OK! \o/
[info] 0 keys read
[info] 0 expires
[info] 0 already expired

1.1.2 自动触发(bgsave)

自动触发也是使用的bgsave的方式,其过程和手动触发使用bgsave的命令完全一样,都是使用创建子进程的方式。

自动触发就是在Redis的配置文件中进行设置,每个多长时间/产生多少次修改就触发RDB。

生成一次rdb快照,这是一个成本较高的操作,不能让这个操作执行的太频繁,所以在配置文件中进行配置时需要注意一下触发生成rdb快照文件的条件。

因为rdb文件不能生成的太频繁,所以快照中的数据和实时数据有一定的偏差。

在两次生成快照的中间,redis接收接收到了大量的key变化的请求,生成下一次快照之前,redis服务器挂了,那么中间这些key的变化就全丢了。

如果是通过正常流程service redis-server restart重新启动的Redis服务器,此时Redis服务器会在退出的时候,自动触发rdb操作。

如果是异常重启(kill -9、系统崩溃 或者 服务器掉电),此时Redis服务器来不及生成rdb文件,数据就会随着重启而丢失。

如果想要查看dump.rdb文件是否重新生成了,可以使用stat dump.rdb命令来查看文件的inode编号,inode编就相当于是文件的身份标识。

LInux文件系统主要是把整个文件系统分成了三个部分:

  1. 超级块:存储整个文件系统的信息,一些管理信息。
  2. inode表:所有文件的元数据(大小、权限、指针),
  3. Data Blocks(数据块):所有文件的实际内容。

1.1.3 RDB的优缺点

  1. RDB是一个压缩紧凑的二进制文件,非常适用于备份、全量复制等场景。
  2. Redis加载RDB要比AOF快的多。

原因:

  1. RDB是使用二进制的方式来组织数据的。直接把数据读取到内存中,按照字节的格式取出来放到结构体/对象中即可。
  2. AOF是使用文本的方式来组织数据的,需要进行一系列的字符串切分操作。
  1. RDB不能做到实时持久化。
  2. RDB使用特定二进制格式保存,Redis版本演进过程中有多个RDB版本,兼容性可能会有风险。

老版本Redis中的rdb文件,放到新版本的redis中不一定能识别。

1.2 AOF(Append Only File) -- 实时备份

AOF类似于MySQL中的binlog,会把用户的每个操作都记录到文件中。

当开启AOF时,rdb文件就不生效了。当Redis重启时会读取aof这个文件来用来恢复数据。

1.2.1 AOF工作流程

  1. 所有的写入命令都会哦追加到aof_buf中
  2. AOF缓冲区根据对应的策略向硬盘中(AOF文件)写入数据。
  3. AOF文件越来越大,进行重写操作。
  4. 重启时读取AOF文件中的数据。

AOF虽然既写内存又写硬盘,但是并没有影响到Redis处理请求的速度。主要有以下两个原因:

  1. AOF机制并不是直接让工作线程把数据写入硬盘,而是先写入一个内存的缓冲区,积累到一定的量时,再统一写入硬盘。

但是这样如果数据还在缓存中,并没有写入到硬盘上,如果进程突然挂了,那么缓冲区中的数据也就丢了。

先写入一个内存缓冲区中,就大大降低了写硬盘的次数。写硬盘的时候,写入硬盘的数据的多少,对性能没有很大的影响。但是写入硬盘的次数对性能影响很大。

  1. AOF每次写入都是写入原文件的末尾,属于顺序写入。

在硬盘上读写数据,顺序读写的速度虽然没有在内存中操作的快,但是还是比较快的。

1.2.2 重写机制(rewrite)

AOF文件会持续增长,体积会越来越大,会影响到下一次Redis启动的速度(因为Redis启动时要读取AOF文件的内容)。

AOF文件中记录着操作的过程,但是Redis重新启动读取时,并不关注这个过程,只关注结果。

Redis中就存在一个重写机制,会对AOF文件进行整理,提出其中的一些冗余操作,并且合并一些操作。

1.2.2.1 手动触发

调用bgrewriteaof命令。

1.2.2.2 自动触发

根据 auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage 参数确定自动触发时

机。

1.2.2.3 AOF重写流程
  1. 父进程执行bgrewriteaof操作。

如果当前进程正在执行 AOF 重写,请求不执行 。如果当前进程正在执行 bgsave 操作,重写命令延迟到 bgsave 完成之后再执行 。

  1. 父进程fork出一个子进程。
  2. 重写。

3.1 父进程不受影响继续处理客户端请求,处理的请求操作依旧写入AOF缓冲区。

3.2 在fork出子进程的一瞬间,子进程就继承了父进程的内存状态。所以子进程中的数据状态时父进程fork之间的数据状态,那fork之后父进程依旧在处理请求,这期间对内存的修改,子进程是不知道的。使用aof_rewrite_buf来专门存放fork之后的数据。

  1. 子进程把内存中当前的数据获取出来,以AOF的格式写入到一个新的AOF文件中。

子进程并不需要读取 硬盘上哪个庞大的旧的AOF文件,而是遍历当前内存数据库中的所有数据,为每个键值对生成一条最精简的命令,并将其写入一个新的临时的AOF文件。

  1. 子进程完成重写。

5.1 子进程把数据写完之后会发送一个信号通知父进程。

5.2 父进程把aof_rewrite_buf缓冲区中的内容也吸入到新的AOF文件中。

5.3 用新的AOF文件替换旧的AOF文件。


问:父进程坚持写即将消亡的旧的AOF文件有什么意义吗?

答:如果父进程不坚持写旧的AOF文件,可能重启就没办法保证数据的完整性了。假如子进程在重写的过程中,服务器突然挂了,新的AOF文件内容还并不完整,子进程的数据就会丢失。

1.3 混合持久化

RDB和AOF各有各的优点,Redis就引入了混合持久化的方式,结合了rdb和aof的特点。

混合持久化的核心是在AOF重写的过程中。

按照aof的方式,每一个请求/操作,都记录到文件中。在触发aof重写之后,会把当前内存的状态按照rdb的二进制的格式写入到新的aof文件的头部,后续再将缓冲区的增量AOF命令写入新的AOF文件的末尾,生成混合格式的RDB头和AOF尾的AOF文件,再用新的AOF文件替换旧的文件。

相关推荐
getdu2 小时前
Redis面试相关
数据库·redis·面试
TDengine (老段)2 小时前
TDengine 选择函数 TOP() 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
m0_694845572 小时前
教你使用服务器如何搭建数据库
linux·运维·服务器·数据库·云计算
okra-4 小时前
如何进行WEB安全性测试
数据库
belldeep4 小时前
Win10 上 Debian 12 如何安装 Redis ?
运维·redis·debian
孙同学_4 小时前
【C++】AVL树
c++·redis
island13145 小时前
【Redis#9】其他数据结构
数据结构·数据库·redis
winfield8215 小时前
Redis 线上问题排查完整手册
redis
言之。5 小时前
Django REST框架:ModelViewSet全面解析
数据库·python·django