redis的持久化和缓存机制解读
作者:王啸tr1912
redis的持久化和缓存机制
说道redis,我们可能都会知道了他是一个类似缓存的一个内存数据库,我们从未感知到它的存在是因为他很快,为什么非常快,是因为他的发展到应用很快,还有他的反应速度也是非常快的。
以前文章我们讲到了缓存以及非关系型数据库的由来,这篇我们来讲讲redis这种非关系型数据库用在什么地方,以及他的特色——持久化是怎么实现的。
一、redis的适用环境
首先作为一个nosql的key—value组成的数据库,它们能存储的数据结构必须是简单的,因为有关系的数据即使存储进去之后查询也是很困难的,并且对于海量的数据存储还是关系型数据库比较合适。
举一个把一般数据库数据存储到key-value中的例子:
student | |||
学号 | 姓名 | 年龄 | 班级 |
001 | 小明 | 18 | 2 |
key | value |
student:001:姓名 | 小明 |
student:001:年龄 | 18 |
student:001:班级 | 2 |
遵从规则为
key 表名:主键值:列名value 列值
如果加上表关系的话还要复杂好几倍的。
那么什么样的数据适合存储在非关系型数据库中的呢?
1、关系不是很密切的的数据,比如用户信息,班级信息,评论数量等等。
2、量比较大的数据,如访问记录等
3、访问比较频繁的数据,如用户信息,访问数量,最新微博等
二、持久化
那么这么多,这么重要的数据都存储在内存中,如果突然断电,岂不是很糟糕,于是就有了数据的持久化机制,这个其实就是把内存中的数据存储到硬盘中,方便数据的持续存在,也可以减少断电造成的损失。
那么我们怎么持久化数据呢?多长时间进行一次持久化呢?
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 操作,可能会严重影响性能。
AOF方式
由于快照方式是在一定间隔时间做一次的,所以如果 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,性能最好,持久化没保证
aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。
例如我们调用 incr test命令 100 次,文件中必须保存全部的 100 条命令,其实有 99 条都是多余的。
因为要恢复数据库的状态其实文件中保存一条 set test 100 就够了。为了压缩 aof 的持久化文件。
redis 提供了 bgrewriteaof 命令。收到此命令 redis 将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件。
redis缓存和两种持久化机制
redis的优点第一个就是速度快它是由c语言实现的基于内存读写的效率特别高第二个优点就是单线程模型所谓的单线程就是一个每个请求都会有一个新的线程来处理请求第三个优点就是使用的是非阻塞 i/o(i/o流)
不会再网上浪费时间第四个优点就是支持多数据类型存储
两种持久化机制
rdb (Rrdis DataBase)默认的持久化方案是某个时间内的间隔执行指定次数的写操作则会将内存中的数据存入磁盘中 是以快照方式进行备份缓存
rdb的优点:
1.适合大规模的数据恢复操作
2.业务操作对数据的完整行和一致性要求不高 那么Rdb是最好的选择,
rdb的缺点:
1.就是数据的不完整行和一致性不高,可能是在最后一次备份是宕机,
2:备份时会占用内存因为redis在备份的时候会独立创建一个线程(此时的内存中有两份相同的数据);
Aof:默认不开启的持久化它的出现就是为了弥补RdB的不足(数据不一致)所以它采用的是日志的方式储存
优点:数据的完整性和一致性更高
缺点:因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。