Redis持久化机制
save m n:在m秒内,如果有n个键发生变化,则自动触发持久化,通过bgsave执行,如果设置多个,只要满足其一就会触发,配置文件有默认配置(可以注释掉)在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。以日志的形式记录服务器所处理的每一个写、删除邮件,查询操作不会记录,以文本的方式记录,可以
一、RDB(Redis DataBase)快照持久化
核心原理:RDB通过fork子进程实现,不会阻塞主进程处理客户端请求
// 伪代码实现流程
1. 主进程调用 fork() 创建子进程
2. 子进程复制父进程的页表(共享物理内存)
3. 子进程遍历所有数据库和键值对
4. 将数据序列化写入临时RDB文件
5. 原子性地 rename 临时文件替换旧文件
1.原理(在指定时间间隔内,将内存中的数据集快照写入磁盘)
在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。
写时复制(Copy-On-Write)机制:
a.fork后子进程共享内存页
b.主进程写数据时,OS会复制被修改的内存页
c.子进程会保留fork时刻的内存快照
补充:fork:当进程调用fork()时,操作系统会创建一个新的进程,这个新进程是原进程(父进程)的几乎完整的副本
创建新的进程控制块(PCB)-->复制内存描述符(关键策略:写时拷贝)-->复制文件描述符-->复制凄然进程属性(寄存器状态、信号处理器、工作目录等待)
复制内存描述符(关键策略:写时拷贝)
这是 fork() 性能的核心。传统上会复制整个地址空间(代码段、数据段、堆、栈),但现代操作系统不会立即复制物理内存。
复制页表:内核会为子进程创建一个新的页表,但页表项最初指向与父进程完全相同的物理内存页。
设置只读:内核将这些共享的物理内存页标记为只读。
写时拷贝:当父进程或子进程试图写入某个共享的内存页时,CPU会产生一个缺页异常。内核此时才真正复制该物理内存页,并将两个进程的页表项更新为指向各自独立的物理页,然后重新标记为可读写。只有被修改的页会被复制,从未修改的页(如代码段的大部分)则一直被共享。
2.触发方式
1.手动触发:
save命令:使Redis处于阻塞状态,知道RDB持久化完成,才会响应其他客户端发来的命令,所以在生产环境一定要慎用
bgsave命令:fork出一个子进程执行持久化,主进程只在fork过程中有短暂的阻塞,子进程创建之后,主进程就可以响应客户端请求了。
save:阻塞主进程(生产环境慎用)
bgsave:fork子进程执行(推荐)
2.自动触发:
save m n:在m秒内,如果有n个键发生变化,则自动触发持久化,通过bgsave执行,如果设置多个,只要满足其一就会触发,配置文件有默认配置(可以注释掉)
flushall:用于清空redis所有的数据库,flushdb清空当前redis所在数据(默认是0号数据库),会清空RDB文件,同时也会生成dump.rdb、内容为空。
3.优点
1.整个Redis数据库将只包含一个文件dump.rdb,方便持久化
2.容灾性好,方便备份
3.性能最大化,fork子进程来完成操作,让主进程继续处理命令,所以是IO最大化。使用单独子进程来进行持久化,主进程不会进行任何IO操作,保证了redis的高性能。
4.相对数据集大是,比AOF的启动效率更高。
5.单文件,数据恢复速度快。文件小,经过压缩的二进制文件。
4.缺点
1.数据库安全性低。RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
2.由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟。会占用CPU。
5.编码格式
每种数据类型都有特定的编码格式:
String: 直接存储(LZF压缩)
List: 连续存储所有元素
Hash: 键值对交替存储
Set: 连续存储所有成员
Sorted Set: 成员+分数交替存储
二、AOF(Append Only File)日志持久化
1.原理
以日志的形式记录服务器所处理的每一个写、删除邮件,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录,调操作系统命令进程刷盘。
1.所有的写命令会追加到AOF缓冲中
2.AOF缓冲区根据对应的策略向硬盘进行同步操作
3.随着AOF文件越来越大,需要定期对AOF文件进行重写,达到压缩的目的
4.当Redis重启时,可以加载AOF文件进行数据恢复
2.同步策略
每秒同步:异步完成,效率非常高,一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。
每修改同步:同步持久化,每次发生的数据变化都会被立即记录到磁盘中,最多丢一条
不同步:由操作系统控制,可能丢失较多数据
| 策略 | 写吞吐量 | 数据丢失风险 | fsync调用次数 |
| always | 5k ops/s | 0条 | 每命令 |
| everysec | 80K ops/s | <=1秒数据 | 1次/秒 |
| no | 100k ops/s | 最近30秒 | OS决定 |
3.优点
1.数据安全
2.通过append模式写文件,即使中途服务器宕机也不会破坏已经存在的内容,可以通过redis-check-aod工具,解决数据一致化问题。
3.AOF机制的rewrite模式,定期对AOF文件进行重写,以达到压缩的目的
重写原理
不是读取就AOF文件,而是读取内存当前数据生成新文件
4.缺点
1.AOF文件比RDB文件大,且恢复速度慢
2.数据集大的时候,比RDB启动效率低
3.运行效率没有RDB高
Questions:
1.fork()后子进程能继承父进程的哪些内存?
代码段、数据段、堆、栈、共享内存(如mmap)、以及通过 clone 标记的其他区域,但通过写时拷贝实现物理共享
2.fork很慢吗?
由于写时拷贝,fork() 本身非常快(只复制页表和创建少量内核结构)。只有后续真正写入内存时才会产生复制开销。这也是为什么 fork() 通常配合 exec() 使用(exec 会重新加载程序,之前复制的页表被丢弃,所以浪费极小)。
3.fork()后父子进程共享同一个打开文件的问题?
会共享文件偏移量,这可能导致意外。通常建议在 fork() 前后关闭不需要的文件描述符,或者使用 O_CLOEXEC
4.有没有只复制文件描述符但不复制内存的版本?
Linux的 vfork() 就是这样一个优化版本,它设计用于 fork() 后立即 exec() 的场景,会阻塞父进程直到子进程调用 exec 或 exit,但现代 fork() 的写时拷贝已经使得 vfork 基本过时。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)