目录
1. 前言
Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,
需要将数据从内存中同步到硬盘中,这一过程就是持久化。
Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。
- RDB:产生一个数据快照文件
- AOF:实时追加命令的日志文件
我们对RDB和AOF的总结如下表。
- 启动优先级:假设Redis 同时打开了RDB和AOF持久化功能,当Redis重启的时候会优先加载AOF,因为AOF数据更新的频率更高,会保存更新的数据。
- 体积大小/恢复速度:RDB是使用二进制压缩的模式保存,因此体积会比较小,在Redis恢复的时候加载的速度也会更快。相反AOF写入的是日志的形式,因此体积会较大,恢复速度也会慢些。
- 数据安全性:RDB是以快照的模式保存数据,对数据的保存不是实时性的,会有丢失数据的可能性。而在这方面AOF的日志方式数据丢失的几率会比RDB低很多(例如:everysec)。
- 资源消耗:RDB显示需要消耗的资源会更大,因为每次将全量的数据保存到磁盘中。而AOF每次可以保存增量的Redis数据。
RDB | AOF | |
持久化方式 | 生成某一时刻的数据快照文件 | 实时记录每一个写命令到文件 |
数据完整性 | 不完整,取决于备份周期 | 相对完整性高,取决于文件刷盘方式 |
文件大小 | 压缩二进制写入,文件较小 | 原始的操作命令,文件大 |
宕机恢复时间 | 快 | 慢 |
恢复优先级 | 低 | 高 |
持久化代价 | 高,消耗大量CPU和内存 | 低,只占用磁盘IO资源 |
使用场景 | 数据备份、主从全量复制、对丢数据不敏感的业务场景快速数据恢复 | 对于丢失数据敏感的场景,例如涉及金钱交易相关的业务 |
我们需要针对不同的业务场景选择合适的持久化方式,也可以根据RDB和AOF的优点配合使用,保证Redis数据的安全性,又可以兼顾它的性能。
2. RDB持久化
RDB是Redis Database 的缩写,其作用是在某一个时间点,将Redis存储在内存中的数据生成快照并存储到磁盘等介质上,存在这个磁盘介质上的文件就是RDB文件。
“快照”顾名思义就是好像照相一样保存当时的数据,这里的RDB文件是一个二进制的文件,并且是经过压缩的。因为RDB文件是保存在硬盘中的,即使Redis服务器进程退出,甚至运行Redis服务器的计算机宕机,但只要RDB文件仍然存在,Redis服务器就可以用它来还原数据库状态。
如下图 所示,可以想象Redis数据库在时间轴上有位于不同时间点的时候都有一个数据库状态,可以把它们想象成一个个切片。图上标注出两个时间点的两个数据库切片,RDB持久化做的事情就是顺着绿色箭头的方向将数据库状态的“切片”以RDB文件的形式保存到磁盘中。
持久化机制:指定的时间间隔内将内存中的数据集以快照写入磁盘
RDB方式的持久化是通过快照(snapshotting)完成的,当符合一定条件时Redis会自动将内存中的数据进行快照并持久化到硬盘。
进行快照的条件可以由用户在配置文件中自定义,由两个参数构成:时间和改动的键的个数。
当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照。
RDB是Redis默认采用的持久化方式,在配置文件中已经预置了3个条件:
save 900 1#900秒内有至少1个键被更改则进行快照
save 300 10#300秒内有至少10个键被更改则进行快照
save 60 10000#60秒内有至少10000个键被更改则进行快照
可以存在多个条件,条件之间是“或”的关系,只要满足其中一个条件,就会进行快照。
如果想要禁用自动快照,只需要将所有的save参数删除即可。
-
Redis默认会将快照文件存储在当前目录(可CONFIG GET dir来查看)的dump.rdb文件中,
可以通过配置dir和dbfilename两个参数分别指定快照文件的存储路径和文件名。
RDB持久化配置(修改redis.conf文件)
RDB持久化配置(修改redis.conf文件)注:标红为配置文件修改部分
deamonize 以进程的形式启动程序改为:yes
timeout 客户端没有操作就中断服务0不中断
RDB快照的配置
database 默认有多少个库16个库
save 900 1每900秒有一次操作就快照一次
rdbcompression对快照进行压缩 yes
dbfilename 这里可以修改dump.rdb的名字
dir ./默认生成当前目录(目录可以修改)
文件修复:redis-check-dump(突然断电什么的造成文件损坏)
通过shutdwon 不会丢失快照数据,直接kill -9直接杀掉异常关机不会实现备份。
一般而言Redis的配置信息会放到redis.conf配置文件中进行存储,其包含很多内容,这里我们就RDB持久化的部分给大家做简单介绍。redis.conf文件中找到“SNAPSHOTTING”(快照)的部分。看如下几个配置项:
# 900秒内有1次修改、300秒内有10次修改、60秒内有10000次修改 #满足任何以上条件,触发RDB持久化。 save 900 1 save 300 10 save 60 10000 # 当快照操作bgsave出错时,是否停止持久化?yes 表示“是”,no表示“否”。 stop-writes-on-bgsave-error yes # 是否压缩?yes表示“是”,no表示“否”,默认选择yes。 rdbcompression yes # 对rdb数据进行校验, 表示写入文件和读取文件时是否开启 RDB 文件检查。 # yes表示“是”,no表示“否”,默认选择yes。 # 选择yes表示在Redis加载RDB需要检查文件是否损坏,如果存在损坏会停止启动。 rdbchecksum yes # 设置rdb的文件名 dbfilename dump.rdb # RDB文件的路径,如果不单独指定,默认是redis的启动路径。 dir ./
RDB实现快照的过程
i.Redis使用fork函数复制一份当前进程(父进程)的副本(子进程);
ii.父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件;
iii.当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此一次快照操作完成。
在执行fork的时候操作系统(类Unix操作系统)会使用写时复制(copy-on-write)策略,
即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),
操作系统会将该片数据复制一份以保证子进程的数据不受影响,所以新的RDB文件存储的是执行fork一刻的内存数据。
Redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。
这使得我们可以通过定时备份RDB文件来实现Redis数据库备份。
RDB文件是经过压缩(可以配置rdbcompression参数以禁用压缩节省CPU占用)的二进制格式,所以占用的空间会小于内存中的数据大小,更加利于传输。
除了自动快照,还可以手动发送SAVE或BGSAVE命令让Redis执行快照,
两个命令的区别在于,SAVE是由主进程进行快照操作,会阻塞住其他请求,BGSAVE会由redis执行fork函数复制出一个子进程来进行快照操作。
Redis启动后会读取RDB快照文件,将数据从硬盘载入到内存。
根据数据量大小与结构和服务器性能不同,这个时间也不同。通常将一个记录一千万个字符串类型键、大小为1GB的快照文件载入到内存中需要花费20~30秒钟。
通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。
这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。
如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。
RDB持久化优劣
优势:整个Redis数据库将只包含一个文件,这对于文件备份而言是非常完美的
劣势:rdb是以每隔一段时间进行一次快照进行的数据持久,如果一旦在这一时间段出现服务器故障,将会灾难性的。
解决:这就需要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够接受的范围。
如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。
RDB持久化恢复Redis数据方面
关于RDB持久化恢复Redis数据方面也比较简单,将RDB持久化文件 (例如:dump.rdb) 移动到 Redis 安装目录并启动Redis服务就可以了。可以通过 Redis 中的“CONFIG GET dir”命令获取Redis的安装目录。
由于RDB是一个压缩的二进制文件,其代表Redis在某一个时间点上的快照。其适合数据库备份和全量复制的场景。比如定期给数据库进行备份,把RDB文件拷贝到其他的服务器上,以及用于灾备。同样是因为压缩的原因,RDB的加载速度比AOF也要快。
3. AOF持久化
AOF(append only file),是以日志的方式记录每次写入的命令,在Redis Server启动的时候会重新执行AOF文件中的命令,从而达到恢复数据的目的。AOF可以解决数据持久化的实时性问题,也是当前Redis主流的持久化方式。
持久化机制:以日志形式记录服务器每一个操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
AOF持久化的过程就是日志不断追加的过程,这里通过图给大家介绍具体流程:
- Redis Client作为命令的来源,会有多个源头以及源源不断的请求命令。
- 在这些命令到达Redis Server 以后,并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令达到一定量以后再写入磁盘,避免频繁的磁盘IO操作。
- AOF缓冲会根据对应的策略将命令写入磁盘上的AOF文件。
- AOF文件随着写入文件内容的增加,会根据规则进行命令的合并,这里叫做AOF重写,从而起到AOF文件压缩的目的。
- 当Redis Server 服务器重启的时候会从AOF文件载入数据。
AOF持久化配置(修改redis.conf文件)
默认情况下Redis没有开启AOF(append only file)方式的持久化,可以在redis.conf中通过appendonly参数开启:
appendonly yes
在启动时Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相较RDB会慢一些
开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。
AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改:
appendfilename appendonly.aof
AOF缓冲区同步文件策略
配置写入AOF文件后,要求系统刷新硬盘缓存的机制
上面提到了Redis 会将命令先写入到AOF缓冲区,再写入AOF文件。这里介绍一下AOF缓冲区同步文件的三个策略。
- always 策略:命令写入AOF缓冲区以后会调用系统fsync 操作同步到AOF文件,fsync完成后线程返回。这里的fsync是针对单个文件的操作,在进行磁盘同步的时候会阻塞直到写入磁盘完成以后返回,从而保证数据持久化的完成。
- everysec 策略:命令写入AOF缓冲区以后调用write操作,write完成后线程返回。此操作会有专门线程执行每秒执行一次。这里的write操作会触发延迟写(delayed write)机制,Linux 内核提供页缓冲区来提高硬盘IO性能。也就是说write 操作写入系统缓冲区以后就返回了,同步硬盘依赖于操作系统调度机制完成。(Redis默认配置)
- no策略:此种刷新策略是根据操作系统来决定的,也就是由操作系统来决定什么时候将缓冲区的数据写入到磁盘中。由于是操作系统来决定持久化,所以这种方式是不可控的。
# appendfsync always #每次执行写入都会执行同步,最安全也最慢 appendfsync everysec #每秒执行一次同步操作 # appendfsync no #不主动进行同步操作,而是完全交由操作系统来做(即每30秒一次),最快也最不安全
AOF 重写
所谓的“重写”其实是一个有歧义的词语,实际上, AOF 重写并不需要对原有的 AOF 文件进行任何写入和读取,
它针对的是数据库中键的当前值。
AOF缓冲区会将Redis Client请求的命令源源不断地同步到AOF文件中,同时AOF文件会不断增大,这里就需要AOF重写。AOF重写就是把Redis进程内的数据转化为写命令同步到新的AOF文件的过程。其目的就是使重写后的AOF文件变得更小:
- 进程内已经超时的数据不会再写入AOF文件中。
- 旧AOF文件含有的无效命令,可以通过进程内的数据直接生成,新的AOF文件只保留最终的数据写入命令。例如就文件中存在三条命令,它们依次是“set hello A”、 “set hello B”和“set hello C”,对同一个key 进行负值只有最后一句“set hello C”是起效的,所以这三条命令会被“set hello C”一条命令替换,并且保存到新的AOF文件中。
- 另外,多条写命令可以合并成一个。例如依次存在三个命令:“lpush list A”、 “lpush list B”和“lpush list C”,这里就可以合并为一条命令“lpush list A B C”。
AOF重写不仅降低了文件的占用空间,同时更小的AOF也可以更快地被Redis加载。
说完了AOF重写的定义以后,下面来看看AOF重写的流程。一般而言有两种方式可以执行重写操作,分别是:bgrewriteaof 命令和AOF重写配置。
bgrewriteaof命令重写
重写的过程只和内存中的数据有关,和之前的aof文件无关。
如下图 所示,整个执行过程由三步组成:
- Redis Client发起bgrewriteaof命令,这个命令是一个异步命令。由于Redis Server 在接受bgrewriteaof命令的同时,还可以接受其他Redis Client的命令,因此后面的第二步和第三步实际上是并行进行的。第二步:进行AOF重写,在同时第三步:还会接受其他非重写的命令请求。
- Redis Server接受到这个命令以后,会启动一个Redis的子进程用来执行AOF重写操作。这个重写过程实际上是针对Redis内存中的数据进行回溯,也就是下方红色区域的“AOF重写缓冲区”。
- 正如在第一步中提到的,在进行第二步的同时第三步还在接受客户端的请求并且通过“AOF缓冲区”保存到“旧AOF文件”中。
- 最终,完成AOF重写操作以后将“新AOF文件”写入到“旧AOF文件”中完成AOF重写。
AOF重写流程图
AOF配置重写
auto-aof-rewrite-percentage 100#当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时的AOF文件大小为依据 auto-aof-rewrite-min-size 64mb#允许重写的最小AOF文件大小
实际上是通过AOF的配置文件中的配置值来确定重写的时机。配置如下:
通过上面的配置可以得到AOF重写的机制如下:
- 当AOF文件当前尺寸大于AOF重写的最小尺寸的时候就触发重写机制。通过上面配置来形成表达式就是:aof-current-size> auto-aof-rewrite-min-size
- 当AOF文件当前尺寸减去AOF文件本身尺寸的值除以AOF文件本身的尺寸得到的结果大于AOF文件重写比率的时候就需要出发重写机制。
表达式就是:aof-current-size- aof-base-size/ aof-base-size > auto-aof-rewrite-percentage
由于Redis的配置文件中RDB是默认配置。AOF需要手动开启。
需要到Redis的配置文件redis.conf中进行如下设置。
#开启AOF模式 ,yes表示“开启AOF模式”。
appendonly yes
与RDB持久化文件恢复数据一样,只需要将AOF文件 移动到 Redis 安装目录,并启动Redis服务就可以在Redis启动的时候加载AOF文件恢复数据了。
通过上面对AOF的描述可以看出,AOF具有数据完整,安全性高(秒级数据丢失)等优点。同时AOF文件以追加日志文件的形式存在,且写入操作是以Redis协议格式保存的,因此其内容是可读性强,适合误删时的紧急恢复。不过,相对于RDB而言其文件尺寸较大,会占用更多Redis启动加载数据的时间。
文件修复
redis-check-aof
Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。此时重新启动Redis后Redis会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少
AOF持久化优劣
AOF持久化方式优劣势:
优势:Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步
1)修改同步:每修改一次同步一次,对于性能的消耗非常大。
2)每秒同步:每秒钟进行的操作进行一次同步
3)不同步
劣势:对于相同数量的数据集而言,AOF文件通常要大于RDB文件,并且根据同步策略的不同,AOF在运行效率上往往会慢于RDB
4.动态切换持久化方案
动态切换redis持久方式,从 RDB 切换到 AOF(支持Redis2.2及以上)
CONFIG SET appendonly yes
CONFIG SET save ""(可选)
注意:当redis启动时,如果rdb持久化和aof持久化都打开了,那么程序会优先使用aof方式来恢复数据集,
因为aof方式所保存的数据通常是最完整的。如果aof文件丢失了,则启动之后数据库内容为空。
注意:如果想把正在运行的redis数据库,从RDB切换到AOF,建议先使用动态切换方式,再修改配置文件,重启数据库。
(不能直接修改配置文件,重启数据库,否则数据库中数据就为空了。)
5.持久化后,服务器宕机的恢复数据(主从复制)
通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据。
但是由于数据是存储在一台服务器上的,如果这台服务器的硬盘出现故障,也会导致数据丢失。
为了避免单点故障,我们希望将数据库复制多个副本以部署在不同的服务器上,即使有一台服务器出现故障其他服务器依然可以继续提供服务。
这就要求当一台服务器上的数据库更新后,可以自动将更新的数据同步到其他服务器上,Redis提供了复制(replication)功能可以自动实现同步的过程。
- 配置方法
通过配置文件从数据库的配置文件中加入slaveof master-ip master-port,主数据库无需配置
通过命令行参数启动redis-server的时候,使用命令行参数--slaveof master-ip master port
redis-server --port 6380--slaveof 127.0.0.16379
通过命令SLAVEOF master-ip master-port
redis>SLAVEOF 127.0.0.16379
SLAVEOF NO ONE可以是当前数据库停止接收其他数据库的同步,转成主数据库
主从复制优点及应用场景
1.读写分离通过复制可以实现读写分离以提高服务器的负载能力。
在常见的场景中,读的频率大于写,当单机的Redis无法应付大量的读请求时(尤其是较耗资源的请求,比如SORT命令等)可以通过复制功能建立多个从数据库,
主数据库只进行写操作,而从数据库负责读操作。
2.从数据库持久化持久化通常相对比较耗时,为了提高性能,可以通过复制功能建立一个(或若干个)从数据库,并在从数据库中启用持久化,
同时在主数据库禁用持久化。
当从数据库崩溃时重启后主数据库会自动将数据同步过来,所以无需担心数据丢失。
而当主数据库崩溃时,需要在从数据库中使用SLAVEOF NO ONE命令将从数据库提升成主数据库继续服务,
并在原来的主数据库启动后使用SLAVEOF命令将其设置成新的主数据库的从数据库,即可将数据同步回来。
6.其他config
相关命令
redis的config命令
使用config set可以动态设置参数信息,服务器重启之后就失效了。
config set appendonly yes
config set save "90 1 30 10 60 100
使用config get可以查看所有可以使用config set命令设置的参数
config get *
使用config rewrite命令对启动Redis服务器时所指定的 redis.conf 文件进行改写(Redis2.8及以上版本才可以使用),
主要是把使用config set动态指定的命令保存到配置文件中。
config rewrite
注意:config rewrite命令对 redis.conf 文件的重写是原子性的,并且是一致的:
-
如果重写出错或重写期间服务器崩溃,那么重写失败,
原有 redis.conf 文件不会被修改。 - 如果重写成功,那么 redis.conf 文件为重写后的新文件。
-
ps -ef | grep redis 查看进程服务是否启动
kill -93004杀掉进程
bgrewriteaof 手动重写aof
requirepass password 配置redis访问密码
auth password 客户端登陆输入访问密码
参考链接:
一杯茶的功夫,上手Redis持久化机制