Redis的持久化设计
Redis 持久化设计
持久化的功能:Redis是内存数据库,数据都是存储在内存中的,为了避免进程退出导致数据的永久丢失,要定期将Redis中的数据以某种形式从内存保存到硬盘,当下次Reids重启时,利用持久化文件实现数据恢复。
RDB:将当前数据保存到硬盘
AOF:将每次执行的写命令保存到硬盘(类似MySQL的binlog)
1. RDB持久化
RDB持久化是将当前进程中的数据生成快照保存到硬盘(因此也称作快照持久化),保存的文件后缀是rdb;当Redis重新启动时,可以读取快照文件恢复数据。
触发条件
- 手动触发 save 命令和bgsave命令都可以生成RDB文件, save命令会阻塞Redis服务进程,知道RDB文件创建完毕,bgsave命令则是创建一个子进程,由子进程来负责创建RDB文件,父进程继续处理请求,bgsave命令执行过程中,只有fork子进程时会阻塞服务器,而对于save命令,整个过程都会阻塞服务器,因此save已基本被废弃,线上环境要杜绝save的使用;后文中也将只介绍bgsave命令。此外,在自动触发RDB持久化时,Redis也会选择bgsave而不是save来进行持久化
SAVE 执行期间,AOF 写入可以在后台线程进行,BGREWRITEAOF 可以在子进程进行,所以这三种操作可以同时进行 ,为了避免性能问题,BGSAVE 和 BGREWRITEAOF 不能同时执行
自动触发
save m n
在配置文件中通过 save m n 命令,指定当前m秒内发生n次变化时,触发bgsave。
其中save 900 1的含义是:当时间到900秒时,如果redis数据发生了至少1次变化,则执行bgsave;save 300 10和save 60 10000同理。当三个save条件满足任意一个时,都会引起bgsave的调用.
Redis的save m n,是通过serverCron函数、dirty计数器、和lastsave时间戳来实现的-
- serverCron函数,是Redis服务器的周期性操作函数,默认每隔100ms执行一次,该函数对服务器的状态进行维护,其中一项工作就是检测save m n 配置是否满足条件,如果满足就执行bgsave.
- dirty计数器 记录服务器进行了多少起操作,修改,不是客户端执行了多少修改数据的命令
- lastsave时间戳也是Reids服务器维持的一个状态,记录上一次成功执行bgsave的时间
save m n的原理如下:每隔100ms,执行serverCron函数;在serverCron函数中,遍历save m n配置的保存条件,只要有一个条件满足,就进行bgsave。对于每一个save m n条件,只有下面两条同时满足时才算满足:
当前时间-lastsave > m
dirty >= n
在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行bgsave命令,并将rdb文件发送给从节点。
在执行shutdown命令时,自动执行rdb持久化
1.2 RDB文件
设置存储路径
- 配置文件:dir配置指定目录,dbfilename指定文件名。默认是Redis根目录下的dump.rdb文件
- 动态设置:
config set dir {newdir} /// config set dbfilename {newFileName}
RDB文件 是经过压缩的二进制文件,默认采用LZF算法对RDB文件进行压缩,虽然压缩耗时,但是可以大大减小文件体积,默认是开启的,可以通过命令关闭:
config set rdbcompression no
RDB文件的压缩并不是针对整个文件进行的,而是对数据库中的字符串进行的,且只有在字符串达到一定长度(20字节)时才会进行
格式:
字段说明:
REDIS常量,保存‘REDIS'5个字符
db_version RDB文件的版本号
SELECTDB 表示一个完整的数据库(0号数据库),同理
SELECTDB 3 pairs
表示完整的3号数据库;只有当数据库中有键值对时,RDB文件中才会有该数据库的信息(上图所示的Redis中只有0号和3号数据库有键值对);如果Redis中所有的数据库都没有键值对,则这一部分直接省略。其中:SELECTDB是一个常量,代表后面跟着的是数据库号码;0和3是数据库号码;KEY-VALUE-PAIRS: pairs则存储了具体的键值对信息,包括key、value值,及其数据类型、内部编码、过期时间、压缩信息等等
EOF 标志着数据库内容的结尾(不是文件的结尾),值为 rdb.h/EDIS_RDB_OPCODE_EOF (255)
CHECK-SUM RDB 文件所有内容的校验和,一个 uint_64t 类型值, REDIS 在写入 RDB 文件时将校验和保存在 RDB 文件的末尾,当读取时,根据它的值对内容进行校验
。如果这个域的值为 0 ,那么表示 Redis 关闭了校验和功能。
1.3 启动时加载
RDB文件的载入工作是在服务器启动时自动执行的,并没有专门的命令。但是由于AOF的优先级更高,因此当AOF开启时,Redis会优先载入AOF文件来恢复数据;只有当AOF关闭时,才会在Redis服务器启动时检测RDB文件,并自动载入。服务器载入RDB文件期间处于阻塞状态,直到载入完成为止
2. AOF持久化
AOF(Append Only File) 则以协议文本的方式,将所有对数据库进行过写入的命令(及其参数)记录到 AOF
文件,以此达到记录数据库状态的目的
2.1 开启AOF
Redis服务器默认开启RDB,关闭AOF;要开启AOF,需要在配置文件中配置:
appendonly yes
2.2 执行流程
2.2.1 命令写入缓冲区
//缓冲区的定义 是一个SDS, 可以兼容C语言的字符串
struct redisServer {
// AOF缓冲区, 在进入事件loop之前写入
sds aof_buf;
};
命令传播: Redis将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中
缓存追加: AOF程序根据接收到的命令命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中。
- 将命令以文本协议格式保存在缓存中
- 为什么使用文本协议格式?兼容性,避免二次开销,可读性
- 为什么写入缓存?这样不会受制于磁盘的IO性能,避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈
文件写入和保存:AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存
条件被满足的话,fsync 函数或者 fdatasync 函数会被调用,将写入的内容真正地保存到磁盘中。为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。
AOF保存模式:
- AOF_FSYNC_ALWAYS: 命令写入aof-buf后立即调用系统的fsync操作同步到AOF文件。因为 SAVE 是由 Redis 主进程执行的,所以在 SAVE 执行期间,主进程会被阻塞,不能接受命令请求。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命。
- AOF_FSYNC_NO: 命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
- AOF_FSYNC_EVERYSEC: 每一秒钟保存一次,命令写入aof_buf后调用系统write操作, write完成后线程返回, fsync同步文件操作由专门线程每秒调用一次
2.2.2. 文件重写
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入AOF重写机制压缩文件体积,AOF文件重写是把Redis进程内的数据转化为写命令同步到新AOF文件的过程。
重写后的AOF文件为什么可以变小?
- 进程内已经超时的数据不再写入文件
- 旧的AOF文件含有无效命令 ,如有些数据被重复设值(set mykey v1, set mykey v2)、有些数据被删除了(sadd myset v1, del myset)等等, 新的AOF文件只保留最终的数据写入命令
- 多条写入命令可以合并为一个,如:lpush list a、lpush list b可以转化为:lpush list a b。为了防止单条命令过大造成客户端缓冲区溢出,对于list、set、hash等类型操作,以64个元素为边界拆分为多条
AOF重写可以手动触发也可以自动触发:
- 手动触发: 直接调用bgrewriteaof命令
- 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机。
- auto-aof-rewrite-min-size:表示运行AOF重写时文件最小体积,默认为64MB
- auto-aof-rewrite-percentage:代表当前AOF文件空间(aof_current_size)和上一次重写后AOF文件空间(aof_base_size)的比值
流程说明:
1)执行AOF重写请求。
如果当前进程正在执行AOF重写,请求不执行。
如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再执行。
2)父进程执行fork创建子进程,开销等同于bgsave过程。
3.1)主进程fork操作完成后,继续响应其它命令。
所有修改命令依然写入AOF文件缓冲区并根据appendfsync策略同步到磁盘,保证原有AOF机制正确性。
3.2)由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据
由于父进程依然响应命令,Redis使用“AOF”重写缓冲区保存这部分新数据,防止新的AOF文件生成期间丢失这部分数据。
4)子进程依据内存快照,按照命令合并规则写入到新的AOF文件。
每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘数据过多造成硬盘阻塞。
5.1)新AOF文件写入完成后,子进程发送信号给父进程,父进程调用一个信号处理函数,并执行以前操作更新统计信息。
5.2)父进程把AOF重写缓冲区的数据写入到新的AOF文件。这时新 AOF 文件所保存的数据库状态将和服务器当前的数据库状态一致。
5.3)对新的AOF文件进行改名,原子地(atomic)覆盖现有的AOF文件,完成新旧文件的替换。
在整个 AOF 后台重写过程中,只有信号处理函数执行时会对服务器进程(父进程)造成阻塞,其他时候,AOF 后台重写都不会阻塞父进程,这将 AOF 重写对服务器性能造成的影响降到了最低
2.2.3 重启加载
流程说明:
1)AOF持久化开启且存在AOF文件时,优先加载AOF文件。
2)AOF关闭或者AOF文件不存在时,加载RDB文件。
3)加载AOF/RDB文件成功后,Redis启动成功。
4)AOF/RDB文件存在错误时,Redis启动失败并打印错误信息。
数据还原的详细步骤:
- 创建一个不带网络连接的伪客户端(fake client): 因为 Redis 的命令只能在客户端上下文中执行,而载入 AOF 文件时所使用的命令直接来源于 AOF 文件而不是网络连接,所以服务器使用了一个没有网络连接的伪客户端来执行 AOF 文件保存的写命令,伪客户端执行命令的效果和带网络连接的客户端执行命令的效果完全一样。
- 从AOF文件中分析并读取出一条写命令,使用伪客户端执行被读出的写命令,重复此操作,直到AOF文件中的所有写命令都被处理完毕为止。
2.2.4 文件校验
加载损坏的AOF文件会拒绝启动,并打印错误信息。
注意:对于错误格式的AOF文件,先进性备份,然后采用redis-check-aof --fix
命令进行修复,修复后使用diff -u对比数据差异,找到丢失的数据,有些可以进行人工补全。
AOF文件可能存在结尾不完整的情况,比如机器突然掉电导致AOF尾部文件命令写入不全。
Redis为我们提高了aof-load-truncated
配置来兼容这种情况,默认开启
3. 了解MySQL中的binlog
参考博文与书籍:
- 《redis设计与实现》
- Redis持久化
- 徐刘根-Redis实战和核心原理详解(8)使用快照RDB和AOF将Redis数据持久化到硬盘中
Redis的持久化设计的更多相关文章
- 深入剖析 redis AOF 持久化策略
本篇主要讲的是 AOF 持久化,了解 AOF 的数据组织方式和运作机制.redis 主要在 aof.c 中实现 AOF 的操作. 数据结构 rio redis AOF 持久化同样借助了 struct ...
- 深入理解Redis的持久化
RDB RDB是将当前数据生成快照保存到硬盘上. RDB的工作流程: 1. 执行bgsave命令,Redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF子进程,如果存在bgsave命令直接 ...
- Redis缓存的设计、性能、应用与数据集群同步
Redis缓存的设计.性能.应用与数据集群同步 http://youzhixueyuan.com/design-performance-and-application-of-redis-cache.h ...
- 【redis】-- redis的持久化(作为数据库)
目录 1.RDB rdb持久化的方式 rdb方式的优点: aof的优点 3.持久化的其他特性 日志重写 工作原理 rdb和aof混合使用 redis是一个基于内存的数据库,故在redis正在运行的数据 ...
- Redis(7)——持久化【一文了解】
一.持久化简介 Redis 的数据 全部存储 在 内存 中,如果 突然宕机,数据就会全部丢失,因此必须有一套机制来保证 Redis 的数据不会因为故障而丢失,这种机制就是 Redis 的 持久化机制, ...
- Redis 的持久化
原文链接:https://www.changxuan.top/?p=1386 Redis 是一个非关系型的内存数据库,使用内存存储数据是它能够进行快速存取数据的原因之一. 在实际应用中,常有人提倡把 ...
- Redis总结(四)Redis 的持久化
前面已经总结了Redis 的安装和使用今天讲下Redis 的持久化. redis跟memcached类似,都是内存数据库,不过redis支持数据持久化,也就是说redis可以将内存中的数据同步到磁盘来 ...
- Redis的持久化的两种方式drbd以及aof日志方式
redis的持久化配置: 主要包括两种方式:1.快照 2 日志 来看一下redis的rdb的配置选项和它的工作原理: save 900 1 // 表示的是900s内,有1条写入,则产生快照 save ...
- redis启用持久化
redis的持久化有rdb和aof两种. rdb是记录一段时间内的操作,一盘的配置是一段时间内操作超过多少次就持久化. aof可以实现每次操作都持久化. 这里我们使用aof. 配置方式,打开redis ...
随机推荐
- LightOJ1220
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1220 题目大意: 给你一个 x,请求出一个最大的 p 使得 np = x(n为 ...
- [开源] .Net orm FreeSql 1.5.0 最新版本(番号:好久不见)
废话开头 这篇文章是我有史以来编辑最长时间的,历时 4小时!!!原本我可以利用这 4小时编写一堆胶水代码,真心希望善良的您点个赞,谢谢了!! 很久很久没有写文章了,上一次还是在元旦发布 1.0 版本的 ...
- PHP 操作结果集对象方法
<?php header('Content-type:text/html;charset=utf-8'); //建立 或者 关闭mysql服务器 @符号用于屏蔽错误信息 $link=@mysql ...
- 将`VuePress`建立的博客部署到GitHub或Gitee上
将VuePress建立的博客部署到GitHub或Gitee上 在上一篇中,我们详细介绍了如何利用VuePress搭建起个人博客系统,但这只是在本地debug启动的,接下来,我们把它部署到Github网 ...
- CPU缓存学习及C6678缓存使用总结(知识归纳)
作者注: 1.本篇博客内容是本人在学习cpu缓存原理时进行的学习总结,参考了多处相关资源(书籍,视频,知乎回答等),参考出处标注在内容最后. 2.由于本篇内容的编辑工作在印象笔记完成,输出的PDF文件 ...
- [256个管理学理论]005.羊群效应(Herd Behavior)
羊群效应(Herd Behavior) 来自于大洋彼岸的让你看不懂的解释: “羊群效应”,也叫“从众效应”,是个人的观念或行为由于真实的或想像的群体的影响或压力,而向与多数人相一致的方向变化的现象.表 ...
- 离散的差分进化Discrete DE
一般的差分算法的变异规则:Xmutation=Xr1+F(Xr2-Xr3),F为缩放因子, 离散差分进化DDE的变异规则:设每个解为K个元素的集合,则Xr2-Xr3:求出Xr2与Xr3有m个共同元素, ...
- 单片机提高ADC精度总结
在常用传感器中,模数转换器是其中至关重要的环节,模数转换器的精度以及系统的成本直接影响到系统的实用性.因此.如何提高模数转换器的精度和降低系统的成本是衡量系统是否具有实际应用价值的标准. 图 1 ...
- 50个SQL语句(MySQL版) 问题十二
--------------------------表结构-------------------------- student(StuId,StuName,StuAge,StuSex) 学生表 tea ...
- FTP免费工具,FTP免费工具推荐!
IIS7服务器管理工具是FTP操作的客户端软件,能够作为批量操作FTP命令!同时,它还能够作为VNC的操作客户端进行VNC的相关操作!能够连接Windows和Linux的服务器和PC,并进行实时的检测 ...