导语
redis作为内存数据库,为了防止因为程序bug或者机器故障导致的数据丢失,redis采取了多维度的措施来保障redis写入数据的安全。从单机层面:采取备份磁盘镜像 数据流水的形式,将内存状态落地到本地磁盘,防止因程序bug或者系统故障导致的数据丢失;从多机层面:通过主备机制,进行远程热备,保障数据安全。
本文分为拆分为多篇,分别从RDB、AOF、主备等角度介绍redis的数据落磁盘机制,介绍落地原理及相关源码流程、主备机制,包括原理,相关协议,以及具体实现。因笔者能力有限,行文观点若有疏漏,恳请指正。更多内容,移步作者个人博客
磁盘备份
redis通过磁盘实现数据落地,主要通过内存镜像定时备份和记录操作流水两种方式:
- 所谓内存镜像定时备份,即RDB(Redis DataBase):redis定时对内存进行全量备份,落地到本地磁盘文件;
- 所谓记录操作流水,即AOF(Append Only File):由于内存全量备份资源开销大,因此RDB只能做到定时更新&备份的时间粒度比较大,所以redis又通过记录操作流水的方式(即AOF),实现存储数据操作的回放。
RDB
所谓RDB,即内存镜像备份机制我们主要关注以下几个问题:
- 什么情况下,会触发redis进程执行RDB操作?
- redis如何进行RDB,期间发生数据的修改怎么办?
- RDB文件的格式是怎样,redis如何解析rdb文件?
我们结合代码,逐个问题进行分析。
RDB触发时机
代码语言:txt复制在redis的配置文档中,我们可以看到rdb触发的时机分为两个维度:时间维度和修改维度;当修改次数超过指定配置,或者修改后超过指定时间,则触发RDB流程。
以下为RDB主调流程的框架,其中:
RDB主流程为rdbSaveBackground接口
触发RDB流程分为两种情形:
客户端执行SAVE/BGSAVE指令,主动触发RDB流程;
二者区别在于,save会阻塞主进程直到RDB完成,bgsave会fork子进程执行rdb流程
定时任务触发(serverCron),当指定时间内修改次数超过阈值时触发RDB流程;
RDB流程是互斥的,即同一时刻只能一个RDB流程在跑;在这期间若是出现客户端执行BGSAVE指令,服务器也是不响应的,会推迟到本地RDB结束之后再执行;
RDB落地流程
代码语言:txt复制redis的RDB是通过fork一个进程实现的,由于进程之间是独立地址空间的,借助Linux的COW机制,当RDB过程中有数据发生修改,被修改的数据只会体现在redis主进程中,对rdb进程没有影响。
代码语言:txt复制另一方面,当redis写请求大的时候,会导致redis内存耗用量变大,为了避免redis在RDB过程中被OOM,需要配置redis的内存占用,避免因为占用内存多大导致进程挂掉。
以上为redis的RDB主流程,主要包括以下几点:
- redis通过fork子进程的形式进行RDB,父进程主要负责一些数据管理和状态记录,实际数据落地操作交给子进程来做;父子进程通过管道进行通信
- redis的落地和数据分为三层:
- 文件级:主要写入文件头、DB和系统相关的管理信息;在接口rdbSave和rdbSaveRio中进行
- DB级:逐个DB进行处理,包括每个DB的大小、DB ID等信息;主要在接口rdbSaveRio中进行
- 数据级:即DB里面每个KV对,主要在接口rdbSaveKeyValuePair中进行
- 需要落地的数据包括:
- Redis-server的元数据,包括redis版本号、系统信息、redis占用内存的大小等
- Database元数据信息:redis版本、键值对数目等
- DB中的字段
- 每个DB的lua脚本
- 由于字典rehash会触发系统的COW机制,所以为了降低内存开销,在RDB过程中,关闭rehash
- RDB文件的格式为:
RDB文件加载
Redis-server在启动过程中,会根据指令加载指定位置的rdb文件,核心流程的代码如下:
主要需要注意的是:
- Redis-server实例启动之后,在完成初始化工作后,通过调用栈:loadDataFromDisk-> rdbLoad->rdbLoadRio完成rdb文件的载入;其中loadDataFromDisk是根据标志位走入rdb分支还是AOF分支,而rdbLoad主要为RDB流程进行相关的准备工作;而真正载入rdb数据的,是rdbLoadRio接口
- server.loading是用于标识当前是否处于加载文件的阶段,这个标志位会对很多模块的逻辑产生影响,亦即,若是在加载rdb文件过程中,很多操作是不允许被执行的
- 超时的KV,在载入RDB数据的时候会删除掉
参考资料
- 《Redis设计与实现》黄建宏著
- https://www.cnblogs.com/winterfells/p/9161540.html
- https://cloud.tencent.com/developer/article/1427626
- https://unix.stackexchange.com/questions/33381/getting-information-about-a-process-memory-usage-from-proc-pid-smaps
- https://blog.csdn.net/u010902721/article/details/46446031
- https://blog.csdn.net/petib_wangwei/article/details/38225929
- http://www.web-lovers.com/redis-source-rdb.html
- http://sunny90.com/a/server/2014/0905/103.html