- 浏览: 703298 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (167)
- CSS (1)
- Eclipse (4)
- English (1)
- ExtJS (1)
- Git (3)
- Grails (3)
- Groovy (2)
- Hadoop (7)
- HTML5 (2)
- JavaScript (3)
- Maven (2)
- MQ (5)
- MyBatis (3)
- NodeJS (6)
- NoSQL (4)
- Oracle (6)
- PDF (3)
- Python (9)
- Redis (17)
- Tomcat (2)
- Unix (8)
- Web Service (6)
- 安全 (1)
- 电子书 (6)
- 工具 (1)
- 其他 (21)
- 人工智能 (2)
- 视觉 (2)
- 算法 (6)
- 图表 (1)
- 网络 (13)
- 性能 (5)
- 游戏 (9)
- 字节码 (3)
- 机器学习 (0)
最新评论
-
lijunwyf:
cevin15 写道可以看下这个开源软件,https://gi ...
用markdown2html把md转换成html -
cevin15:
可以看下这个开源软件,https://github.com/c ...
用markdown2html把md转换成html -
Raina:
运行不了呢……提示错误无法加载主类Baiduwallpaper ...
用Java更换Windows桌面壁纸 -
苏城细雨沐秋风:
我把解码的jar添加到类路径后,mp3可以播放,但是flac和 ...
java播放mp3/ogg/ape/flac音乐 -
peishuai1987:
请问楼主现在怎么样了,读了很多源码吗,比如mybatis、sp ...
mybatis源码阅读心得
1. 持久化
Redis提供了两种持久化数据到硬盘的方式。
RDB:数据库里所有记录的一个快照
AOF(append only file):原汁原味地记录了每次操作命令的历史记录,相当于一个log
如果还没了解过持久化功能的话,请先阅读Redis官网上的persistence手册中文翻译版。
RDB以二进制方式存储,每条记录只记一次,文件大小更紧凑,这样恢复起来更快。但是写这个RDB需要时间,这样会造成宕机后数据丢失。
AOF以文本文件方式存储,把每条命令都记下来,会有冗余,但是写aof快,只要往文件末尾追加记录即可,可以使得宕机后可以恢复更多的数据。
接下来可以阅读Redis 设计与实现里的RDB和AOF部分。
2. RDB的save
SAVE 直接调用 rdbSave ,阻塞 Redis 主进程,直到保存完成为止。
BGSAVE 则 fork 出一个子进程,子进程调用 rdbSave ,并在保存完成之后向主进程发送信号,通知保存已完成。
2.1 redis代码核心点
我们看下BGSAVE的代码,主要关注如何fork子进程
解释一下,父进程fork出一个子进程。
子进程如果做完了,则调用_exit函数,即可通知到父进程。
如下代码则是父进程如何接收信号
以上代码便是核心关键,serverCron可以暂且理解成一个定时要执行的函数,wait3函数意思可以理解成查看一下子进程有没有完成,有了则调用backgroundSaveDoneHandler,没有的话不阻塞,继续干自己的活,过一段时间再来查看子进程是否完成。
如果看不懂,需要补习一下c的进程交互的知识(fork,wait,_exit)。
3. C语言里的fork函数
c语言:fork函数详解
3.1 写个程序进一步理解fork,wait,_exit
运行结果如下
可以看到用了wait3的话,父亲每隔2秒看一下孩子,如果没有音讯,可以做自己的事情(非阻塞的),过一会儿再来看看。
而如果把wait3改成wait的话(把代码里wait3那行注释掉,wait那行注释去掉)
运行结果如下
可以看到父亲傻傻地等待孩子的音讯(阻塞的)等了10秒,这之间他不能做别的事情。
4. RDB和AOF的格式
这一部分自己跑个实例,然后打开dump.rdb和appendonly.aof,对照网上的资料或是协议分析一下就可以了,比较枯燥,不再赘述。
5. LZF压缩
5.1 Redis里的LZF
RDB因为存的是二进制,所以可以对长的字符串做压缩。如果字符串长度大于20,并且服务器开启了LZF压缩功能,那么保存压缩之后的数据。
用到的类库是liblzf
redis把以下4个源文件原封不动的拷过来了。
lzf_c.c
lzf_d.c
lzf.h
lzfP.h
5.2 Java里的LZF
java也有lzf的类库,可参考如下网址:
https://github.com/ning/compress
https://github.com/ning/jvm-compressor-benchmark/wiki
6. CRC校验
6.1 Redis里的CRC
RDB文件的末尾8个字节是CRC校验和(循环冗余校验).
算法都在下面几个文件里
crc16.c
crc64.c
crc64.h
redis采用了crc-64-jones算法,
rio.h中的定义
如上定义了一个函数指针void (*update_cksum),
rioWrite可以理解成写rdb文件时会调用的函数,每调用一次,它就会去调用函数指针,以这样的方式来更新crc值:
r->update_cksum()
rio.c
这个函数就是简单的调用一下crc64.c里写的crc算法
rdb.c中
最后可以看到rdbSave的时候会去调用rioWrite,而最后则是写入crc校验和。
6.2 Java里的CRC
JDK里也有crc的算法实现,不过是32位的
java.util.zip.CRC32
java.util.zip.Adler32
Adler-32 校验和几乎与 CRC-32 一样可靠,但是能够更快地计算出来。
Redis提供了两种持久化数据到硬盘的方式。
RDB:数据库里所有记录的一个快照
AOF(append only file):原汁原味地记录了每次操作命令的历史记录,相当于一个log
如果还没了解过持久化功能的话,请先阅读Redis官网上的persistence手册中文翻译版。
RDB以二进制方式存储,每条记录只记一次,文件大小更紧凑,这样恢复起来更快。但是写这个RDB需要时间,这样会造成宕机后数据丢失。
AOF以文本文件方式存储,把每条命令都记下来,会有冗余,但是写aof快,只要往文件末尾追加记录即可,可以使得宕机后可以恢复更多的数据。
接下来可以阅读Redis 设计与实现里的RDB和AOF部分。
2. RDB的save
SAVE 直接调用 rdbSave ,阻塞 Redis 主进程,直到保存完成为止。
BGSAVE 则 fork 出一个子进程,子进程调用 rdbSave ,并在保存完成之后向主进程发送信号,通知保存已完成。
2.1 redis代码核心点
我们看下BGSAVE的代码,主要关注如何fork子进程
//简化以后的流程 int rdbSaveBackground(char *filename) { pid_t childpid; long long start; // 如果 BGSAVE 已经在执行,那么出错 if (server.rdb_child_pid != -1) return REDIS_ERR; // ...... if ((childpid = fork()) == 0) { int retval; /* Child */ // 执行保存操作 retval = rdbSave(filename); // ...... // 向父进程发送信号 exitFromChild((retval == REDIS_OK) ? 0 : 1); } else { /* Parent */ // 如果 fork() 出错,那么报告错误 if (childpid == -1) { return REDIS_ERR; } // 打印 BGSAVE 开始的日志 redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid); // 记录负责执行 BGSAVE 的子进程 ID server.rdb_child_pid = childpid; return REDIS_OK; } return REDIS_OK; /* unreached */ } void exitFromChild(int retcode) { _exit(retcode); //_exit调用后,会发信号给父进程 }
解释一下,父进程fork出一个子进程。
子进程如果做完了,则调用_exit函数,即可通知到父进程。
如下代码则是父进程如何接收信号
/* 处理 BGSAVE 完成时发送的信号 */ void backgroundSaveDoneHandler(int exitcode, int bysignal) { // BGSAVE 成功 if (!bysignal && exitcode == 0) { redisLog(REDIS_NOTICE, "Background saving terminated with success"); //...... } // 更新服务器状态 server.rdb_child_pid = -1; } //简化以后的流程, 这是 Redis 的时间中断器,每秒调用 server.hz 次。 int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { pid_t pid; // 接收子进程发来的信号,非阻塞 if ((pid = wait3(&statloc,WNOHANG,NULL)) != 0) { // BGSAVE 执行完毕 if (pid == server.rdb_child_pid) { backgroundSaveDoneHandler(exitcode,bysignal); // BGREWRITEAOF 执行完毕 } else if (pid == server.aof_child_pid) { backgroundRewriteDoneHandler(exitcode,bysignal); } } }
以上代码便是核心关键,serverCron可以暂且理解成一个定时要执行的函数,wait3函数意思可以理解成查看一下子进程有没有完成,有了则调用backgroundSaveDoneHandler,没有的话不阻塞,继续干自己的活,过一段时间再来查看子进程是否完成。
如果看不懂,需要补习一下c的进程交互的知识(fork,wait,_exit)。
3. C语言里的fork函数
c语言:fork函数详解
3.1 写个程序进一步理解fork,wait,_exit
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main (void) { pid_t fpid; //fpid表示fork函数返回的值 int count=0; fpid=fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am the child process, my process id is %d, parent process id is %d\n",getpid(), getppid()); printf("我是儿子\n"); fflush(stdout); count++; sleep(10); } else { printf("i am the parent process, my process id is %d, parent process id is %d\n",getpid(), getppid()); printf("我是孩子他爹\n"); fflush(stdout); count++; int statloc; pid_t pid; while (1) { if ((pid = wait3(&statloc,1,NULL)) != 0) { //if ((pid = wait(&statloc)) != 0) { printf("收到儿子 %d的信号\n",pid); fflush(stdout); break; } else { printf("还没收到儿子 的信号\n"); fflush(stdout); sleep(2); } } } printf("统计结果是: %d\n",count); fflush(stdout); return 0; }
运行结果如下
i am the child process, my process id is 4260, parent process id is 6660 我是儿子 i am the parent process, my process id is 6660, parent process id is 1 我是孩子他爹 还没收到儿子 的信号 还没收到儿子 的信号 还没收到儿子 的信号 还没收到儿子 的信号 还没收到儿子 的信号 统计结果是: 1 还没收到儿子 的信号 收到儿子 4260的信号 统计结果是: 1
可以看到用了wait3的话,父亲每隔2秒看一下孩子,如果没有音讯,可以做自己的事情(非阻塞的),过一会儿再来看看。
而如果把wait3改成wait的话(把代码里wait3那行注释掉,wait那行注释去掉)
运行结果如下
i am the child process, my process id is 10904, parent process id is 9056 我是儿子 i am the parent process, my process id is 9056, parent process id is 1 我是孩子他爹 统计结果是: 1 收到儿子 10904的信号 统计结果是: 1
可以看到父亲傻傻地等待孩子的音讯(阻塞的)等了10秒,这之间他不能做别的事情。
4. RDB和AOF的格式
这一部分自己跑个实例,然后打开dump.rdb和appendonly.aof,对照网上的资料或是协议分析一下就可以了,比较枯燥,不再赘述。
5. LZF压缩
5.1 Redis里的LZF
RDB因为存的是二进制,所以可以对长的字符串做压缩。如果字符串长度大于20,并且服务器开启了LZF压缩功能,那么保存压缩之后的数据。
用到的类库是liblzf
redis把以下4个源文件原封不动的拷过来了。
lzf_c.c
lzf_d.c
lzf.h
lzfP.h
5.2 Java里的LZF
java也有lzf的类库,可参考如下网址:
https://github.com/ning/compress
https://github.com/ning/jvm-compressor-benchmark/wiki
6. CRC校验
6.1 Redis里的CRC
RDB文件的末尾8个字节是CRC校验和(循环冗余校验).
算法都在下面几个文件里
crc16.c
crc64.c
crc64.h
redis采用了crc-64-jones算法,
rio.h中的定义
struct _rio { // 校验和计算函数,每次有写入/读取新数据时都要计算一次 void (*update_cksum)(struct _rio *, const void *buf, size_t len); // 当前校验和 uint64_t cksum; }; typedef struct _rio rio; //将 buf 中的 len 字节写入到 r 中。 static inline size_t rioWrite(rio *r, const void *buf, size_t len) { while (len) { size_t bytes_to_write = (r->max_processing_chunk && r->max_processing_chunk < len) ? r->max_processing_chunk : len; // 如果crc函数指针被赋值过,则调用它更新crc值 if (r->update_cksum) r->update_cksum(r,buf,bytes_to_write); if (r->write(r,buf,bytes_to_write) == 0) return 0; buf = (char*)buf + bytes_to_write; } return 1; }
如上定义了一个函数指针void (*update_cksum),
rioWrite可以理解成写rdb文件时会调用的函数,每调用一次,它就会去调用函数指针,以这样的方式来更新crc值:
r->update_cksum()
rio.c
/* * 通用校验和计算函数 */ void rioGenericUpdateChecksum(rio *r, const void *buf, size_t len) { r->cksum = crc64(r->cksum,buf,len); }
这个函数就是简单的调用一下crc64.c里写的crc算法
rdb.c中
int rdbSave(char *filename) { // 设置校验和函数,如果需要校验,则把函数指针赋值给rdb.update_cksum if (server.rdb_checksum) rdb.update_cksum = rioGenericUpdateChecksum; // ...... cksum = rdb.cksum; rioWrite(&rdb,&cksum,8); }
最后可以看到rdbSave的时候会去调用rioWrite,而最后则是写入crc校验和。
6.2 Java里的CRC
JDK里也有crc的算法实现,不过是32位的
java.util.zip.CRC32
java.util.zip.Adler32
Adler-32 校验和几乎与 CRC-32 一样可靠,但是能够更快地计算出来。
发表评论
-
redis官方文档中文版_Partitioning : 怎么样将你的数据分布在多个redis instance上?
2014-07-30 17:26 2215本文转载自http://skynetdoc.com/?p=11 ... -
redis源码阅读笔记(13)——事务
2014-07-22 15:40 10871. 高层视角解读 redis的 ... -
redis源码阅读笔记(12)——发布与订阅
2014-07-21 16:33 15401. 发布/订阅 发布/订阅(Publish/subscrib ... -
redis源码阅读笔记(11)——服务器与客户端
2014-07-21 16:14 20601.高层视角 可首先阅读《Redis设计与实现》中的服务器与 ... -
redis源码阅读笔记(10)——事件
2014-07-20 14:40 14581. Reactor模式 Reactor模式(反应器模式)是一 ... -
redis源码阅读笔记(8)——数据库
2014-07-18 11:27 11911. 高层视角解读 Redis设计与实现中的数据库章节 Re ... -
redis源码阅读笔记(7)——对象
2014-07-12 23:19 7020本篇我们研究redis里的对象。 1. 概述 redis有5 ... -
redis源码阅读笔记(6)——ziplist
2014-07-12 01:13 11121.高层视角解读 压缩列表(ziplist)是为了尽可能地节 ... -
redis源码阅读笔记(5)——intset
2014-07-08 16:23 7881.高层视角解读 整数集合(intset)是集合键的底层实现 ... -
redis源码阅读笔记(4)——skiplist
2014-07-08 15:08 8910.跳表基础知识 跳表(s ... -
redis源码阅读笔记(3)——dict
2014-07-08 13:26 13351.高层视角解读 字典, ... -
redis源码阅读笔记(2)——adlist
2014-07-07 15:54 1736adlist(A doubly linked list)是Re ... -
redis源码阅读笔记(1)——sds
2014-07-06 01:03 1340最近突然一时兴起,开 ... -
用spring-data-redis实现类似twitter的网站
2014-06-20 14:09 72601. spring-data-redis简介 封装了一下red ... -
jedis/nosql-unit初步
2014-06-17 16:36 11081. redis的客户端概述 redis的客户端实在太多了,比 ... -
redis初步
2014-06-16 23:19 15230. 介绍 redis是一个高性 ...
相关推荐
RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。 也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。
Redis 有两种持久化方案,RDB (Redis DataBase)和 AOF (Append Only File)。如果你想快速了解和使用RDB和AOF,可以直接跳到文章底部看总结。本章节通过配置文件,触发快照的方式,恢复数据的操作,命令操作演示...
部署安装Redis及RDB、AOF持久化验证.md
Redis持久化 - RDB和AOF
java学习-Redis的安装/连接/Redis中的五种数据累心的基本操作/Redis的持久化方案-Rdb+AOF
本文主要针对Redis 有两种持久化方案RDB和AOF做了详细的分析,希望我们整理的内容能够帮助大家对这个两种方案有更加深入的理解。 Redis 有两种持久化方案,RDB (Redis DataBase)和 AOF (Append Only File)。如果...
- RDB持久化机制: ...- AOF持久化机制: - AOF默认关闭,需要将appendonly yes手动开启 - RDB默认持久化日志文件,将每次写操作的命令持久化到本地文件中,在持久化和读取持久化文件时,相对RDB较慢
AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以 redis 协议追加保存每次写的操作到文件末尾,redis 还能对 AOF 文件进行后台重写,使得 AOF 文件的体积...
redis主从复制 RDB/AOF持久化 数据类型-附件资源
RDB是Redis内存到硬盘的快照,用于redis持久化,创建RDB二进制文件,将存储在内存中的数据,持久化的放到硬盘中,当我们需要这些数据的时候,启动载入RDB文件,数据将会被存入内存中,其实RDB就是一种快照的方式持久...
四、命令操作(redis的数据结构、高级命令),五、redis的安全性,六、redis主从复制的特点及实现过程(配置),七、redis哨兵,八、redis简单事务,九、持久化(redis的持久化机制RDB/AOF),十、redis发布与订阅...
linux搭建redis单机 数据的持久化 rdb aof 优缺点 还原优先级 rdb切换aof介绍
非阻塞,RDB-AOF混合持久化,PSYNC2.0 Redis 5 增加Stream即Redis MQ,主动碎片整理V2,集群管理器移植到C,RESP2 Redis 6 引入多线程IO,客户端缓存,权限控制,支持SSL,提升了RDB加载速度,Redis集群代理模块, ...
非阻塞,RDB-AOF混合持久化,PSYNC2.0 Redis 5 增加Stream即Redis MQ,主动碎片整理V2,集群管理器移植到C,RESP2 Redis 6 引入多线程IO,客户端缓存,权限控制,支持SSL,提升了RDB加载速度,Redis集群代理模块, ...
很全面的大数据公开课,课件+视频+代码
目录: 简介 1.1 Redis概述 1.2 Redis在Spring Boot中的应用 配置Redis依赖 2.1 添加Maven依赖 2.2 配置application.properties 编写Redis配置类 ...7.2 AOF持久化 7.3 持久化配置示例 最佳实践与注意事项
0304 AOF持久化机制. 0305 AOF数据恢复案例 0306 Redis线程模型 0307 Redis过期数据淘汰 0308 listpack 0309 碎片整理 0310 SLOWLOG 0311 Latency Monitoring 0312 SSL 0313 ACL简介 0314 ACL用户管理 0315 ACL配置...