- 浏览: 725202 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (168)
- 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)
- 机器学习 (1)
最新评论
-
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 2306本文转载自http://skynetdoc.com/?p=11 ... -
redis源码阅读笔记(13)——事务
2014-07-22 15:40 11781. 高层视角解读 redis的 ... -
redis源码阅读笔记(12)——发布与订阅
2014-07-21 16:33 16321. 发布/订阅 发布/订阅(Publish/subscrib ... -
redis源码阅读笔记(11)——服务器与客户端
2014-07-21 16:14 21591.高层视角 可首先阅读《Redis设计与实现》中的服务器与 ... -
redis源码阅读笔记(10)——事件
2014-07-20 14:40 15471. Reactor模式 Reactor模式(反应器模式)是一 ... -
redis源码阅读笔记(8)——数据库
2014-07-18 11:27 12931. 高层视角解读 Redis设计与实现中的数据库章节 Re ... -
redis源码阅读笔记(7)——对象
2014-07-12 23:19 7115本篇我们研究redis里的对象。 1. 概述 redis有5 ... -
redis源码阅读笔记(6)——ziplist
2014-07-12 01:13 12081.高层视角解读 压缩列表(ziplist)是为了尽可能地节 ... -
redis源码阅读笔记(5)——intset
2014-07-08 16:23 8781.高层视角解读 整数集合(intset)是集合键的底层实现 ... -
redis源码阅读笔记(4)——skiplist
2014-07-08 15:08 9850.跳表基础知识 跳表(s ... -
redis源码阅读笔记(3)——dict
2014-07-08 13:26 14231.高层视角解读 字典, ... -
redis源码阅读笔记(2)——adlist
2014-07-07 15:54 1823adlist(A doubly linked list)是Re ... -
redis源码阅读笔记(1)——sds
2014-07-06 01:03 1435最近突然一时兴起,开 ... -
用spring-data-redis实现类似twitter的网站
2014-06-20 14:09 73781. spring-data-redis简介 封装了一下red ... -
jedis/nosql-unit初步
2014-06-17 16:36 11961. redis的客户端概述 redis的客户端实在太多了,比 ... -
redis初步
2014-06-16 23:19 16440. 介绍 redis是一个高性 ...
相关推荐
Redis 持久化是确保数据安全的重要机制,它提供了两种主要的方法:RDB(Redis Database)和 AOF(Append Only File)。RDB 是一种快照式的持久化方式,而 AOF 则记录每次写操作的日志。 RDB 持久化在特定条件下将...
“Redis持久化 - RDB和AOF” Redis持久化是指将数据库中的数据保存到永久存储设备中,以避免数据丢失。Redis提供了两种持久化方式:RDB(快照方式)和AOF(写日志方式)。 RDB(Redis Database)是一种快照方式的...
部署安装Redis及RDB、AOF持久化验证.md
Redis还可以结合RDB和AOF两种方式,实现更灵活的持久化策略,以平衡数据安全和性能需求。 【NoSQL数据库的优势与应用场景】 NoSQL 数据库相比关系型数据库,具有以下优势: 1. 非结构化数据处理:NoSQL 支持处理...
混合持久化(RDB + AOF)混合持久化结合了RDB持久化和AOF持久化的优点,可以在保证数据安全性的同时,提供较快的数据加载速度。在这种持久化方式下,Redis会同时生成RDB文件和AOF文件。当Redis重新启动时,优先使用...
2. **持久化**:Redis提供RDB(快照)和AOF( Append Only File)两种持久化方式,确保在服务器重启后能恢复数据。RDB在指定时间间隔生成数据快照,而AOF记录所有写操作日志。 3. **主从复制**:Redis支持主从复制...
Redis的RDB和AOF持久化机制分别提供了不同的数据安全保障。RDB通过定期快照,适合对数据一致性要求不那么高的场景,而AOF则更适合需要保证数据完整性的应用。选择合适的持久化策略,需要权衡数据丢失的风险、恢复...
2. **持久化**:尽管 Redis 是一个内存数据库,但它提供了持久化机制,可以将内存中的数据保存到磁盘,防止数据丢失。 3. **支持事务**:Redis 支持简单的事务功能,可以保证操作的原子性。 4. **丰富的数据类型**:...
AOF持久化方案是指记录每一个对Redis数据库进行修改的命令到一个日志文件中,并在Redis重启时通过回放这些命令来恢复数据。AOF能够提供更高的数据安全性,可以通过配置选择不同的fsync策略,如每次写入后同步到磁盘...
**AOF持久化**则是另一种持久化策略,它记录了所有的写操作日志到一个`.aof`文件。Redis重启时会读取这些日志重新执行,从而恢复数据。AOF默认是关闭的,可以通过修改配置文件开启。AOF的优点在于可以提供更好的数据...
- `appendonly`: 是否启用AOF持久化,默认为no。 - `appendfsync`: 写入策略,默认为everysec,表示每秒同步一次。 - `auto-aof-rewrite-percentage` 和 `auto-aof-rewrite-min-size`: 控制何时自动触发AOF重写。 #...
- RDB持久化机制: ...- AOF持久化机制: - AOF默认关闭,需要将appendonly yes手动开启 - RDB默认持久化日志文件,将每次写操作的命令持久化到本地文件中,在持久化和读取持久化文件时,相对RDB较慢
为了保证数据的安全性和持久性,Redis 提供了两种主要的持久化机制:RDB 快照(Redis Database Backup)和 AOF(Append Only File)。本文将详细介绍这两种持久化方式的原理、配置方法及其各自的优缺点。 #### RDB ...
**AOF持久化**: AOF(Append Only File)记录了所有对数据库的写操作,以命令追加形式保存在日志文件中。当Redis重启时,会重新执行AOF文件中的所有命令来恢复数据。AOF有三种同步策略: 1. `always`:每次写操作...
AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以 redis 协议追加保存每次写的操作到文件末尾,redis 还能对 AOF 文件进行后台重写,使得 AOF 文件的体积...
Redis支持两种持久化方式:RDB(快照)和AOF(Append Only File)。RDB定期保存当前数据库状态到磁盘,而AOF记录所有写操作日志。可以根据需求选择合适的持久化策略,保证数据安全性。 7. 主从复制与集群: Redis...
AOF持久化的方法使得在Redis停止工作时,可以通过重新执行这些命令来恢复数据。AOF提供了比RDB更高的数据安全性,因为它可以在不中断当前写操作的情况下,以很小的数据丢失风险来持久化数据。 从上面的描述中我们...