ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Redis RDB持久化原理解析

2021-05-23 12:03:46  阅读:247  来源: 互联网

标签:fork Redis RDB bgsave server 键值 rdb 解析


Redis版本:Redis 4.0.1 Redis是一个键值对数据库服务器,存储在内存中,如果重启没进行持久化,数据会丢失。所以需要持久化策略RDB和AOF。 涉及Redis源码解析: https://gitee.com/lidishan/redis-source-code-analysis/blob/master/src/rdb.c   前提知识归纳 RDB用于保存和恢复数据库所有键值对 使用save或bgsave报错,其中bgsave是fork子进程不会造成阻塞 rdb文件是一个二进制文件 不同类型键,会有不同数据结构存储   RDB会采用save、bgsave进行rdb保存 save:生成RDB,会导致Redis阻塞 bgsave:生成RDB,fork子进程处理 备注:RDB是在服务器启动的时候自动载入的(如果有rdb文件)。但如果开启了AOF(更新·频率更高),服务器就会 优先使用AOF文件加载数据。   其中是否执行bgsave这些是根据 RedisServer#saveparams 来判断,其数据结构如下: struct redisServer { ....     // 保存触发 rdb 文件存储的参数数组     struct saveparam * saveparams ; /* Save points array for RDB */ } // 在seconds秒内数据库修改changes次就触发RDB文件生成 struct saveparam {     time_t seconds ;// 秒数     int changes ;// 数据库修改次数 }; 符合上面的参数生成RDB,举个例子:
  • seconds=1, changes=5。即代表1秒内数据库有5次修改就可以重新生成RDB
  bgsave是fork子进程进行处理,其触发方式大概有如下两种: 手动触发:执行bgsave命令手动触发   自动触发:根据上面的saveparams命令定时触发 或者 主从节点同步 sync指令或psync(这个做主从分析的时候再解析)   下面举个定时触发的例子源码(serverCron定时触发,然后扫描saveparams参数) /** * 作为时间事件运行 */ int serverCron ( struct aeEventLoop *eventLoop , long long id , void *clientData) {     ....     // 单位时间内修改次数达到上限     if (server. dirty >= sp-> changes &&         server.unixtime-server.lastsave > sp->seconds &&  (server.unixtime-server.lastbgsave_try >  CONFIG_BGSAVE_RETRY_DELAY ||  server. lastbgsave_status == C_OK))  {         // 打印保存进行中的日志         serverLog(LL_NOTICE , "%d changes in %d seconds. Saving..." ,         sp-> changes , ( int )sp->seconds) ;         rdbSaveInfo rsi , *rsiptr ;         rsiptr = rdbPopulateSaveInfo(&rsi) ;         // 进行 bgsave         rdbSaveBackground(server. rdb_filename , rsiptr) ;         break;     }     .... }   /** * rdbbgsave ,会 fork 一个子进程处理 **/ int rdbSaveBackground ( char *filename , rdbSaveInfo *rsi) {     pid_t childpid ; // 子进程     // 判断是否有活跃的子进程在拷贝,如果有则终止 server.child_pid != -1     if (hasActiveChildProcess()) return C_ERR ;      // 记录当前 bgsave 前的数据库被修改次数 和 最后修改的时间     server. dirty_before_bgsave = server. dirty ;     server.lastbgsave_try = time(NULL) ;     // fork 子进程     if ((childpid = redisFork(CHILD_TYPE_RDB)) == 0 ) {         int retval ;           /* Child */         redisSetProcTitle( "redis-rdb-bgsave" ) ; // 设置标题         redisSetCpuAffinity(server. bgsave_cpulist ) ; // 设置 CPU 亲缘属性         retval = rdbSave(filename , rsi) ; // 开始保存         if (retval == C_OK) { // 发送保存数据             sendChildCowInfo( CHILD_INFO_TYPE_RDB_COW_SIZE , "RDB" ) ;         }         exitFromChild((retval == C_OK) ? 0 : 1 ) ; // 结束子进程保存     } else {         /* Parent */         // fork 子进程失败         if (childpid == - 1 ) {             server. lastbgsave_status = C_ERR ;             serverLog(LL_WARNING , "Can't save in background: fork: %s" ,             strerror(errno)) ;             return C_ERR ;         }         // 保存状态         serverLog(LL_NOTICE , "Background saving started by pid %ld" , ( long ) childpid) ;         server.rdb_save_time_start = time(NULL) ;         server. rdb_child_type = RDB_CHILD_TYPE_DISK ;         return C_OK ;     }     return C_OK ; /* unreached */ }  
上面解释了RDB是如何装载进来的,那下面来讲解一下RDB的文件结构。如何存储?如何压缩? RDB文件大致组成结构 - REDIS:标识RDB文件开头的字符'REDIS' - db_version:4字节。记录RDB文件版本号 - database:包含0-N个数据库 - EOF:标记RDB结束 - check_sum:保存前面四个的校验和,用于做签名校验   其中database存储结构如下 - SELECTDB:database存储的开始标识 - db_number:1/2/5字节。数据库号码 - key_value_pairs:存储当前数据库中所有的键值对数据, 根据类型不同而结构不同   key_value_pairs结构为 不带过期时间的键值对 - TYPE:记录value类型,主要含string、list、zset、hash、list_zipskiplist等 - key:redis key,总是string类型 - value:redis对应的值 带过期时间的键值对 - EXPIRETIME_MS:1字节。开始标识 - ms:8字节。UNIX时间戳 - TYPE:记录value类型,主要含string、list、zset、hash、list_zipskiplist等 - key:redis key,总是string类型 - value:redis对应的值   接下来讲解一下 value是怎么根据TYPE编码来生成RDB的对应值数据(大致讲解几个即可,知道什么回事,没必要纠结) String字符串 字符串<=20字节:len记录原来长度 字符串>20字节:origin_len记录原来长度,compresesed_len记录压缩后长度   List列表 记录长度,然后item一个接一个拼起来(每个元素记录长度)   set集合 跟list一样   hash哈希 记录有多少个键值对,比如下面:2个键值对,"a"->"apple","b"->"banana"   zset有序集合 记录分数和item      

标签:fork,Redis,RDB,bgsave,server,键值,rdb,解析
来源: https://blog.csdn.net/qq_28666081/article/details/117192030

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有