Redis | 第5章 Redis 中的持久化技术《Redis设计与实现》
前言
参考资料:《Redis设计与实现 第二版》;
第二部分为单机数据库的实现,主要由以下模块组成:数据库、持久化、事件、客户端与服务器;
本篇将介绍 Redis 中的持久化技术,主要有两种:RDB持久化和AOF持久化;
1. RDB 持久化
1.1 RDB 文件的创建与载入
- Redis使用 SAVE 和 BGSAVE 命令生成 RDB 文件;
- SAVE:会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止,阻塞期间服务器不能处理任何命令请求;
- BGSAVE:会派生一个子进程,由指进程负责创建 RDB 文件,父进程继续处理命令请求。BGSAVE 执行期间,会发生以下特殊情况:
- 在 BGSAVE 命令执行期间,客户端发送 SAVE 和 BGSAVE 命令会被服务器拒绝,防止产生竞争条件。客户端发送 BGREWRITEAOF 命令会被延迟;
- 在 BGREWRITEAOF 命令执行期间,客户端发送 BGSAVE 命令会被服务器拒绝;
- 创建 RDB 文件由
rdb.c/rdbSave
函数完成; - 载入 RDB 文件由
rdb.c/rdbLoad
函数完成; - RDB 文件的载入工作是在服务器启动时自动执行,只要 Redis 服务器在启动时检测到 RDB 文件存在,就会自动载入 RDB 文件;
- AOF 文件的更新频率通常比 RDB 文件更新频率高:
- 当服务器开启了 AOF 持久化功能时,会优先使用 AOF 文件还原数据库状态;
- 当服务器关闭了 AOF 持久化功能时,才会使用 RDB 文件来还原数据库状态;
- 服务器在载入 RDB 文件期间,会一直处于阻塞状态,直到载入工作完成为止;
1.2 自动间隔性保存
1.2.1 设置保存条件
服务器会根据
save
选项所设置的保存值,设置服务器状态redisServer
结构的saveparams
属性;redisServer
的结构定义:struct redisServer{
//...
//记录了保存条件的数组
struct saveparam *saveparams;
//
}
saveparams
属性是一个数组,每个saveparam
结构保存了一个save
设置的保存条件;saveparam
的结构定义:struct saveparam{
//秒数
time_t seconds;
//修改值
int changes;
}
1.2.2 dirty 计数器和 lastsave 属性
dirty
属性和lastsave
属性在redisServer
结构体里:struct redisServer{
//...
//修改计数器
long long dirty;
//上一次执行保存的时间
time_t lastsave;
};
dirty
计数器记录距离上一次成功执行 SAVE 命令或者 BGNAME 命令之后,服务器对数据库状态进行了多少次修改;lastsave
属性是一个 UNIX 时间戳,记录了服务器上一次成功执行 SAVE 命令或 BGSAVE 命令的时间;
1.2.3 检查保存条件是否满足
- Redis 的服务器周期性操作函数
serverCron
默认每隔 100ms 会执行一次,其中包括检查 save 选项所设置的保存条件是否满足(遍历并检查saveparams
数组中的所有保存条件),满足则执行 BGSAVE 命令;
1.3 RDB 文件
1.3.1 RDB 的文件结构
RDB 文件结构的逻辑图:
各个字段含义:
字段 长度 储存值 说明 REDIS 5字节 “REDIS” 在载入文件时,快速检查所载入的文件是否为 RDB 文件 db_version 4字节 字符串表示的整数 RDB 文件的版本号 databases 0个或任意多个数据库,以及数据库中的键值对数据 EOP 1字节 EOP 常量 表示 RDB 文件正文内容的结束 check_sum 8字节 无符号整数 前4个部分的校验和
1.3.2 database 的文件结构
- database 为 RDB 文件的结构组成部分;
databases
部分的逻辑结构:
各字段含义:
字段 长度 存储值 说明 SELECTDB 1字节 常量 表示接下来读入数据库号码 db_number 1、2或5字节 数字 表示数据库号码 key_value_pairs 长度不定 数据库所有的键值对数据
1.3.3 key_value_pairs 的文件结构
- key_value_pairs 为 databases 的结构组成部分;有两种类型,一种不带过期时间,一种带过期时间;
key_value_pairs
部分的逻辑结构:
各字段含义:
字段 长度 存储值 说明 EXPIRETIME_MS 1字节 数值 表示过期时间 ms 8字节 数值 以毫秒为单位的 UNIX 时间戳 TYPE 1字节 常量 代表一种对象类型或底层编码 key 长度不定 字符串对象 表示键对象 value 长度不定 各种对象 表示值对象
1.3.4 value 的编码
- value 为 key_value_pairs 的结构组成成分;
- value 值对象的结构和长度会根据 TYPE 类型的不同而不同;
- value可以是字符串对象、列表对象、集合对象、哈希表对象、有序集合对象、INTSET编码的集合和ZIPLIST编码的列表、哈希表或有序集合;
- value的格式与编码对应请见 《第3章 对象》1.1 对象的定义;
- 字符串对象的格式与示例:
- 字符串对象可分为:压缩字符串和无压缩字符串两种:
- 列表与集合对象的格式:
- 哈希表对象的格式:
- 有序集合对象的格式:
INTSET 编码集合的格式:
- 将整数集合转换成字符串即可;
ZIPLIST编码的列表、哈希表或有序集合的格式:
- 将压缩列表转换成一个字符串对象,然后再保存到 RDB 文件;
1.4 RDB 文件的示例
不包含任何键值对的 RDB 文件:
REDIS标识 db_version EOF标识 check_num REDIS 0006 377 334 263 c 360 z 334 362 v 包含字符串键的 RDB 文件:
REDIS标识 db_version SELECTDB db_number,0 号数据库 TYPE,\0 表示字符串 key value EOF标识 check_num REDIS 0006 376 \0 \0 003 MSG 005 HELLO 377 207 z = 304 f T L 343 包含带有过期时间的字符串键的 RDB 文件:
REDIS标识 db_version SELECTDB 切换数据库 EXPIRETIME_MS ms TYPE,\0 表示字符串 key value EOF标识 check_num REDIS 0006 376 \0 374 \ 2 365 336 @ 001 \0 \0 \0 003 MSG 005 HELLO 377 212 231 x 247 252 } 021 306 包含一个集合键的 RDB 文件:
REDIS标识 db_version SELECTDB 切换数据库 常量 REDIS_RDB_TYPE_SET key 集合大小 第一个元素 第二个元素 第三个元素 EOF常量 check_num REDIS 0006 376 \0 002 004 LANG 003 004 RUBY 004 JAVA 001 C 377 202 312 r 352 346 305 * 023
2 AOF 持久化与 RDB 持久化的区别
- AOF 持久化:保存 Redis 服务器所执行的命令来记录数据库状态;
- RDB 持久化:保存数据库中的键值对来记录数据库状态不同;
3. AOF 持久化
3.1 AOF 持久化的实现
AOF 持久化功能可分为:追加(append)、文件写入、文件同步(sync)三个步骤;
AOF 文件中的所有命令都以 Redis 命令请求协议的格式保存;
当 AOF 持久化功能打开时,服务器在执行完一个写命令之后,会以协议格式将被执行的写命令追加到服务器状态的
aof_buf
缓冲区的末尾:struct redisServer{
//...
//AOF 缓冲区
sds aof_buf;
};
AOF 文件的写入与同步依赖事件循环 loop,每次循环主要有三个工作:
- 处理文件事件:负责接收客户端的命令请求,以及向客户端发送命令回复;
- 处理时间事件:执行需要定时运行的函数;
- flushAppendOnlyFile():考虑是否将
aof_buf
中的内容追加到 AOF 文件中;
flushAppendOnlyFile() 函数的行为由服务器配置的
appendfsync
选项的值决定,该值有三种不同的行为:appendfsync 选项的值 flushAppendOnlyFile 函数的行为 效率与安全性 always 将 aof_buf 缓冲区中的所有内容写入并同步到 AOF 文件 效率最慢,安全性最高 everysec 将 aof_buf 缓冲区中的所有内容写入并同步到 AOF 文件,如果上次同步 AOF 文件的事件距离现在超过 1s ,则对再次 AOF 文件进行同步,并且这个同步由一个线程专门负责 效率高 no 将 aof_buf 缓冲区中的所有内容写入到 AOF 文件,但不对 AOF 文件进行同步,何时同步由操作系统决定 效率最高,安全性最低
3.2 AOF 文件的载入与数据还原
- 服务器创建一个不带网络连接的伪客户(fake client),伪客户端读入并执行 AOF 文件即可;
3.3 AOF 重写
- AOF 重写不需要对现有 AOF 文件进行任何读取、分析或写入操作,而是通过读取服务器当前数据库状态实现;
- AOF 重写功能的实现原理:从数据库读取键现在的值,然后用一条命令记录键值对,代替之前记录这个键值对的多条命令;
- 为了避免执行命令时造成客户端输入缓冲区溢出,重写程序在处理列表、哈希表、集合、有序集合这四种键时,会检查元素数量,超过一定数量(64)时会使用多条命令记录这个键的情况;
- 这个数量由常量
redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD
确定;
- 这个数量由常量
3.4 AOF 后台重写
- AOF 重写需要解决2个问题:
- 重写不能阻碍服务器处理客户端请求:使用子进程解决;
- 子进程在 AOF 重写期间,父进程服务器对数据库状态进行修改,会使服务器当前状态与重写后 AOF 状态不一致:设置AOF 重写缓冲区解决;
- Redis 将 AOF 重写程序放到子进程里执行:
- 子进程进行 AOF 重写期间,服务器进程(父进程)可以继续处理命令请求;
- 子进程带有服务器进程的数据副本,使用子进程而不是线程,避免使用锁的情况下保证数据安全;
Redis 服务器设置一个 AOF 重写缓冲区,以保证:
- AOF 缓冲区的内容会定期被写入和同步到 AOF 文件,对现有 AOF 文件的处理工作如常进行;
- 从创建子进程开始,服务器执行的所有写命令都会被记录到 AOF 重写缓冲区里;
子进程完成 AOF 重写工作后,向父进程发送一个信号,父进程接到信号后调用信号处理函数,执行以下工作:
- 将 AOF 重写缓冲区中的所有内容写入到新 AOF 文件,此时新 AOF 文件保存的数据库状态将与服务器当前的数据库状态一致;
- 对新的 AOF 文件进行改名,原子地覆盖现有的 AOF 文件,完成新旧两个 AOF 文件的替换;
只有号处理函数执行时会对服务器进程(父进程)造成阻塞;
最后
新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!
Redis | 第5章 Redis 中的持久化技术《Redis设计与实现》的更多相关文章
- Redis | 第8章 发布订阅与事务《Redis设计与实现》
目录 前言 1. 发布订阅 1.1 频道的订阅与退订 1.2 模式的订阅与退订 1.3 发送消息 1.4 查看订阅消息 2. 事务 2.1 事务的实现 2.2 WATCH 命令的实现 2.3 事务的 ...
- Redis | 第9章 Lua 脚本与排序《Redis设计与实现》
目录 前言 1. Lua 脚本 1.1 Redis 创建并修改 Lua 环境的步骤 1.2 Lua 环境协作组件 1.3 EVAL 命令的实现 1.4 EVALSHA 命令的实现 1.5 脚本管理命令 ...
- 07_NoSQL数据库之Redis数据库:Redis的高级应用之事务处理、持久化操作、pub_sub、虚拟内存
事务处理 Redis对事务的支持目前还比较简单.Redis只能保证一个client发起的事务中的命令可以连续的执行,而中间不会插入其他client的命令.当一个client在一个连接中发出mul ...
- springboot中使用cache和redis
知识点:springboot中使用cache和redis (1)springboot中,整合了cache,我们只需要,在入口类上加 @EnableCaching 即可开启缓存 例如:在service层 ...
- 分布式缓存技术redis学习系列(五)——redis实战(redis与spring整合,分布式锁实现)
本文是redis学习系列的第五篇,点击下面链接可回看系列文章 <redis简介以及linux上的安装> <详细讲解redis数据结构(内存模型)以及常用命令> <redi ...
- 分布式缓存技术redis系列(五)——redis实战(redis与spring整合,分布式锁实现)
本文是redis学习系列的第五篇,点击下面链接可回看系列文章 <redis简介以及linux上的安装> <详细讲解redis数据结构(内存模型)以及常用命令> <redi ...
- Python操作redis学习系列之(集合)set,redis set详解 (六)
# -*- coding: utf-8 -*- import redis r = redis.Redis(host=") 1. Sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合 ...
- 阿里云Centos7.6上面部署基于redis的分布式爬虫scrapy-redis将任务队列push进redis
Scrapy是一个比较好用的Python爬虫框架,你只需要编写几个组件就可以实现网页数据的爬取.但是当我们要爬取的页面非常多的时候,单个服务器的处理能力就不能满足我们的需求了(无论是处理速度还是网络请 ...
- Redis数据类型,持久化,回收策略——(Redis缓存第一章)
缓存:第一种是内存缓存 比如Map(简单的数据结构),以及EH Cache(Java第三方库),第二种是缓存组件比如Memached,Redis:Redis(remote dictionary ser ...
随机推荐
- Lynis 漏洞扫描工具部署及效果展示
Lynis 漏洞扫描工具部署及效果展示 介绍 Lynis是一个安全审计工具,它可以在Linux,macOS和其他基于Unix的系统上运行.Lynis的主要重点是执行系统的运行状况检查,它还有助于检测漏 ...
- Chrome 实时字幕
Chrome 实时字幕
- C#特性知识图谱-一、委托
一. 委托 1.1 委托定义 委托可以看成是一个方法的容器,将某一具体的方法装入后就可以把它当成方法一样调用.一个委托类型的变量可以引用任何一个满足其要求的方法.委托类似于C语言中的函数指针,但并不完 ...
- 兜底机制——leader到底做了什么?
Case 在之前一次年底考评的时候,有一位leader将一个案例同时用到了自己和下属身上,老板发出了责问: 这个项目到底你是负责人,还是你下面的同学是负责人,如果下面的同学是负责人,为什么要算到你的头 ...
- 【Java虚拟机9】类加载器之命名空间详解
前言 前面介绍类加载器的时候,介绍了一下命名空间这个概念.今天就通过一个例子,来详细了解一下[类加载器的命名空间].然后通过这个例子,我们可以总结一下双亲委托模型的好处与优点. 例1(不删除class ...
- Oracle 11g 常用sql记录
--表备份 create table xxx_bak as select * from xxx; --表数据清除 truncate table xxx --锁表问题处理sql开始 select ses ...
- Java 将Excel转为et和ett格式
以.et结尾的文件格式是属于金山办公软件WPS Office中的电子表格文件,.ett是一种模板文件格式.除了通过WPS软件可以创建该格式的电子表格外,也可以通过格式转换的方法来获得,如将Micros ...
- cf16E Fish(状压DP)
题意: N只FISH.每个回合会有一只FISH吃掉另一个FISH.直到池塘里只剩一只FISH. 给出aij:第i只FISH吃掉第J只FISH的概率. 问每一只FISH是最后存活者的概率. Input ...
- ARM 链接配置.lds文件学习<转>
本文由Jacky原创,来自http://blog.chinaunix.net/u1/58780/showart.php?id=462971 对于.lds文件,它定义了整个程序编译之后的连接过程,决定了 ...
- Java测试开发--sts安装Lombok(七)
1.sts安装Lombok的步骤: 下载最新的lombok.jar包,进入cmd窗口,切到Lombok下载的目录,运行命令: java -jar lombok.jar,会出现如下界面: 已经默认选好了 ...