redis的数据持久化策略
redis提供了两种不同的持久化方法来将数据存储到硬盘里面。一种方法叫快照,它可以将存在于某一时刻的所有数据都写入硬盘里面。另一种方法叫只追加文件(AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面。这两种持久化方法既可以同时使用,又可以单独使用,在某些情况下甚至可以两种方法都不用,具体选择哪种持久化方法,需要根据用户的数据及应用来决定。
快照持久化
redis可以通过创建快照来获得在内存里面的数据在某个时间点上的副本。在创建快照之后,用户可以对快照进行备份,可以将快照复制到其他的服务器从而创建具有相同数据的服务器副本,还可以将快照留在原地以便重启服务器使用。
触发RDB持久化可以分为:手动触发和自动触发两种模式!
触发机制:
手动触发分别对应save命令和bgsave命令
- save命令:阻塞当前redis服务器,知道RDB过程完成为止,对于内存比较大的实例会造成长时间阻塞,显示环境不建议使用。
- bgsave命令: redis进程执行fork操作创建子进程,rdb持久化由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。很明显bgsave命令是针对阻塞问题做的优化。因此redis内部所有涉及RDB的操作都采用bgsave的方式,而save命令已经废弃。
除手动触发外,redis可以使用save命令配置redis内部的自动触发机制,如下:
快照的配置如下:
save
stop-srites-on-bgsave-error no
rdbcompression on
dbfilename dump.rdb
创建快照的几种方法:【虽然是save命令,但是触发的是bgsave操作】
- 客户端可以通过向redis发送bgsave命令来创建一个快照。对于支持bgsave命令的平台来说(除windows外),redis会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,二父进程继续处理命令请求。
- 客户端还可以通过redis发送save命令来创建一个快照,接到save命令的redis服务器在快照创建完毕之前将不再响应其他任何命令。save命令并不常用,我们通常只会在没有足够内存去执行bgsave命令的情况下,又或者即使等到持久化操作执行完毕也无所谓的情况下,才会使用这个命令。
- 如果用户设置了save配置选项,譬如save 60 10000, 那么从redis最近一次创建快照操作之后开始算起。当“60s内有10000次写入”这个条件被满足时,redis就会自动触发bgsave命令。如果用户设置了多个save配置选项,那么当任意一个save配置选项所设置的条件被满足时,redis就会触发一次bgsave命令。
- 当redis通过shutdown命令接收到关闭服务器的请求时,或者接受到标准term信号时,会执行一个save命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在save命令执行完毕之后关闭服务器。
- 当一个redis服务器连接另一个redis服务器,并向对方发送sync命令来开始一次复制操作的时候,如果主服务器目前没有在执行bgsave操作,或者主服务器并非刚刚执行完bgsave操作,那么主服务器就会执行bgsave命令。
- 执行debug reload命令重新加载redis时,也会自动触发save操作。
在只使用快照持久化来保存数据时,一定要记住:如果系统真发生崩溃,用户将丢失最近一次生成快照之后的更改的所有数据。因此,快照持久化只适用于那些即使丢失一部分数据也不会造成问题的应用程序。
bgsave执行流程:
bgsave是主流的触发rdb持久化方式,执行流程如下:
- 执行bgsave命令,redis父进程判断当前是否存在正在执行的子进程,如RDB/AOF进程,如果存在bgsave命令直接返回。
- 父进程执行fork操作创建子进程,fork操作过程中父进程会阻塞,通过info stats命令查看latest_fork_usec选项,可以获取最近一个fork操作耗时,单位为微妙。
- 父进程fork完成后,bgsave命令返回“Background saving started”信息并不再阻塞父进程,可以继续响应其他命令。
- 子进程创建RDB文件,根据父进程内存生成临时快照文件,完成后对原文件进行原子替换。执行lastsave命令可以获取最后一次生成RDB的时间,对应info统计的rdb_last_save_time选项。
- 进程发送信号给父进程表示完成,父进程更新统计信息。
运维提示:
1:rdb文件的位置可以在线动态修改,可以使用config set dir指定rdb文件的位置,使用config set dbfilename执行文件名。
2:redis默认采用LZF算法对生成的rdb文件做压缩处理,压缩后的文件远远小于内存大小,默认开启,可以使用config set rdbcompression动态修改。虽然压缩rdb会消耗cpu,但可大幅度降低文件体积,方便保存到硬盘或通过网络发送给从节点,因此线上建议开启。
RDB的优缺点:
RDB是一个紧凑压缩的二进制文件,代表redis在某个时间点上的数据快照。非常适用于备份,全量恢复等场景。redis加载rdb恢复数据远远快于AOF方式。
RDB的缺点:
RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作常见子进程,属于重量级操作,频繁执行成本过高。RDB文件使用特定的二进制格式保存,redis版本演进过程中有多个格式的RDB版本,存在老版本redis服务无法兼容新版本rdb格式的问题。
AOF持久化
简单来说,AOF持久化会将被执行的写命令写到AOF文件的末尾,以此来记录数据发生的变化。因此,redis只要从头到尾重新执行一次AOF文件包含的所有写命令,就可以恢复AOF文件所记录的数据集。AOF持久化可以通过设置如下选项来打开。AOF的主要作用是解决了数据持久化的实时性,目前已经是redis持久化的主流方式。
appendonly no #是否开启aof持久化
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage
auto-aof-rewrite-min-size 64mb dir ./ #这个参数决定来持久化文件保存的位置
appendfsync参数有三个选项:
always: 每个redis写命令都要同步写入硬盘,这样会严重降低redis的速度。
everysec: 每秒执行一次同步,显式地将多个写命令同步到硬盘。
no : 让操作系统来决定应该何时进行同步。
aof处理流程如下:
- 所有的写入命令追加到aof_buf(缓冲区)中。
- aof缓冲区根据对应的策略向硬盘做同步操作。
- 随着aof文件越来越大,需要定期对aof文件进行重写,达到压缩的目的。
- 当redis服务器重启时,可以加载aof文件进行数据恢复。
*1:aof命令写入的内容直接是文本协议格式;文本协议有很好的兼容性;开启aof后,所有写入命令都包含追加操作,直接采用协议格式,避免了二次处理开销。文本协议具有可读性,方便直接修改和处理。
*2:aof为什么吧命令追加到aof_buf中?redis使用单线程相应命令,如果每次写aof文件命令都直接追加到硬盘,那么性能完全取决于当前硬盘负载。先写入aof_buf中,还有另一个好处,redis可以提供多种缓冲区同步硬盘的策略,在性能和安全性方面做出平衡。
aof_buf同步到磁盘的策略,可以使用appendfsync参数来控制!
- 如果使用always选项的话,那么每个redis写命令都会被写入硬盘。从而将发生系统崩溃时出现的数据丢失减少到最少。不过遗憾的是,因为这种同步策略需要对硬盘进行大量写入,所以redis处理命令的速度会受到硬盘性能的影响;机械硬盘在这种同步频率下每秒只能处理大约200个写命令,而固态硬盘每秒大概也只能处理几万个写命令。(使用固态硬盘慎用always选项,因为不断写入少量数据做法可能会引发严重的写入放大问题)。【命令写入aof_buf后调用系统fsync操作同步到aof文件,fsync完成后线程返回】
- 为来兼顾数据安全和写入性能,可以考虑用everysec选项,让redis以每秒一次的频率对aof文件进行同步。redis每秒同步一次aof文件时的性能和不适用任何持久化特性时的性能相差无几,而通过每秒同步一次aof文件,redis可以保证,即使出现系统崩溃,用户也最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,redis还会优雅地放慢自己的速度以便使用硬盘的最大写入速度。【命令写入aof_buf后调用系统write操作,write操作完成后线程返回。fsync同步文件由专门线程每秒调用一次】【建议使用】
- 如果使用来no选项,那么redis将不对aof文件执行任何显式的同步操作,而是由操作系统来决定应该在何时对aof文件进行同步。这个选项在一般情况下不会对redis的性能带来影响,但系统崩溃将导致使用这种选项的redis服务器丢失不定数量的数据。另外,如果用户的硬盘处理写入操作的速度不够快,那么当缓冲区被等待写入硬盘的数据被填满时,redis的写入操作将会被阻塞,并导致redis处理命令请求的速度变慢。【命令写入aof_buf后调用系统write操作,不对aof文件做fsync同步,同步硬盘操作由操作系统负责,通常同步周期最长为30s】
*3:重新机制
随着命令不断写入AOF,文件会越来越大,为了解决这个问题,redis引入了aof重写机制压缩文件体积。aof文件重写使redis进程内的数据转化为写命令同步到新aof文件的过程。
重写后aof文件为什么可以表小?
- 进程内已经超时的数据不再写入文件。
- 旧aof文件包含无效命令,如del key1, del key2, srem keys, set all 等。重写使用进程内数据直接生成,这样的新的aof文件只保留最终数据的写入命令。
- 多条写命令可以合并为一个,如:lpush list a,lpush list b可以转换为lpush a b。为了防止单条命令过大造成客户端缓冲区溢出,对于list,set,hash,zset等类操作,以64个元素为界拆分为多条。
aof重写降低了文件占用空间,除此之外,另一个目的:更小的aof文件可以更快第被redis加载。
aof重写过程可以手动触发或自动触发:
- 手动触发:直接调用bgrewriteaof命令
- 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数确定自动触发时机。
aof持久化可以通过设置auto-aof-rewrite-percentage选项和auto-aof-rewrite-min-size选项来自动执行bgrewriteaof。默认的配置如下:
auto-aof-rewrite-percentage
auto-aof-rewrite-min-size 64mb #那么当aof文件的体积大于64MB,并且aof文件的体积比上一次重写之后的体积大至少一倍(100%)的时候,redis将执行bgrewriteaof命令。如果aof重写执行得过于频繁的话,用户可以考虑将auto-aof-rewrite-percentage选项的值设置为100以上,
#这种做法可以让redis在aof文件的体积变得更大之后才执行重写操作,不过也会让redis在启动时还原数据集所需的时间变得更长。 自动触发机制:aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size减去aof_base_zise)/aof_base_size>=auto-aof-rewrite-percentag
其中:aof_current_size和aof_base_size可以在info命令统计信息中查看
AOF重写流程
1:执行aof重写请求,如果当前进程正在执行aof重写,请求不执行并且返回如下响应:
ERR Background append only file rewriting already in progress
如果当前进程正在执行bgsave操作,重写命令延迟到bgsave完成之后再执行,返回如下响应:
Background append only file rewriting scheduled
2:父进程执行fork创建子进程,开销等同于bgsave过程。
3.1: 主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入aof缓冲区并根据appendfsync策略同步到硬盘,保证原有aof机制正确。
3.2:由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,redis使用‘AOF重写缓冲’保存这部分数据,防止新AOF文件生成期间丢失这部分数据。
4:子进程根据内存快照,按照命令合并规则写入到新的AOF文件。每次批量写入硬盘数据量由配置aof-rewrite-incremental-fsync控制,默认为32MB,防止单次刷盘过多造成硬盘阻塞。
5:新aof文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。父进程把aof重写缓冲区的数据写入到新的aof文件,使用新aof文件替换老文件,完成aof重写。
redis重启加载流程:
1:aof持久化开启并存在aof文件时,优先加载aof文件。
2:aof关闭或者aof文件不存在时,加载rdb文件。
3:加载aof/rdb文件成功后,redis启动成功。
4:aof/redis文件存在错误时,redis启动失败并打印错误信息。
验证快照文件和aof文件
无论是快照持久化还是aof持久化,都提供了在遇到系统故障时进行数据恢复的工具。redis提供来两个命令行程序redis-check-aof和redis-check-dump,它们可以在系统故障发生之后,检查aof文件和快照文件的状态,并在有需要的情况下对文件进行修复。
[root@test2 redis]# redis-check-aof
Usage: redis-check-aof [--fix] <file.aof>
[root@test2 redis]# redis-check-rdb
Usage: redis-check-rdb <rdb-file-name>
[root@test2 redis]#
如果用户在运行redis-check-aof程序时给定了--fix参数,那么程序将对aof文件进行修复。程序修复aof文件的方法非常简单:它会扫描给定的aof文件,寻找不正确或者不完整的命令,当发现第一个出错命令的时候,程序会删除出错的命令以及位于出错命令之后的所有命令,只保留那些位于出错命令之前的正确命令。在大多数情况下,被删除的都是aof文件末尾的不完整的写命令。
redis的数据持久化策略的更多相关文章
- Redis 中的数据持久化策略(RDB)
Redis 是一个内存数据库,所有的数据都直接保存在内存中,那么,一旦 Redis 进程异常退出,或服务器本身异常宕机,我们存储在 Redis 中的数据就凭空消失,再也找不到了. Redis 作为一个 ...
- Redis 中的数据持久化策略(AOF)
上一篇文章,我们讲的是 Redis 的一种基于内存快照的持久化存储策略 RDB,本质上他就是让 redis fork 出一个子进程遍历我们所有数据库中的字典,进行磁盘文件的写入. 但其实这种方式是有缺 ...
- Redis之数据持久化RDB与AOF
Redis之数据持久化RDB与AOF https://www.cnblogs.com/zackku/p/10087701.html 大家都知道,Redis之所以性能好,读写快,是因为Redis是一个内 ...
- 进阶的Redis之数据持久化RDB与AOF
大家都知道,Redis之所以性能好,读写快,是因为Redis是一个内存数据库,它的操作都几乎基于内存.但是内存型数据库有一个很大的弊端,就是当数据库进程崩溃或系统重启的时候,如果内存数据不保存的话,里 ...
- redis配置数据持久化---APPEND ONLY MODE
Redis配置数据持久化---APPEND ONLY MODE 2016年04月01日 19:05:11 阅读数:9918 Redis可以实现数据的持久化存储,即将数据保存到磁盘上. Redis的持久 ...
- redis学习——数据持久化
一.概述 Redis的强大性能很大程度上都是因为所有数据都是存储在内存中的,然而当Redis重启后,所有存储在内存中的数据将会丢失,在很多情况下是无法容忍这样的事情的.所以,我们需要将内存中的数据持久 ...
- Redis两种持久化策略分析
Redis专题地址:https://www.cnblogs.com/hello-shf/category/1615909.html SpringBoot读源码系列:https://www.cnblog ...
- redis两种持久化策略/存储模式
redis的持久化策略 RDB,即 Redis DataBase,以快照形式将数据写入一个临时文件,持久化结束后,用这个临时文件替换上次持久化的dump文件,达到数据恢复. 默认开启,见redis ...
- redis的数据持久化方案
Redis的持久化方案有两种 1.Rdb方式:快照形式,定期将内存中的数据持久化到硬盘.是Redis默认的数据持久化的形式. Rdb:缺点是:数据还没有更新到磁盘上,突然断电,造成数据的不完整性. 在 ...
随机推荐
- 用JS编写个人所得税计算器
编写 “个人所得税计算器”函数 计算个税的方法: 3500 以下免征 3500 ~ 5000 部分 缴纳 3% 5000 ~ 9000 部分 缴纳 10% 9000 以上部分 缴纳 20% 代码如下: ...
- 屏蔽登录QQ后总是弹出的QQ网吧页面
不知道从什么时候开始的,每次登录QQ的时候,有个叫qq网吧的页面都会弹出来,腾讯你是撒吗?这个公司真是死性不改.按照它的提示,已经设置了好几次这是我家,这特么不是网吧,然并卵.你说它技术不行吧,它堪称 ...
- 新装的centos怎样显示中文界面
默认的显示英文界面,即使各种配置中都选择的chinese也没用,默认显示的还是英文. 要在终端输入 vim ~/.bashrc 编辑本用户配置文件 打开后最后一行加入 export LANG=&quo ...
- Go并发示例-Pool
https://mp.weixin.qq.com/s/MBY6l5VxrFPJ4AA8nGeQUQ <Go语言实战>笔记(十六) | Go并发示例-Pool 飞雪无情 异步图书 2017- ...
- Lambda Expression
Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁.当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口.下面这个例子就是使用Lambda语法来代替匿名的内部类 ...
- oracle学习笔记第一天
oracle学习笔记第一天 --oracle学习的第一天 --一.几个基础的关键字 1.select select (挑选) 挑选出显示的--列--(可以多列,用“,”隔开,*表示所有列),为一条 ...
- Linux基础命令2
1.修改网络状态: 1).Cd /etc/sysconfig/network-scripts/network-scripts 2).vi ifcfg-eth0 编辑 onboot=yes: 3 ...
- eclemma怎么安装 eclemma的安装与简单使用图文教程(附下载)
来自于:https://www.jb51.net/softjc/628026.html 一. 安装 有两种安装方法 1. 下载安装(推荐) 地址: http://sourceforge.net/pro ...
- 136A
#include <stdio.h> #include <string.h> #define MAXSIZE 110 int main() { int giv[MAXSIZE] ...
- NABCD分析---校园服务
N(需求): 大学生活中,很多琐碎的小事浪费同学时间精力.我们的APP本着为同学服务的宗旨,解决生活中各方面的问题,同学们可以在APP上发布各种信息,例如兼职,二手买卖等等. A(做法): 用户打开A ...