Redis数据库的持久化机制
redis是一个支持持久化的内存数据库,也就是说redis需要经常将内存中的数据同步到磁盘来保证持久化。redis支持两种持久化方式,一种是Snapshotting(快照)也是默认方式,另一种是Append-only file(缩写aof)的方式。下面分别介绍:
Snapshotting:
快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。可以通过配置设置自动做快照持久化的方式。我们可以配置redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置
save 900 1 #900秒内如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
save 60 10000
下面介绍详细的快照保存过程:
1.redis调用fork,现在有了子进程和父进程。
2. 父进程继续处理client请求,子进程负责将内存内容写入到临时文件。
由于os的实时复制机制(copy on write)父子进程会共享相同的物理页面,当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程地址空间内的数据是fork时刻整个数据库的一个快照。
3.当子进程将快照写入临时文件完毕后,用临时文件替换原来的快照文件,然后子进程退出。
client 也可以使用save或者bgsave命令通知redis做一次快照持久化。save操作是在主线程中保存快照的,由于redis是用一个主线程来处理所有client的请求,这种方式会阻塞所有client请求。所以不推荐使用。另一点需要注意的是,每次快照持久化都是将内存数据完整写入到磁盘一次,并不是增量的只同步变更数据。如果数据量大的话,而且写操作比较多,必然会引起大量的磁盘io操作,可能会严重影响性能。
下面将演示各种场景的数据库持久化情况
复制代码 代码如下:
redis 127.0.0.1:6379> set name HongWan
OK
redis 127.0.0.1:6379> get name
"HongWan"
redis 127.0.0.1:6379> shutdown
redis 127.0.0.1:6379> quit
我们先设置了一个name的键值对,然后正常关闭了数据库实例,数据是否被保存到磁盘了呢?我们来看一下服务器端是否有消息被记录下来了:
复制代码 代码如下:
[6563] 09 Aug 18:58:58 * The server is now ready to accept connections on port 6379
[6563] 09 Aug 18:58:58 - 0 clients connected (0 slaves), 539540 bytes in use
[6563] 09 Aug 18:59:02 - Accepted 127.0.0.1:58005
[6563] 09 Aug 18:59:03 - 1 clients connected (0 slaves), 547368 bytes in use
[6563] 09 Aug 18:59:08 - 1 clients connected (0 slaves), 547424 bytes in use
[6563] 09 Aug 18:59:12 # User requested shutdown...
[6563] 09 Aug 18:59:12 * Saving the final RDB snapshot before exiting.
[6563] 09 Aug 18:59:12 * DB saved on disk
[6563] 09 Aug 18:59:12 # Redis is now ready to exit, bye bye...
[root@localhost redis-2.2.12]#
从日志可以看出,数据库做了一个存盘的操作,将内存的数据写入磁盘了。正常的话,磁盘上会产生一个dump文件,用于保存数据库快照,我们来验证一下:
复制代码 代码如下:
[root@localhost redis-2.2.12]# ll
总计 188
-rw-rw-r-- 1 root root 9602 2011-07-22 00-RELEASENOTES
-rw-rw-r-- 1 root root 55 2011-07-22 BUGS
-rw-rw-r-- 1 root root 84050 2011-07-22 Changelog
drwxrwxr-x 2 root root 4096 2011-07-22 client-libraries
-rw-rw-r-- 1 root root 671 2011-07-22 CONTRIBUTING
-rw-rw-r-- 1 root root 1487 2011-07-22 COPYING
drwxrwxr-x 4 root root 4096 2011-07-22 deps
drwxrwxr-x 2 root root 4096 2011-07-22 design-documents
drwxrwxr-x 2 root root 12288 2011-07-22 doc
-rw-r--r-- 1 root root 26 08-09 18:59 dump.rdb
-rw-rw-r-- 1 root root 652 2011-07-22 INSTALL
-rw-rw-r-- 1 root root 337 2011-07-22 Makefile
-rw-rw-r-- 1 root root 1954 2011-07-22 README
-rw-rw-r-- 1 root root 19067 08-09 18:48 redis.conf
drwxrwxr-x 2 root root 4096 08-05 19:12 src
drwxrwxr-x 7 root root 4096 2011-07-22 tests
-rw-rw-r-- 1 root root 158 2011-07-22 TODO
drwxrwxr-x 2 root root 4096 2011-07-22 utils
[root@localhost redis-2.2.12]#
硬盘上已经产生了一个数据库快照了。这时侯我们再将redis启动,看键值还是否真的持久化到硬盘了。
复制代码 代码如下:
redis 127.0.0.1:6379> keys *
1) "name"
redis 127.0.0.1:6379> get name
"HongWan"
redis 127.0.0.1:6379>
数据被完全持久化到硬盘了。
另外由于快照方式是在一定间隔时间做一次的,所以如果redis意外down掉的话,就会丢失最后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用aof持久化方式。下面介绍Append-only file:
aof 比快照方式有更好的持久化性,是由于在使用aof持久化方式时,redis会将每一个收到的写命令都通过write函数追加到文件中(默认是appendonly.aof)。当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。当然由于os会在内核中缓存 write做的修改,所以可能不是立即写到磁盘上。这样aof方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉redis我们想要通过fsync函数强制os写入到磁盘的时机。有三种方式如下(默认是:每秒fsync一次)
复制代码 代码如下:
appendonly yes //启用aof持久化方式
# appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
appendfsync everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
# appendfsync no //完全依赖os,性能最好,持久化没保证
接下来我们以实例说明用法:
复制代码 代码如下:
redis 127.0.0.1:6379> set name HongWan
OK
redis 127.0.0.1:6379> set age 20
OK
redis 127.0.0.1:6379> keys *
1) "age"
2) "name"
redis 127.0.0.1:6379> shutdown
redis 127.0.0.1:6379>
我们先设置2个键值对,然后我们看一下系统中有没有产生appendonly.aof文件
复制代码 代码如下:
[root@localhost redis-2.2.12]# ll
总计 184
-rw-rw-r-- 1 root root 9602 2011-07-22 00-RELEASENOTES
-rw-r--r-- 1 root root 0 08-09 19:37 appendonly.aof
-rw-rw-r-- 1 root root 55 2011-07-22 BUGS
-rw-rw-r-- 1 root root 84050 2011-07-22 Changelog
drwxrwxr-x 2 root root 4096 2011-07-22 client-libraries
-rw-rw-r-- 1 root root 671 2011-07-22 CONTRIBUTING
-rw-rw-r-- 1 root root 1487 2011-07-22 COPYING
drwxrwxr-x 4 root root 4096 2011-07-22 deps
drwxrwxr-x 2 root root 4096 2011-07-22 design-documents
drwxrwxr-x 2 root root 12288 2011-07-22 doc
-rw-rw-r-- 1 root root 652 2011-07-22 INSTALL
-rw-rw-r-- 1 root root 337 2011-07-22 Makefile
-rw-rw-r-- 1 root root 1954 2011-07-22 README
-rw-rw-r-- 1 root root 19071 08-09 19:24 redis.conf
drwxrwxr-x 2 root root 4096 08-05 19:12 src
drwxrwxr-x 7 root root 4096 2011-07-22 tests
-rw-rw-r-- 1 root root 158 2011-07-22 TODO
drwxrwxr-x 2 root root 4096 2011-07-22 utils
[root@localhost redis-2.2.12]#
结果证明产生了,接着我们将redis再次启动后来看一下数据是否还在
复制代码 代码如下:
[root@localhost redis-2.2.12]# src/redis-cli
redis 127.0.0.1:6379> keys *
1) "age"
2) "name"
redis 127.0.0.1:6379>
数据还存在系统中,说明系统是在启动时执行了一下从磁盘到内存的load数据的过程。
aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件。redis提供了bgrewriteaof命令。收到此命令redis将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件。
具体过程如下:
(1)、redis调用fork ,现在有父子两个进程
(2)、子进程根据内存中的数据库快照,往临时文件中写入重建数据库状态的命令
(3)、父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
(4)、当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
(5)、现在父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。
需要注意到是重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。接来我们看一下实际的例子:
我们先调用5次incr age命令:
复制代码 代码如下:
redis 127.0.0.1:6379> incr age
(integer) 21
redis 127.0.0.1:6379> incr age
(integer) 22
redis 127.0.0.1:6379> incr age
(integer) 23
redis 127.0.0.1:6379> incr age
(integer) 24
redis 127.0.0.1:6379> incr age
(integer) 25
redis 127.0.0.1:6379>
接下来我们看一下日志文件的大小
复制代码 代码如下:
[root@localhost redis-2.2.12]# ll
总计 188
-rw-rw-r-- 1 root root 9602 2011-07-22 00-RELEASENOTES
-rw-r--r-- 1 root root 259 08-09 19:43 appendonly.aof
-rw-rw-r-- 1 root root 55 2011-07-22 BUGS
-rw-rw-r-- 1 root root 84050 2011-07-22 Changelog
大小为259个字节,接下来我们调用一下bgrewriteaof命令将内存中的数据重新刷到磁盘的日志文件中
复制代码 代码如下:
redis 127.0.0.1:6379> bgrewriteaof
Background append only file rewriting started
redis 127.0.0.1:6379>
再看一下磁盘上的日志文件大小
复制代码 代码如下:
[root@localhost redis-2.2.12]# ll
总计 188
-rw-rw-r-- 1 root root 9602 2011-07-22 00-RELEASENOTES
-rw-r--r-- 1 root root 127 08-09 19:45 appendonly.aof
-rw-rw-r-- 1 root root 55 2011-07-22 BUGS
-rw-rw-r-- 1 root root 84050 2011-07-22 Changelog
相关热词:
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://www.juheyunku.com/jiaob/shell/10441.shtml
相关文章
热门TAG
命令 权重 外链 企业网站 白帽 php 织梦教程 dedecms修改内容 javascript 织梦 功能 标签 调用 详解 服务器 网站流量 实例解析 Dedecms 织梦cms HTML tags标签 python jquery教程 jquery windows SEO优化 蜘蛛 搜索引擎 网站收录 JSP最新文章
-
Centos下PHP5升级为PHP7的方法
时间:2021-01-03
-
在php当中常量和变量的区
时间:2020-12-29
-
PHP中经典的四大排序算法
时间:2020-12-29
-
dw怎么运行php文件?
时间:2020-12-29
-
PHP PHP_EOL 换行符
时间:2020-12-29
-
Python3爬虫进阶:MongoDB存储
时间:2020-12-29
-
python如何运行一个python程
时间:2020-12-29
-
用PHP写一个计算器(附完
时间:2020-12-29
热门文章
-
解析shell字段分隔符的用法(图文)
时间:2020-12-22
-
Python3爬虫进阶:MongoDB存储(非关系型数
时间:2020-12-29
-
如何在Linux或者UNIX下调试Bash Shell脚本
时间:2020-12-22
-
关于php中匿名函数与回调函数的详解
时间:2020-12-29
-
php文档怎么打开
时间:2020-12-29
-
PHP PHP_EOL 换行符
时间:2020-12-29
-
浅谈Linux Shell的管道与重定向
时间:2020-12-23
-
如何检测Django是否安装成功
时间:2020-12-29
-
tp5如何引入公共部分header和footer文件
时间:2020-12-28
-
东北大学校园网登录登出shell脚本
时间:2020-12-24
