专栏首页源码阅读Redis源码走读及编程实践——数据安全篇(二)
原创

Redis源码走读及编程实践——数据安全篇(二)

导语

《Redis源码走读及编程实践——数据安全篇(一)》介绍了RDB的落地原理并走读了redis的RDB落地流程,本文继续介绍redis的另外一种数据落地机制AOF,从配置、原理三个角度介绍redis的AOF机制。因笔者能力有限,行文观点若有疏漏,恳请指正。更多后台开发文章移步:作者个人博客

AOF

如前所述,redis采取RDB的方式进行全内存镜像备份;但是这种方式开销大,不能频繁进行;为了降低数据丢失,redis采取记录操作流水的形式记录客户端每次对redis-server数据的修改,也就是AOF(Append Only File)。关于AOF,主要需要关注以下几个问题:

  1. AOF具体的实现流程是怎样的?
  2. AOF文件如何描述redis-server的DB操作?
  3. 由于AOF是记录操作流水,AOF是如何解决操作流水中数据冗余的问题?

配置篇

Redis-server配置中和AOF相关的配置如下图:

Redis官方对于各个配置项的解释很清楚,这里简要介绍一下,具体可以参考redis发布包配置文件中的说明文档:

  1. appendonly:redis默认采取RDB模式进行数据冷备;但是由于RDB模式开销比较大,频率不能太高,所以间隔之间挂机的话会有分钟级的数据丢失。而AOF则是可以保证秒级或者严格的无数据丢失,更加适用于数据比较重要的场景。
  2. appendfilename:AOF落地写文件的文件名。
  3. appendfsync:程序写磁盘实际是一个异步过程,实际只是将数据写到一个输出缓存;需要依次经过flush和fsync才能落到磁盘上;而appendfsync提供了写文件刷磁盘的机制,可以分别配置为:
    1. no:表示不强制刷盘,根据os调度自动执行,性能最高,但是落地延迟不确定
    2. everysec:每秒强制调用fsync落到磁盘,可以达到秒级的数据持久性;
    3. always:每写一条log,就调用一次fsync同步到磁盘,严格保证数据落地,但是性能较差
  4. no-appendfsync-on-rewrite:当AOF配置为always或者everysec时,会强制fsync数据刷盘,但是当此时正在有线程执行bgsave或者AOF重写过程时,容易导致fsync阻塞时间过长,影响redis-server的性能,为此通过此配置项控制,若是后端有重写或者落地过程时,不执行刷盘机制。
  5. auto-aof-rewrite-percentage和auto-aof-rewrite-min-size:针对前文所述,AOF记录的操作流水,则必然存在大量的数据冗余,因此AOF提供了AOF重写机制规避这种问题,这两个配置就是触发AOF重写的条件,一个是文件大小至少得达到一定大小(auto-aof-rewrite-min-size)才会触发AOF重写;其次,达到一定的变化量才会触发AOF重写(auto-aof-rewrite-percentage)。
  6. aof-load-truncated:redis在运行过程中若是系统崩溃了,容易出现AOF文件被截断的情况,若是出现这种情况,通过此配置决定是否正常启动;若是配置yes,则表示接受AOF截断,然后尽可能多的从文件恢复数据;若是配置no,则发现出现截断则启动失败。

操作落地

所谓AOF(Append Only File)是redis在RDB之外的一种数据落地机制,区别于RDB全量备份内存镜像,AOF机制采取的是记录操作流水的方式实现数据落地,因此可以实践秒级甚至可以完全的无数据丢失。
Redis中,AOF落地其实分为三步:首先是写数据到AOF数据缓存区,然后是将数据从用户缓存区通过系统调用复制到内核缓存区,此时进程挂掉数据不会丢失,但是机器掉电或者系统崩溃会导致数据丢失;最后是写文件的数据从内核缓存区真正写入到磁盘,此时真正意义数据落地;可以通过手动调用flush和fsync强制数据刷到内核缓存区和强制数据落磁盘。
在redis中feedAppendOnlyFile完成上述流程的第一步,而flushAppendOnlyFile完成数据落内核缓存区和写磁盘两步:依次来看,首先是feedAppendOnlyFile接口:
  1. feedAppendOnlyFile的调用时机:在redis-server实例接收到客户端的指令请求之后,会对比server的dirty值,若大于0,则表示最近一次执行的redis命令触发了DB的数据发生变化,那么与此同时aof_state指令打开,则意味着开启AOF机制,则此时调用feedAppendOnlyFile走记录日志流水的流程;
  2. AOF机制中,类expireCommand命令都被转为pexpireCommandAt命令,类setexCommand的命令都被转为setCommand和pexpireatCommand命令;
  3. AOF重写过程中,若是出现写DB操作出现,由于当前文件会被丢弃掉,所以在写文件的同时需要写复制积压缓存区,同步给子进程落地;

数据flush并没有完全实际意义上的数据落地,flushAppendOnlyFile才是实际完成数据落磁盘:

关于AOF数据落地,需要关注以下几点:

  1. 对于always的落地策略,redis在flushAppendOnlyFile接口中是通过调用接口aof_fsync直接实现的;
  2. 而对于everysec的落地机制,redis采取的是提交任务,然后交给后台线程执行落地指令;也就是说其实现在的redis-server实际上是多进程+多线程的框架;
  3. 对于部分写入的场景,redis的机制是,发现只能部分写入,则认为写操作失败,写的数据全部回滚,通过truncate文件实现,并且在下次写入的时候重新尝试写入(若是always的写入机制则此时redis-server无法从错误中恢复,只能选择结束进程);
  4. 由于多进程同时写多个文件,带来IO性能的损耗,因此通知配置aof_no_fsync_on_rewrite开关来关闭bgsave或者aof-rewrite过程中的刷盘信息;这种做法,虽然提升了性能,但也带来一定的风险,即刷盘未完成机器宕机或系统崩溃会有数据丢失;

AOF重写

由于AOF记录的是redis的操作流,则必然存在很多冗余信息;时间长了,会导致AOF文件过大,既占用了存储空间又导致了重启进程的时候重建数据时间过长,为此redis采取AOF重写的方式来消除冗余数据;如前所述,触发AOF重写有两个维度,一个是文件大小;另外一个是文件的增长比例;在此,我们着重看AOF重写流程:

AOF重写的核心接口与流程已经在上面截图中有所论述,我们针对其中的一些需要注意的点进行说明:

  1. AOF重写的流程框架为:通过接口rewriteAppendOnlyFileBackground来fork出子进程负责执行AOF重写的核心主控接口rewriteAppendOnlyFile,主控接口通过rewriteAppendOnlyFileRio/rdbSaveRio完成内存镜像落地(以字节串形式或者指令流的格式),通过aofReadDiffFromParent完成复制积压缓存区的写入;
  2. AOF重写机制中,父子进程通过管道进行通信,包括:父进程写AOF重写期间发生写操作的指令流;子进程通知父进程停止写复制积压缓存区等;
  3. 相比AOF指令流回放,RDB重建DB的速度更快,因此redis4之后,通过开关aof_use_rdb_preamble控制是否打开RDB+AOF混合持久化机制,对于RDB+AOF混合持久化的AOF重写文件,实际就是RDB文件

加载流程

在redis server启动的时候,会加载磁盘数据,根据配置项中的AOF开关,判断是加载RDB文件还是AOF文件,分别通过不同的接口rdbLoad和loadAppendOnlyFile实现;关于AOF文件的加载,核心代码的流程如下部分代码截图所示;这里归纳一下需要注意的地方:

  1. 由于AOF存在混合持久化的机制,因为在加载AOF文件之处,会先加载头文件五个字节,判断是否是AOF混合持久化的落地文件,若是的话,采取RDB的加载机制;否则通过构建伪终端的形式,通过重放redis命令重建DB;
  2. 因为redis在执行指令的时候需要涉及很多client的成员变量,用于缓存参数等,所以在重放AOF文件的时候需要构建一个伪终端,即对端连接的client;
  3. 因为AOF存的是指令流,因此存在在指令落地的时候,进程crash了,导致指令不全,此时通过开关aof_load_truncated控制是否接收残缺的AOF文件,若是接受残缺的AOF文件,则在读到最后的时候会丢弃最后一次指令结果;
  4. 此外,在类似list这种含有N个元素的数据结构中,对于RDB的重建机制,就是读取N个参数读入进来,但是对于AOF重建来说,每个参数实际对应一个RPUSH key val指令,需要解析三个参数并执行一个RPUSH指令,因此来说RDB的重建效率要高于AOF所以redis4.0之后开启了RDB+AOF混合持久化机制。

参考资料

  1. 《Redis设计与实现》黄建宏著
  2. https://www.cnblogs.com/winterfells/p/9161540.html
  3. https://cloud.tencent.com/developer/article/1427626
  4. https://unix.stackexchange.com/questions/33381/getting-information-about-a-process-memory-usage-from-proc-pid-smaps
  5. https://blog.csdn.net/u010902721/article/details/46446031
  6. https://blog.csdn.net/petib_wangwei/article/details/38225929
  7. http://www.web-lovers.com/redis-source-rdb.html
  8. http://sunny90.com/a/server/2014/0905/103.html

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Redis源码走读及编程实践——数据安全篇(一)

    redis作为内存数据库,为了防止因为程序bug或者机器故障导致的数据丢失,redis采取了多维度的措施来保障redis写入数据的安全。从单机层面:采取备份磁盘...

    王鹏程1990
  • redis代码走读与编程实践——网络交互篇(上)

    redis是一种内存数据存储系统,可被用作数据库、缓存、消息队列等;以高性能、高并发能力著称;本文分为上下两篇,其中上篇主要着眼于最简单的单机数据库&非事务命令...

    王鹏程1990
  • redis代码走读与编程实践——网络交互篇(下)

    在文章《redis代码走读与编程实践——网络交互篇(上)》中,对redis连接请求与建立流程进行源码剖析和走读;本文主要尝试编写一个简单的redis客户端和re...

    王鹏程1990
  • 有了它,Redis不再是你技术面试中的阻碍

    Redis在互联网技术存储方面使用非常广泛,几乎所有的后端技术面试官都要在Redis的使用和原理方面对求职小伙伴们进行各种刁难,特别是那些优秀的、竞争激烈的大型...

    博文视点Broadview
  • 小白和进阶都适用! java学习路上必看的书单

    男怕入错行,女怕嫁错郎,学java最怕看错书!也是很久之前就想写这篇了,以前也零零星星的推荐过几本书,但是始终没有这样认真的整理一篇出来,这篇文章就是和...

    微笑的小小刀
  • 2021 最新的Java 后端学习路线!凎!

    断断续续写了大半个月,终于把 2021 最新版的 Java 后端学习路线给整完了!

    Guide哥
  • 惊艳!阿里内部445页爆款Redis源码分析宝典终开源

    在开源界,高性能服务的典型代表就是Nginx和Redis。纵观这两个软件的源码,都是非常简洁高效的,也都是基于异步网络I/O机制的,所以对于要学习高性能服务的程...

    烂猪皮
  • 进BAT这些互联网大厂,面试之前刷几百道面试题真的有用吗?

    面试之前先刷几篇面经,或者做几道热门面试题,想必是大家很熟悉的一种复习方式了,就像我们当年经常做五年高考三年模拟一样。但是可不要把面试题和面经当成你的主要复习...

    美的让人心动
  • 七种武器之一口箱子Redis

    江湖传言「在任何规模、任何类型的服务器项目中,都存在一些最适合用Redis存储的数据。」

    有福
  • 基于实践:一套百万消息量小规模IM系统技术要点总结

    本文由公众号“后台技术汇”分享,原题“基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统”,原文链接在文末。由于原文存在较多错误和不准确内容,有大...

    JackJiang
  • (码友推荐)2018-07-09 .NET及相关开发资讯速递

    4.为什么Kubernetes获得了胜利?--让Kubernetes成为开发人员最喜欢的容器编排平台的的秘诀是什么? - DockOne.io

    Rector
  • Redis 深度历险:核心原理与应用实践

    Redis 是互联网技术架构在存储系统中使用最为广泛的中间件,它也是中高级后端工程师技术面试中面试官最喜欢问的工程技能之一,特别是那些优秀的、竞争激烈的大型互联...

    Bug开发工程师
  • 【真荐书】双11书单,我们一起共读 36 + 1 本书

    《Redis开发与运维》全面讲解 Redis 基本功能及其应用,并结合线上开发与运维监控中的实际使用案例,深入分析并总结了实际开发运维中遇到的“陷阱”,以及背后...

    kirito-moe
  • 今日推荐:awesome-architecture

    但是这条路还是有很多人走,而且也留下了相应的封神之法,今天推荐的就是一个相当详细的架构师框架学习图。内容很充实,看目录的时候,滚动条滚了很多次!学习起来肯定也不...

    仇诺伊
  • 学习 Java,有什么书籍推荐?学习的方法和过程是怎样的?

    为什么要学 Linux 呢?因为在实际的开发工作中,项目基本上都要部署到 Linux 环境下。Windows 作为服务器的很少,除了慢没别的原因。

    AI码师
  • Spring Boot整合ELK 处理为服务日志,妙!

    在排查线上异常的过程中,查询日志总是必不可缺的一部分。现今大多采用的微服务架构,日志被分散在不同的机器上,使得日志的查询变得异常困难。工欲善其事,必先利其器。如...

    OwenZhang
  • 阿里,百度,腾讯一线互联网公司中,Java开发的招聘标准(文末福利)!

    精讲java
  • PHP核心技术与最佳实践 - 列旭松,陈文

    《PHP核心技术与最佳实践》是一本致力于为希望成为中高级PHP程序员的读者提供高效而有针对性指导的经典著作。系统归纳和深刻解读了PHP开发中的编程思想、底层原理...

    用户3157710
  • Github开源免费编程书籍

    时见疏星

扫码关注云+社区

领取腾讯云代金券