• Redis基础篇(四)持久化:内存快照(RDB)


    AOF好处是每次执行只需要记录操作命令,记录量不大。但在故障恢复时,需要逐一执行AOF的操作命令,如果日志很大,恢复就很慢。

    今天学习另一种持久化方式:内存快照。内存快照,是Redis某一时刻的状态,以文件的形式保存在磁盘上。这个快照文件就称为RDB文件,其中RDB就是Redis Database的缩写。

    当故障恢复时,只要把RDB文件读入内存即可,恢复速度很快。但是内存快照并不是最优选项,为什么呢?

    我们还需要考虑两个问题:

    • 对哪些数据做快照?这关系到快照的执行效率;
    • 做快照时,数据还能被增删改吗?这关系到Redis是否被阻塞,能否同时正常处理请求。

    对哪些数据做快照?

    Redis的数据都在内存中,为了提供所有数据的可靠性保证,它执行的是全量快照。

    Redis提供两个命令生成RDB文件:

    • save:在主线程中执行,但会导致阻塞;
    • bgsave:创建一个子进程,专门用于写入RDB文件,避免了主线程的阻塞。也是Redis RDB文件生成的默认配置。

    做快照时,数据还能被增删改吗?

    如果快照执行期间数据不能被修改,是会有潜在问题的。假如做快照的20s时间里,如果数据不能被修改,Redis就不能处理对这些数据的写操作,那无疑就会给业务服务造成巨大影响。

    Redis借助操作系统提供的写时复制技术(Copy-On-Write,COW),在执行快照的同时,正常处理写操作。

    bgsave流程图

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

    当主线程要修改数据时,通过COW复制一份副本出来给bgsave子进程。

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

    可以每秒做一次快照吗?

    如果内存快照每隔几分钟执行一次,这样就可能出现丢失数据的风险。那么是否可以每秒做一次快照吗?

    如果频繁地执行全量快照,会带来两方面开销:

    • 一是频繁将全量数据写入磁盘,会给磁盘带来很大压力。
    • 二是bgsave子进程需要从主线程fork出来,fork创建过程本身会阻塞主线程,而且主线程的内存越大,阻塞时间越长。

    既然频繁执行全量快照不行,那还有什么其他好方法吗?

    第一个方法是做增量快照

    在第一次做完全量快照后,T1和T2时刻如果再做快照,只需要将被修改的数据写入快照文件就行了。如下图所示:

    image

    第二个方法是Redis 4.0提出一个混合使用AOF日志和RDB快照的方法:RDB快照以一定的频率执行,在两次快照之间,使用AOF日志记录这期间的所有命令操作。

    T1和T2时刻的修改,用AOF日志记录,等到第二次做全量快照时,就可以清空AOF日志,因为此时的修改都已经记录到快照中了。如下图所示:

    image

    拓展

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

    主要有两方面风险:内存资源风险CPU资源风险

    内存资源风险

    Redis fork子进程做RDB持久化,由于写的比例为80%,那么在持久化过程中,“写时复制”会重新分配整个实例80%的内存副本,大约需要重新分配1.6GB内存空间,这样整个系统的内存使用接近饱和。

    如果此时父进程又有大量新key写入,很快机器内存就会被吃光,如果机器开启了Swap机制,那么Redis会有一部分数据被换到磁盘上。

    当Redis访问这部分在磁盘上的数据时,性能会急剧下降,已经达不到高性能的标准。

    如果没有开启Swap,会直接触发OOM,父子进程会面临被系统kill掉的风险。

    CPU资源风险

    虽然子进程在做RDB持久化,但生成RDB快照过程会消耗大量的CPU资源。

    虽然Redis处理请求是单线程的,但Redis Server还有其他线程在后台工作,例如AOF每秒刷盘、异步关闭文件描述符这些操作。

    由于机器只有2核CPU,这也就是意味着父进程占用了超过一半的CPU资源。

    此时子进程做RDB持久化,可能会产生CPU竞争,导致的结果是父进程处理请求延迟增大,子进程生成RDB快照的时间也会变长,整个Redis Server性能下降。

    如果Redis进程绑定了CPU,那么子进程会继续父进程的CPU亲和性属性,子进程必然会与父进程争夺同一个CPU资源,整个Redis Server的性能必然会受到影响。

    因此如果Redis需要开启定时RDB和AOF重写,进程一定不要绑定CPU。

    参考资料

  • 相关阅读:
    高级查询及分页总结
    SQL编程
    线程同步
    创建和启动线程
    错题集04
    错题集03
    错题集02
    错题集
    新闻发布系统
    九大内置对象
  • 原文地址:https://www.cnblogs.com/liang24/p/14180984.html
Copyright © 2020-2023  润新知