redis核心技术与实战系列2:基础篇B

一、日志,宕机了,redis如何避免数据丢失

本章主要讲redis如何保障它的可靠性?我们知道redis是内存数据库所以性能高速度快,但是会带来一个致命性的问题,一旦服务器宕机,内存数据库将全部丢失.那么如何保证redis的数据持久化呢?本章为你作出解答:分别为AOF和RDB.这两种方式有何区别?分别适用于何种场景业务呢?这就需要你了解这两种方式的基本原理了.带着疑问开始关于redis日志的学习吧.

Redis 的持久化两大机制
  1. AOF(Append Only File)日志
  2. RDB 快照。
AOF 日志是如何实现的?
  1. AOF是“写后”日志,即先执行命令,把数据写入内存,然后才记录日志.
  2. AOF 记录的是 Redis 收到的每一条命令,以文本形式保存的。
AOF优点
  • 可以避免出现记录错误命令的情况。
  • 它是在命令执行后才记录日志,不阻塞当前的写操作
三种写回策-AOF 配置项 appendfsync
  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;
  • Everysec,每秒写回:每个写命令执行完,先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;
  • No,操作系统控制的写回:每个写命令执行完,先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时
选择场景:
  • 高性能–No 策略
  • 高可靠性保证-- Always 策略
  • 允许数据有一点丢失且希望性能别受太大影响的话–Everysec 策略
日志文件太大了怎么办?—AOF重写机制
AOF重写机制

目的:
对过大的AOF文件进行重写,以此来压缩AOF文件的大小。

方式:
检查当前键值数据库中的键值对,记录键值对的最终状态,从而实现对[某个键值对重复操作后产生的多条操作记录压缩成一条]的效果。进而实现压缩AOF文件的大小。

AOF 重写会阻塞吗

和 AOF 日志由主线程写回不同,重写过程是由后台子进程 bgrewriteaof 来完成的,这也是为了避免阻塞主线程,导致数据库性能下降。

一个拷贝,两处日志。

每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用额外的线程进行数据重写,所以,这个过程并不会阻塞主线程。

小结

1、介绍了 Redis 用于避免数据丢失的 AOF 方法。通过逐一记录操作命令,在恢复时再逐一执行命令的方式,保证了数据的可靠性。
2、AOF 日志的三种写回策略:Always、Everysec 和 No,这三种策略在可靠性上是从高到低,而在性能上则是从低到高。
3、为了避免日志文件过大,Redis 还提供了 AOF 重写机制,直接根据数据库里数据的最新状态,生成这些数据的插入命令,作为新日志。这个过程通过后台线程完成,避免了对主线程的阻塞。
4、三种写回策略体现了系统设计中的一个重要原则 ,即 trade-off,或者称为“取舍”,指的就是在性能和可靠性保证之间做取舍。
落盘时机和重写机制都是在“记日志”这一过程中发挥作用的。例如,落盘时机的选择可以避免记日志时阻塞主线程,重写可以避免日志文件过大。但是,在“用日志”的过程中,也就是使用 AOF 进行故障恢复时,我们仍然需要把所有的操作记录都运行一遍。再加上 Redis 的单线程设计,这些命令操作只能一条一条按顺序执行,这个“重放”的过程就会很慢了。
那么,有没有既能避免数据丢失,又能更快地恢复的方法呢?当然有,那就是 RDB 快照了。

每课一问

这节课,我给你提两个小问题:
AOF 日志重写的时候,是由 bgrewriteaof 子进程来完成的,不用主线程参与,我们今天说的非阻塞也是指子进程的执行不阻塞主线程。但是,你觉得,这个重写过程有没有其他潜在的阻塞风险呢?如果有的话,会在哪里阻塞?
AOF 重写也有一个重写日志,为什么它不共享使用 AOF 本身的日志呢?

二、redis05-内存快照,宕机后redis如何快速恢复
AOF存在的问题:

AOF 方法进行故障恢复的时候,需要逐一把操作日志都执行一遍。如果操作日志非常多,Redis 就会恢复得很缓慢,影响到正常使用。

那么,还有没有既可以保证可靠性,还能在宕机时实现快速恢复的其他方法呢?

内存快照RDB

指内存中的数据在某一个时刻的状态记录。将某一时刻的状态以文件的形式写到磁盘上。即使宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件就称为 RDB (Redis DataBase)。就类似于照片,当你给朋友拍照时,一张照片就能把朋友一瞬间的形象完全记下来。

和 AOF 相比,RDB 记录的是某一时刻的数据,并不是操作,所以,在做数据恢复时,我们可以直接把 RDB 文件读入内存,很快地完成恢复。

由此我们需要考虑两个问题。
1、对哪些数据做快照?这关系到快照的执行效率问题;
2、做快照时,数据还能被增删改吗?这关系到 Redis 是否被阻塞,能否同时正常处理请求。

用个拍照的形象例子类比上面两个问题,即:
1、如何取景?我们打算把哪些人、哪些物拍到照片中;
2、在按快门前,要记着提醒朋友不要乱动,否则拍出来的照片就模糊了。

针对任何操作,我们都会提一个灵魂之问:“它会阻塞主线程吗?”

RDB 文件的生成是否会阻塞主线程,这就关系到是否会降低 Redis 的性能。

Redis 生成 RDB 文件方式:
  • save:在主线程中执行,会导致阻塞;
  • bgsave(默认配置):创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞。
    借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。
主线程同时在修改数据怎么办

如果主线程对这些数据也都是读操作(例如图中的键值对 A),那么,主线程和 bgsave 子进程相互不影响。但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本。然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。

这既保证了快照的完整性,也允许主线程同时对数据进行修改,避免了对正常业务的影响。

快照时间间隔

对于快照来说,所谓“连拍”就是指连续地做快照.即快照的间隔时间变得很短,即使某一时刻发生宕机了,因为上一时刻快照刚执行,丢失的数据也不会太多。

如下图所示,我们先在 T0 时刻做了一次快照,然后又在 T0+t 时刻做了一次快照,在这期间,数据块 5 和 9 被修改了。如果在 t 这段时间内,机器宕机了,那么,只能按照 T0 时刻的快照进行恢复。此时,数据块 5 和 9 的修改值因为没有快照记录,就无法恢复了。

t可以越小越好吗?

要想尽可能恢复数据,t 值就要尽可能小,t 越小,就越像“连拍”。但是可能带来的后果呢?

  • 频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没有做完,后一个又开始做了,容易造成恶性循环。
  • bgsave 子进程需要通过 fork 操作从主线程创建出来。虽然子进程在创建后不会再阻塞主线程,但是,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。如果频繁 fork 出 bgsave 子进程,这就会频繁阻塞主线程了。

那么,有什么其他好方法吗?

增量快照

增量快照:做了一次全量快照后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。
在第一次做完全量快照后,T1 和 T2 时刻如果再做快照,我们只需要将被修改的数据写入快照文件就行。但是,这么做的前提是,我们需要记住哪些数据被修改了。你可不要小瞧这个“记住”功能,它需要我们使用额外的元数据信息去记录哪些数据被修改了,这会带来额外的空间开销问题。如下图所示:

虽然跟 AOF 相比,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销,那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF 日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。
如下图所示,T1 和 T2 时刻的修改,用 AOF 日志记录,等到第二次做全量快照时,就可以清空 AOF 日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。

小结

1、学习了 Redis 用于避免数据丢失的内存快照方法–RDB。优势在于可以快速恢复数据库, 只需要把 RDB 文件直接读入内存,这就避免了 AOF 需要顺序、逐一重新执行操作命令带来的低效性能问题。
2、RDB局限性在于它拍的是一张内存的“大合影”,不可避免地会耗时耗力。即使Redis 设计了 bgsave 和写时复制方式,尽可能减少了内存快照对正常读写的影响,但是,频繁快照仍然是不太能接受的。而混合使用 RDB 和 AOF,正好可以取两者之长,避两者之短,以较小的性能开销保证数据可靠性和性能。
3、 AOF VS RDB :
数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;
如果允许分钟级别的数据丢失,可以只使用 RDB;
如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。

每课一问

我曾碰到过这么一个场景:我们使用一个 2 核 CPU、4GB 内存、500GB 磁盘的云主机运行 Redis,Redis 数据库的数据量大小差不多是 2GB,我们使用了 RDB 做持久化保证。当时 Redis 的运行负载以修改操作为主,写读比例差不多在 8:2 左右,也就是说,如果有 100 个请求,80 个请求执行的是修改操作。你觉得,在这个场景下,用 RDB 做持久化有什么风险吗?你能帮着一起分析分析吗?

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值