前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis源码走读及编程实践——数据安全篇(二)

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

原创
作者头像
王鹏程1990
修改2021-10-13 11:14:38
7310
修改2021-10-13 11:14:38
举报
文章被收录于专栏:源码阅读

导语

《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,则发现出现截断则启动失败。

操作落地

代码语言:txt
复制
所谓AOF(Append Only File)是redis在RDB之外的一种数据落地机制,区别于RDB全量备份内存镜像,AOF机制采取的是记录操作流水的方式实现数据落地,因此可以实践秒级甚至可以完全的无数据丢失。
代码语言:txt
复制
Redis中,AOF落地其实分为三步:首先是写数据到AOF数据缓存区,然后是将数据从用户缓存区通过系统调用复制到内核缓存区,此时进程挂掉数据不会丢失,但是机器掉电或者系统崩溃会导致数据丢失;最后是写文件的数据从内核缓存区真正写入到磁盘,此时真正意义数据落地;可以通过手动调用flush和fsync强制数据刷到内核缓存区和强制数据落磁盘。
代码语言:txt
复制
在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重写

代码语言:txt
复制
由于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

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导语
  • AOF
    • 配置篇
      • 操作落地
        • AOF重写
          • 加载流程
          • 参考资料
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档