宕机了,Redis数据丢了怎么办?
前言 什么是AOF? 三种写回策略 日志文件太大怎么办? AOF重写会阻塞主线程吗? AOF的缺点 总结 什么是RDB? 给哪些数据做快照? 快照时能够修改数据吗? 多久做一次快照? 增量快照 AOF和RDB混合使用 总结 总结
前言
Redis
作为内存型的数据库,虽然很快,依然有着很大的隐患,一旦「服务器宕机」重启,内存中数据还会存在吗?Redis
来说,实现数据的持久化和快速恢复是至关重要。Redis
持久化的两种机制AOF
日志、RDB
快照。什么是 AOF 日志?
AOF
(Append Only File
)日志称之为「写后日志」,即是命令先执行完成,把数据写入内存,然后才会记录日志。AOF
日志(文本形式)会将收到每一条的命令且执行成功的命令以一定的格式写入到文本中(追加的方式)。对于写前日志无论命令是否执行成功都会被记录,但是 Redis
的写后日志则只有命令执行成功才会被写入日志,避免了日志中存在错误命令;同时由于是命令执行成功之后才会写入日志,因此不会阻塞当前命令的执行。
AOF
日志也有「潜在的风险」,分析如下:由于是写后日志,如果在命令执行成功之后,在日志未写入磁盘之前服务器突然宕机,那重启恢复数据的时候,这部分的数据肯定在日志文件中不存在了,那么将会丢失。(无法通过后台数据库恢复的情况下) 虽然不会阻塞当前命令的执行,由于记录日志也是在主线程中( Redis
是单线程),如果日志写入磁盘的时候突然阻塞了,肯定会影响下一个命令的执行。
AOF
日志提供了三种回写策略。三种写回策略
AOF
机制提供了三种回写策略,这些都在appendfsync
配置,如下:Always
(同步写回):命令执行完成,立马同步的将日志写入磁盘Everysec
(每秒写回):命令执行完成后,先将日志写入 AOF 文件的内存缓冲区,每隔一秒把缓冲区中内容写入磁盘。No
(操作系统控制的写回):每个写命令执行完,只是先把日志写到AOF
文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。
同步写回
:基本不丢失数据,但是每步操作都会有一个慢速的落盘操作,不可避免的影响主线程性能。每秒写回
:采用一秒写一次到 AOF 日志文件中,但是一旦宕机还是会丢失一秒的数据。操作系统控制的写回
:在写完缓冲区之后则会写入磁盘,但是数据始终在缓冲区的时间内一旦宕机,数据还是会丢失。
日志文件太大怎么办?
Redis
会创建一个新的AOF
日志文件,将每个键值对最终的值用一条命令写入日志文件中。set key1 value1
AOF
日志文件中将会记录多次修改键值的命令,重写机制是根据这个键值最新状态为它生成「写入」命令,这样旧文件中的「多条」命令在重写后的新日志中变成了「一条」命令。AOF重写会阻塞主线程吗?
bgrewriteaof
来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。fork
一个子线程bgrewriteaof
,主线程会把内存数据拷贝一份到子线程,此时子线程中包含了数据库的最新数据。然后子线程就能在不影响主线程的情况下进行AOF重写了。第一处日志
:子线程重写并未阻塞主线程,此时主线程仍然会处理请求,此时的AOF日志仍然正在记录着,这样即使宕机了,数据也是齐全的。第一处日志即是值主线程正在使用的日志。第二处日志
:指新的AOF重写日志;重写过程中的操作也会被写到重写日志缓冲区,这样重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。
Redis
在进行AOF
重写时,会fork
一个子线程(不会阻塞主线程)并进行内存拷贝用于重写,然后使用两个日志保证重写过程中,新写入的数据不会丢失。AOF的缺点
总结
Always
、Everysec
和No
,这三种策略在可靠性上是从高到低,而在性能上则是从低到高。什么是RDB?
RDB
(Redis DataBase)是另外一种持久化方式:内存快照。RDB
记录的是「某一个时刻」的内存数据,并不是操作命令。RDB
文件。给哪些数据做快照?
save
:在主线程中执行,会导致主线程阻塞。bgsave
:fork
一个子进程,专门用于写入RDB
文件,避免了主线程的阻塞,这是Redis的默认配置。
bgsave
命令执行全量快照,既可以保证数据的可靠性也避免了主线程的阻塞。快照时能够修改数据吗?
T
时刻进行全量快照,假设数据量有8G
,写入磁盘的过程至少需要20S
,在这20S
的时间内,一旦内存中的数据发生了修改,则快照的完整性就破坏了。Redis
借助操作系统提供的写时复制技术
(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。bgsave
命令会fork
一个子线程,这个子线程共享所有内存的数据,子线程会读取主线程内存中的数据,将他们写入RDB
文件。键值对A
的读取并不会影响子线程,但是如果主线程一旦修改内存中一块数据(例如键值对D
),这块数据将会被复制一个副本,然后bgsave
子线程会将其写入RDB
文件。多久做一次快照?
T1
时间做了一次快照,在T1+t
时又做了一次快照,如果在t
这个时间段内服务器突然宕机了,则快照中只保存了T1
时刻的快照,在t
时间段内的数据修改未被记录(丢失)。如下图:RDB
并不是一个完美的日志记录方案」,只有让t
时间逐渐缩小,才能保证丢失的数据缩小。1秒
吗?」 即是每秒执行一次快照。增量快照
AOF
和RDB
混合使用的方式。AOF和RDB混合使用
Redis4.0
提出的,简单的说就是「内存快照以一定的频率执行,比如1小时一次,在两次快照之间,使用AOF日志记录这期间的所有命令操作。」总结
RDB
内存快照记录的是某一个时刻的内存数据,因此能够快速恢复;AOF
和RDB
混合使用能够使得宕机后数据快速恢复,又能够避免AOF
日志文件过大。总结
AOF
和RDB
。AOF
介绍了什么?如下:AOF
是写后日志,通过记录操作命令持久化数据。由于 AOF
是在命令执行之后记录日志,如果在写入磁盘之前服务器宕机,则会丢失数据;如果写入磁盘的时候突然阻塞,则会阻塞主线程;为了解决以上问题,AOF机制提供了三种写回的策略,每种策略都有不同的优缺点。AOF
日志文件过大怎么办?AOF
通过fork
一个子线程重写一个新的日志文件(共享主线程的内存,记录最新数据的写入命令),同时子线程重写,避免阻塞主线程。
RDB
介绍了什么?如下:RDB
是内存快照,记录某一个时刻的内存数据,而不是操作命令。Redis
提供了两个命令,分别是save
、bgsave
来执行全量快照,这两个命令的区别则是save
是在主线程执行,势必会阻塞主线程,bgsave
是在fork
一个子线程,共享内存。RDB通过操作系统的「写时复制技术」,能够保证在执行快照的同时主线程能够修改快照。 由于两次快照之间是存在间隔的,一旦服务器宕机,则会丢失两次间隔时刻的数据, Redis4.0
开始使用AOF
日志记录两次快照之间执行的命令(AOF
和RDB
混合使用)。
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号
好文章,我在看❤️
评论