美文网首页
自我系统学习Redis小记-02

自我系统学习Redis小记-02

作者: Timor小先生 | 来源:发表于2021-10-19 19:23 被阅读0次

    04 | AOF日志:宕机了,Redis如何避免数据丢失?

    1、一个问题引出持久化:一旦服务器宕机,内存中的数据将全部丢失。

    容易的解决方案:从后端数据库恢复这些数据,存在两个问题

    1)、频繁操作数据库,给db带来压力

    2)、一段时间内导致应用程序变慢

    所以,redis持久化至关重要,能避免从后端恢复数据,目前redis有两种持久化方式,即 AOF 日志和 RDB 快照

    2、AOF 日志是如何实现的

    DB是WAL,写前日志,也就是在写数据前,先把修改的数据记录在日志中,以便故障恢复

    AOF是写后日志,意思是Redis是先执行命令,把数据写入内存,再记录日志

    Redis AOF操作过程

    AOF 为什么要先执行命令再记日志呢?

    不同于DB,AOF记录的是每一条命令,以文本方式保存

    AOF 日志内容

    *3 :代表有三部分,每部分都是由“$+数字”开头,后面紧跟着具体的命令、键或值,“数字”代表和部分有多少字节

    Redis再向AOF记录日志时不会检查命令的语法,因此如果先记日志在执行命令可能出现错误的命令,导致redis日志恢复时出错。

    所以写后日志的好处是:

    1)、先让系统执行命令,只有命令能执行成功,才会被记录到日志中,可以避免出现记录错误命令的情况

    2)、不会阻塞当前的写操作

    AOF 也有两个潜在的风险

    1)、如果执行完一条命令直接宕机,没来得及记录日志,那么这个命令和相应的数据就有丢失的风险

    2)、AOF 虽然避免了对当前命令的阻塞,但可能会给下一个操作带来阻塞风险

    这是因为,AOF 日志也是在主线程中执行的,如果在把日志文件写入磁盘时,磁盘写压力大,就会导致写盘很慢,进而导致后续的操作也无法执行了。

    所以,AOF写会磁盘的时机很重要。

    3、三种写回策略-----AOF配置项 appendfsync 的三个可选值。

    Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘;

    Everysec,每秒写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘;

    No,操作系统控制的写回:每个写命令执行完,只是先把日志写到 AOF 文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘。

    三种写回策略优缺点

    4、AOF日志文件太大了怎么办?

    日志过大带来的三个影响:

    1)、文件系统本身限制文件大小,过大无法保存

    2)、文件过大,再往里面追加命令,效率变慢

    3)、如果发生宕机,AOF中记录的命令熬一个一个的被执行,用于故障恢复,如果日志文件过大,整个恢复过程会相当缓慢,会影响Redis的正常使用

    解决方案:AOF 重写机制

    说白了就是多条命令变一条命令,下面这个是6变1

    AOF重写减小日志大小

    5、AOF重写会阻塞吗?

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

    即:一个拷贝,两处日志:

    一个拷贝:每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,fork 会把主线程的内存拷贝一份给 bgrewriteaof 子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。

    两处日志:因主线程未阻塞,仍然可以执行写操作,此时,如有写操作,

    第一处日志指正在使用的 AOF 日志,Redis会把这个操作写到他的缓冲区,这样一来即使宕机,这个aof日志是齐全的,可以用来恢复;

    第二处日志是指新的 AOF 重写日志,这个新的操作也会被记录到重写日志的缓冲区,保证重写aof日志不丢失新的操作,等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。

    AOF非阻塞的重写过程

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

    6、小结

    1)、写回策略三种,trade-off 取舍原则,性能-可靠性

    2)、重写日志


    05丨内存快照:宕机后,Redis如何实现快速恢复?

    1、引出问题,AOF恢复比较缓慢,还有没有既可以保证可靠性,还能在宕机时实现快速恢复的其他方法?

    另一种持久化方式:RDB内存快照------所谓内存快照,就是指内存中的数据在某一个时刻的状态记录。这就类似于照片,当你给朋友拍照时,一张照片就能把朋友一瞬间的形象完全记下来。

    对 Redis 来说,它实现类似照片记录效果的方式,就是把某一时刻的状态以文件的形式写到磁盘上,也就是快照。

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

    需要考虑的问题:

    1)、对哪些数据做快照?这关系到执行效率

    2)、做快照时,数据还能被增删改吗?这关系到 Redis 是否被阻塞,能否同时正常处理请求。

    (答案:Redis 会使用 bgsave 对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主线程同时可以修改数据。)

    2、给哪些内存数据做快照?

    Redis提供所有数据的可靠性保证,所以他执行的是全量快照,即将内存中的所有数据都记录到磁盘中。

    Redis 提供了两个命令来生成 RDB 文件,分别是 save 和 bgsave。

    ----------save:在主线程中执行,会导致阻塞;

    ----------bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是Redis RDB 文件生成的默认配置。

    这时就可以通过 bgsave 命令来执行全量快照,这既提供了数据的可靠性保证,也避免了对 Redis 的性能影响。

    3、快照时数据能修改吗?

    如果在快照时数据修改,会有潜在风险,如果不允许修改,会给业务造成压力。

    bgsave 避免阻塞,避免阻塞和正常处理写操作并不是一回事,快照时,主线程能正常接收请求,但是为了保证快照的完整性,他只能处理读操作,不能处理正在快照数据的写操作。

    为了快照暂停写操作是不可取的,所以Redis借助操作系统提供写时复制技术(Copy-On-Write, COW),在执行快照时,正常处理写操作。

    写时复制机制保证快照期间数据可修改

    bgsave 子进程是由主线程 fork 生成的,可以共享主线程的所有内存数据。

    bgsave 子进程运行后,开始读取主线程的内存数据,并把它们写入 RDB 文件。读操作主线程、副本线程互不影响。

    但是,如果主线程要修改一块数据(例如图中的键值对 C),那么,这块数据就会被复制一份,生成该数据的副本。

    然后,bgsave 子进程会把这个副本数据写入 RDB 文件,而在这个过程中,主线程仍然可以直接修改原来的数据。

    写时复制技术(Copy-On-Write, COW)就保证里快照完整性、也允许主线程对数据修改,避免对业务影响。

    4、可以每秒做一次快照吗?

    快照机制下丢失数据

    虽然 bgsave 执行时不阻塞主线程,但是,如果频繁地执行全量快照,也会带来两方面的开销

    1)、频繁将全量数据写入磁盘,会给磁盘带来很大压力,多个快照竞争有限的磁盘带宽,前一个快照还没做完,后一个又开始了,容易恶性循环。

    2)、bgsave 子进程需要通过 fork 操作从主线程创建出来,创建以后不影响主线程,fork 这个创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长,频繁fork出bgsave子进程,就会频繁阻塞主线程。

    解决这个问题可以采用增量快照,也就是说,在做一次全量快照以后,后续的快照只对修改的数据进行快照记录,这样可以避免每次全量快照的开销。

    增量快照的前提是:我们需要记住哪些数据被修改了

    增量快照示意图

    5、混合使用 AOF 日志和内存快照

    虽然跟 AOF 相比,快照的恢复速度快,但是,快照的频率不好把握,如果频率太低,两次快照间一旦宕机,就可能有比较多的数据丢失。如果频率太高,又会产生额外开销。

    划重点!!!!!

    那么,还有什么方法既能利用 RDB 的快速恢复,又能以较小的开销做到尽量少丢数据呢?

    Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。简单来说,内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。

    优点是  :

    1)、快照不用频繁执行,避免了频繁 fork 对主线程的影响

    2)、两次快照间的操作记录 AOF 日志,不会出现文件过大的情况,也可以避免重写开销

    接下来,看一下这个混合模式的过程:

    RDB和AOF混合使用

    这个混合模式即享受到了RDB的快速恢复,又能享受到AOF记录简单命令。

    6、小结

    这节课,我们学习了 Redis 用于避免数据丢失的内存快照方法。这个方法的优势在于,可以快速恢复数据库,也就是只需要把 RDB 文件直接读入内存,这就避免了 AOF 需要顺序、逐一重新执行操作命令带来的低效性能问题。

    不过,内存快照也有它的局限性。它拍的是一张内存的“大合影”,不可避免地会耗时耗力。虽然,Redis 设计了 bgsave 和写时复制方式,尽可能减少了内存快照对正常读写的影响,但是,频繁快照仍然是不太能接受的。而混合使用 RDB 和 AOF,正好可以取两者之长,避两者之短,以较小的性能开销保证数据可靠性和性能。

    最后,关于 AOF 和 RDB 的选择问题,我想再给你提三点建议:

    1)、数据不能丢失时,内存快照和 AOF 的混合使用是一个很好的选择;

    2)、如果允许分钟级别的数据丢失,可以只使用 RDB;

    3)、如果只用 AOF,优先使用 everysec 的配置选项,因为它在可靠性和性能之间取了一个平衡。

    相关文章

      网友评论

          本文标题:自我系统学习Redis小记-02

          本文链接:https://www.haomeiwen.com/subject/ypuaoltx.html