Redis是⼀个基于内存的数据库,它的数据是存放在内存中,内存有个问题就是关闭服务或者断电会丢失。Redis的数据也⽀持写到硬盘中,这个过程就叫做持久化。
Redis提供如下2中持久化⽅式:
•
RDB
(
Redis DataBase
)
:在指定的时间间隔内,定时的将
redis
存储的数据⽣成
Snapshot
快照并存储到磁盘等介质上;
•
AOF
(
Append Of File
)
:将
redis
执⾏过的所有写指令记录下来,在下次
redis
重新启动时,只要把这些写指令从前到后再重复执⾏⼀遍,就可以实现数据恢复了。
• AOF+RDB : RDB 和 AOF 两种⽅式也可以同时使⽤,在这种情况下,如果 redis 重启的话,则会优先采⽤ AOF ⽅式来进⾏数据恢复,这是因为 AOF ⽅式的数据恢复完整度更⾼。
1.RDB
Redis Database Backup file(Redis数据备份⽂件
)
,也被叫作
Redis
数据快照。简单的来说就是把内存中的所有数据都记录到磁盘中。当
Redis
实例故障重启后,从磁
盘读取快照⽂件(⼆进制⽂件),恢复数据。快照⽂件称为
RDB
⽂件。
我们知道
Redis
是单线程程序,这个线程要
同时负责多个客户端套接字的并发读写操作和内存数据结构的逻辑读写
。
在服务线上请求的同时,Redis
还需要进⾏内存快照,内存快照要求
Redis
必须进⾏⽂件
IO
操作,这意味着单线程同时在服务线上的请求还要进⾏⽂件
IO
操作,⽂件
IO
操作会严重拖垮服务器请求的性能。还有个重要的问题是为了不阻塞线上的业务,就需要边持久化边响应客户端请求。
SAVE的执⾏时机:
1.
执⾏
save
命令
2.
执⾏
bgsave
命令
3.
触发
RDB
条件时候
save 900 1
900
秒内,如果⾄少有
1
个
key
被修改,则执⾏
bgsave
, 如果是
save ""
则表示
禁⽤
RDB
bgsave
Redis 在持久化时会调⽤
glibc
的函数
fork
产⽣⼀个⼦进程,快照持久化完全交给⼦进程来处理,⽗进程继续处理客户端请求。⼦进程刚刚产⽣时,它和⽗进程共享内存⾥⾯的代码段和数据段。这时你可以将⽗⼦进程想像成⼀个连体婴⼉,共享身体。这是 Linux
操作系统的机制,为了节约内存资源,所以尽可能让它们共享起来。在进程分离的⼀瞬间,内存的增⻓⼏乎没有明显变化。
COPY-ON-WRITE(写时复制)
其核⼼思想是,如果有多个调⽤者(callers
)同时请求相同资源(如内存或磁盘上的
数据存储
),他们会共同获取相同的指针指向相同的资源,直到某个调⽤者试图修改资源的
内容时,系统才会真正复制⼀份专⽤副本(
private copy
)给该调⽤者,⽽其他调⽤者所⻅到的最初的资源仍然保持不变。
这⾥会有⼀个极端的情况,⽐如
Redis
内存⼤
⼩是
32
个
GB
,在某⼀个时刻,这
32GB
的数
据都被修改了,根据上⾯
COW
技术,那么就
需要把当前数据在复制⼀份,需要内存⼤⼩
为
32G
了,两个内存占⽤量就是
64GB
,所
以,我们在给
Redis
分配内存空间的时候,需
要注意,需要给
Redis
预留⼀些空间内存。
RDB的优缺点
RDB 的优点
体积更⼩:相同的数据量
RDB
数据⽐
AOF
的⼩,因为
RDB
是紧凑型⽂件。
恢复更快:因为
RDB
是数据的快照,基本上就是数据的复制,不⽤重新读取再写⼊内存。
性能更⾼:⽗进程在保存 RDB 时候只需要fork⼀个⼦进程,⽆需⽗进程的进⾏其他io操作,也保证了服务器的性能。
RDB 的缺点
故障丢失:因为
RDB
是全量的,我们⼀般是使⽤
shell
脚本实现
30
分钟或者
1
⼩时或者每天对
Redis
进⾏
RDB
备份,
(注,也可以是⽤⾃带的策略),但是最少也要
5
分钟进⾏⼀次的备份,所以当服务死掉后,最少也要丢失
5
分钟的数据。
耐久性差:相对
AOF
的异步策略来说,因为
RDB
的复制是全量的,即使是
fork
的⼦进程来进⾏备份,当数据量很⼤的时
候对磁盘的消耗也是不可忽视的,尤其在访问量很⾼的时候,主线程
fork
的时间也会延⻓,导致
cpu
吃紧,耐久性相对较
差。
2.AOF持久化机制
AOF
持久化:以独⽴⽇志的⽅式记录每次写命令,重启时再重新执⾏
AOF
⽂件中的命令达到回复数据的⽬的。
AOF
的主要作⽤是解决了数据持久化的实时性。
开启⽅式:
开启
AOF
功能需要设置配置:
appendonly yes
,默认不开启。
AOF
⽂件名通过
appendfilename
配置设置,默认⽂件名是
appendonly.aof
。保存路径同
RDB
持久化⽅式⼀致,通过dir
配置指定。
系统调⽤write和fsync说明:
Write操作会触发延迟写机制。
Linux
在内核提供⻚缓冲区⽤来提⾼硬盘
IO
性能。
wirte
操作在写⼊系统缓冲区后直接返回。同步硬盘操作依赖 于系统调度机制。例如:缓冲区⻚空间写满或达到特定时间周期。同步⽂件之前,如果此时系统故障宕机,缓冲区内数据将丢失。
fync针对单个⽂件操作(⽐如
AOF
⽂件),做强制硬盘同步,
fsync
将阻塞直到写⼊硬盘完成后返回,保证了数据持久化
AOF追加阻塞
当开启AOF
持久化时,常⽤的同步硬盘的策略是
everysec
,⽤于平 衡性能和数据安全性。对于这种⽅式,Redis
使⽤另⼀条线程每秒执 ⾏fsync
同步硬盘。当系统硬盘资源繁忙时,会造成
Redis
主线程阻 塞
阻塞流程分析:
1
)主线程负责写⼊
AOF
缓冲区
2
)
AOF
线程负责每秒执⾏⼀次同步磁盘操作,并记录最近⼀次同步时
间
3
)主线程负责对⽐上次
AOF
同步时间
如果距上次同步成功时间在
2
秒内,主线程直接返回。
如果距上次同步成功时间超过
2
秒,主线程将会阻塞,直到同步操作完
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
)主进程
fork
操作完成后,继续响应其他命令。所有修改命令依然写
⼊
AOF
缓冲区并根据
appendfsync
策略同步到硬盘,保证原有
AOF
机制
正确性
由于
fork
操作运⽤写时复制技术,⼦进程只能共享
fork
操作时的内
存数据。由于⽗进程依然响应命令,
Redis
使⽤
“AOF
重写缓冲区
”
保存
这部
分新数据,防⽌新
AOF
⽂件⽣成期间丢失这部分数据
4
)⼦进程根据内存快照,按照命令合并规则写⼊到新的
AOF
⽂件。每
次批量写⼊硬盘数据量由配置
aof-rewrite-incremental-fsync
控制,默
认为
32MB
,防⽌单次刷盘数据过多造成硬盘阻塞
5
)新的
AOF
⽂件写⼊完成后,⼦进程发送信号给⽗进程,⽗进程更新
统计信息,具体⻅
info persistence
下的
aof_*
相关统计
⽗进程把
AOF
重写缓冲区的数据写⼊到新的
AOF
⽂件
使⽤新
AOF
⽂件替换⽼⽂件,完成
AOF
重写
AOF的优缺点分析
AOF 的优点
数据保证:我们可以设置
fsync
策略,⼀般默认是
Everysec
,也可以设置每次写⼊追加,所以即使服务死掉了,也最多丢失⼀秒数据
⾃动缩⼩:当
AOF
⽂件⼤⼩到达⼀定程度的时候,后台会⾃动的去执⾏
AOF
重写,此过程不会影响主进程,重写完成后,新的写⼊将会写到新的
AOF
中,
旧的就会被删除掉。但是此条如果拿出来对⽐
RDB
的话还是没有必要算成优点,只是官⽹显示成优点⽽已。
AOF 的缺点
性能相对较差:它的操作模式决定了它会对
Redis
的性能有所损耗。(主线程写⽂档)
体积相对更⼤:尽管是将
AOF
⽂件重写了,但是毕竟是操作过程和操作结果仍然有很⼤的差别,体积也毋庸置疑的更⼤。
恢复速度更慢:因为要重新加载每条命令的执⾏,恢复速度⽐较慢