元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
Redis核心
▶
数据结构
字符串实现
哈希表实现
列表实现
集合实现
有序集合实现
▶
内存管理
内存分配策略
淘汰算法
▶
持久化
▶
RDB机制
快照生成原理
文件格式解析
▶
AOF机制
命令追加策略
重写过程分析
▶
高可用
▶
主从复制
SYNC原理
增量复制
▶
哨兵机制
故障检测
领导选举
▶
高级特性
▶
事务系统
ACID实现
WATCH原理
▶
Lua脚本
沙盒环境
执行管道
▶
实战问题
▶
缓存问题
缓存雪崩
缓存穿透
缓存击穿
缓存预热
▶
数据一致性
读写一致性
双写一致性
▶
性能优化
大key处理
热点key优化
发布时间:
2025-03-22 10:43
↑
☰
# Redis RDB文件格式解析 ## 引言 RDB文件是Redis持久化数据的二进制格式,本文将深入分析RDB文件的格式结构、编码方式以及解析过程,帮助读者理解Redis的数据存储机制。 ## 文件结构 ### 1. 文件头 ```c // RDB文件头格式 +----------------+---------------+ | "REDIS" | db_version | | 5 bytes magic | 4 bytes ver | +----------------+---------------+ // 示例代码 char magic[10]; snprintf(magic, sizeof(magic), "REDIS%04d", RDB_VERSION); if (rdbWriteRaw(rdb, magic, 9) == -1) goto werr; ``` ### 2. 数据库结构 ```c // 数据库格式 +----------------------+------------------+ | SELECTDB | db_number | | 1 byte | 1-5 bytes | +----------------------+------------------+ | key-value pairs | ... | +----------------------+------------------+ ``` ### 3. 键值对格式 ```c // 键值对结构 +-------------+----------+-----------+-------------+ | EXPIRETIME | ms-time | TYPE | key-value | | (optional) | 8 bytes | 1 byte | ... | +-------------+----------+-----------+-------------+ ``` ## 数据编码 ### 1. 长度编码 ```c // 长度编码实现 int rdbSaveLen(rio *rdb, uint64_t len) { unsigned char buf[2]; size_t nwritten; if (len < (1<<6)) { /* Save a 6 bit len */ buf[0] = (len&0xFF)|(RDB_6BITLEN<<6); if (rdbWriteRaw(rdb,buf,1) == -1) return -1; nwritten = 1; } else if (len < (1<<14)) { /* Save a 14 bit len */ buf[0] = ((len>>8)&0xFF)|(RDB_14BITLEN<<6); buf[1] = len&0xFF; if (rdbWriteRaw(rdb,buf,2) == -1) return -1; nwritten = 2; } else { /* Save a 32 bit len */ buf[0] = RDB_32BITLEN; if (rdbWriteRaw(rdb,buf,1) == -1) return -1; len = htonl(len); if (rdbWriteRaw(rdb,&len,4) == -1) return -1; nwritten = 1+4; } return nwritten; } ``` ### 2. 字符串编码 ```c // 字符串编码类型 typedef enum { RDB_ENC_INT8 = 0, /* 8 bit signed integer */ RDB_ENC_INT16 = 1, /* 16 bit signed integer */ RDB_ENC_INT32 = 2, /* 32 bit signed integer */ RDB_ENC_LZF = 3, /* LZF compressed string */ } rdbEncoding; // 字符串编码示例 int rdbSaveRawString(rio *rdb, unsigned char *s, size_t len) { int enclen; int n, nwritten = 0; /* Try integer encoding */ if (len <= 11) { unsigned char buf[5]; if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) { if (rdbWriteRaw(rdb,buf,enclen) == -1) return -1; return enclen; } } /* Try LZF compression */ if (server.rdb_compression && len > 20) { n = rdbSaveLzfStringObject(rdb,s,len); if (n == -1) return -1; if (n > 0) return n; } /* Store verbatim */ if ((n = rdbSaveLen(rdb,len)) == -1) return -1; nwritten += n; if (len > 0) { if (rdbWriteRaw(rdb,s,len) == -1) return -1; nwritten += len; } return nwritten; } ``` ### 3. 数据类型编码 ```c // 数据类型编码 typedef enum { RDB_TYPE_STRING = 0, RDB_TYPE_LIST = 1, RDB_TYPE_SET = 2, RDB_TYPE_ZSET = 3, RDB_TYPE_HASH = 4, RDB_TYPE_ZIPMAP = 9, RDB_TYPE_ZIPLIST = 10, RDB_TYPE_INTSET = 11, RDB_TYPE_ZSET_ZIPLIST = 12, RDB_TYPE_HASH_ZIPLIST = 13, RDB_TYPE_LIST_QUICKLIST = 14, RDB_TYPE_STREAM_LISTPACKS = 15 } rdbType; ``` ## 解析过程 ### 1. 文件校验 ```c // CRC64校验 static uint64_t crc64_tab[256]; // 初始化CRC表 void rdbLoadRio(rio *rdb) { uint64_t cksum; // 读取文件头 char buf[10]; if (rioRead(rdb,buf,9) == 0) goto eoferr; buf[9] = '\0'; // 校验魔数 if (memcmp(buf,"REDIS",5) != 0) { rdbExitReportCorruptRDB("Wrong signature"); } // 校验版本 int rdbver = atoi(buf+5); if (rdbver < 1 || rdbver > RDB_VERSION) { rdbExitReportCorruptRDB("Can't handle RDB format version"); } // 校验CRC if (rdb->update_cksum) { cksum = rdb->cksum; memrev64ifbe(&cksum); rioWrite(rdb,&cksum,8); } } ``` ### 2. 类型解析 ```c // 类型解析函数 int rdbLoadType(rio *rdb) { unsigned char type; if (rioRead(rdb,&type,1) == 0) return -1; return type; } // 解析示例 while(1) { int type; // 读取类型 if ((type = rdbLoadType(rdb)) == -1) break; // 根据类型解析数据 switch(type) { case RDB_TYPE_STRING: if (rdbLoadStringObject(rdb) == NULL) goto eoferr; break; case RDB_TYPE_LIST: if (rdbLoadListObject(rdb) == NULL) goto eoferr; break; case RDB_TYPE_SET: if (rdbLoadSetObject(rdb) == NULL) goto eoferr; break; // ... } } ``` ### 3. 数据重建 ```c // 数据重建过程 int rdbLoad(char *filename) { FILE *fp; rio rdb; int retval; // 打开文件 if ((fp = fopen(filename,"r")) == NULL) return C_ERR; // 初始化rio rioInitWithFile(&rdb,fp); retval = rdbLoadRio(&rdb); // 重建数据库 while(retval == C_OK) { robj *key, *val; // 加载键值对 if ((key = rdbLoadStringObject(&rdb)) == NULL) { retval = C_ERR; break; } if ((val = rdbLoadObject(type,&rdb)) == NULL) { decrRefCount(key); retval = C_ERR; break; } // 存储到数据库 dbAdd(db,key,val); } return retval; } ``` ## 性能优化 ### 1. 压缩优化 ```c // LZF压缩配置 rdbcompression yes // 压缩实现 int rdbSaveLzfStringObject(rio *rdb, unsigned char *s, size_t len) { size_t comprlen, outlen; unsigned char *out; // 计算压缩后长度 comprlen = len*105/100+13; if ((out = zmalloc(comprlen)) == NULL) return 0; // LZF压缩 outlen = lzf_compress(s,len,out,comprlen); if (outlen == 0) { zfree(out); return 0; } // 写入压缩数据 int nwritten = rdbSaveRawString(rdb,out,outlen); zfree(out); return nwritten; } ``` ### 2. 内存优化 ```c // 内存优化配置 rdb-save-incremental-fsync yes // 增量同步实现 size_t rdbWriteRaw(rio *rdb, void *p, size_t len) { if (rdb->io.buffer.ptr != NULL) { rioBufferWrite(rdb,p,len); } else { if (rioWrite(rdb,p,len) == 0) return 0; } return 1; } ``` ### 3. 校验优化 ```c // 校验和配置 rdbchecksum yes // 校验实现 void rioGenericUpdateChecksum(rio *r, const void *buf, size_t len) { r->cksum = crc64(r->cksum,buf,len); } ``` ## 工具支持 ### 1. 文件检查 ```bash # 检查RDB文件 redis-check-rdb dump.rdb # 分析RDB内容 redis-memory-analyzer dump.rdb ``` ### 2. 转换工具 ```python # RDB转AOF示例 def rdb_to_aof(rdb_file, aof_file): with open(rdb_file, 'rb') as f: rdb = f.read() # 解析RDB parser = RdbParser(rdb) commands = parser.parse() # 生成AOF with open(aof_file, 'w') as f: for cmd in commands: f.write(cmd + '\n') ``` ## 最佳实践 1. **版本兼容** - 保持RDB版本向后兼容 - 处理版本升级时的格式变化 - 定期备份不同版本的RDB文件 2. **性能调优** - 合理配置压缩选项 - 使用增量同步机制 - 优化文件IO性能 3. **监控和维护** - 定期检查RDB文件完整性 - 监控RDB生成性能 - 及时清理过期的RDB文件 4. **安全考虑** - 加密重要数据 - 控制RDB文件访问权限 - 安全传输RDB文件 ## 总结 RDB文件格式是Redis持久化机制的核心组成部分,通过合理的二进制编码和压缩算法,实现了高效的数据存储和恢复。理解RDB文件格式和解析过程,有助于我们更好地使用Redis,优化持久化性能,确保数据可靠性。在实际应用中,需要根据具体场景选择合适的配置参数,并结合监控和维护策略,构建稳定可靠的Redis持久化方案。