大家都知道,Redis之所以性能好,读写快,是因为Redis是一个内存数据库,它的操作都几乎基于内存。但是内存型数据库有一个很大的弊端,就是当数据库进程崩溃或系统重启的时候,如果内存数据不保存的话,里面的数据就会丢失不见了。这样的数据库并不是一个可靠的数据库。
所以数据的持久化是内存型数据库的重中之重。它不仅提供数据保存硬盘的功能,还可以借此用硬盘容量扩展数据存储空间,使得Redis的可以存储超过机器本身内存大小的数据。
Redis对于数据持久化提供了两种持久化的方案,RDB与AOF。它们的原理和使用场景都大不相同,下面我们来详细地了解下。
RDB——数据快照(Snapshot)
RDB,提供一个某个时间点的数据的Snapshot,保存在RDB文件中。它可以通过SAVE/BGSAVE命令手动执行,把数据Snapshot写到RDB文件,也可以通过配置,定时执行。
Redis也可以通过加载RDB文件,把数据从磁盘加载读取到Redis中。
RDB文件创建
连上Redis,设值一些值,然后执行SAVE
命令。
然后可以查看下redis.conf的持久化工作目录。进入目录可以看到保存了一个dump.rdb
文件。该文件是一个二进制文件,无法直接正常打开。
至于SAVE/BGSAVE
的区别,就是前置是阻塞执行,此时服务不会接受请求,后者是Fork
一个子进程出来,由该进程去执行保存RDB
文件的操作,不影响用户请求。
P.S. Redis
是单进程的,所以BGSAVE
只能Fork一个子进程,而不是创建一个线程处理。
以上是手动执行的过程。但在生产我们很少会手动登上服务去执行操作,所以更多的时候是依赖Redis的配置,定时保存RDB文件。
打开redis.conf
配置文件,找到SNAPSHOTTING
的配置,Save Point
的设置。
- save 900 1 : 表示15分钟(900秒钟)内至少1个键被更改则进行快照。
- save 300 10 : 表示5分钟(300秒)内至少10个键被更改则进行快照。
- save 60 10000 :表示1分钟内至少10000个键被更改则进行快照。
这里就是 Redis 默认配置信息,可以配置多个条件(每行配置一个条件),每个条件之间是“或”的关系。
在Redis中,这个自动保存RDB的功能是默认开启的。
RDB原理
- Redis 使用 fork 函数复制一份当前进程的副本(子进程)
- 父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件。
- 当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此,一次快照操作完成。
注意事项
- Redis 在进行快照的过程中不会修改 RDB 文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候 RDB 文件都是完整的。
- 这就使得我们可以通过定时备份 RDB 文件来实现 Redis 数据库的备份, RDB 文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。
RDB优缺点
优点:
- RDB是某一时间点的快照,是一个紧凑的单文件,更多用于数据备份。可以按每小时或每日来备份,方便从不同的版本恢复数据。
- 单文件容易传输到远程服务做故障恢复。
- RDB可以Fork子进程进行持久化,使Redis可以更好地处理用户请求
- 在大量数据的情况下,RDB相比较于AOF会更快的加载。
缺点:
- 如果Redis不及时保存RDB文件,会造成数据的丢失。例如系统突然断电,但未来得及保存数据。即使你设置更多的Save point,也无法保证100%的数据不丢失。
- RDB经常需要fork子进程去执行,但如果再大量数据的情况下,这个fork操作会非常耗CPU资源的。对比AOF虽然也是fork,但是它的数据保存处理是可以控制的,不需要全量保存。
AOF——日志追加(Append-Only)
Redis的另外一种持久化方案就是AOF,Append Only File。AOF相当于一个操作的日志记录,每次对于数据的变更都会记录追加到AOF日志。当服务启动的时候就会读这些操作日志,重新执行一次操作,从而恢复原始数据。
AOF启用
AOF默认是关闭的。打开redis.conf
配置文件,找到appendonly no
改成appendonly yes
。
AOF和RDB是可以共存的,只要保存的文件名不冲突。
AOF fsync同步规则
配置文件往下拉,看到fsync
的配置。
Redis 每次更改数据的时候, aof 机制都会将命令记录到 aof 文件,但是实际上由于操作系统的缓存机制,数据并没有实时写入到硬盘,而是进入硬盘缓存。再通过硬盘缓存机制去刷新到保存到文件。
fsync()是一个系统调用函数,告诉操作系统把数据写到硬盘上,而不是缓存更多数据才写到硬盘。这样的调用可以及时保存数据到硬盘上。
Redis提供了三种fsync的调用方式
- appendfsync always,每次操作记录都同步到硬盘上,最低效,最安全。
- appendfsync everysec,每秒执行一次把操作记录同步到硬盘上。默认选项。
- appendfsync no,不执行fysnc调用,让操作系统自动操作把缓存数据写到硬盘上,不可靠,但最快。
AOF文件格式解析
开启AOF后,会再工作目录看到appendonly.aof
文件。
在客户端上执行一些命令后,打开AOF
文件,可以观察到有对应的操作的记录日志。
1 | 127.0.0.1:6379> set x 1 |
文件解析说明:
- *,表示命令的参数个数,例如
set a 1
是三个参数,所以是*3 - $,表示参数的字节数,例如
set
这个参数是三字节,所以是$3,key值a是一个字节,所以是$1 - 无符号,表示是参数的数据,例如
set
,a
,1
就是具体的数据
AOF重写
AOF虽然比RDB更可靠,但缺点也是比较明显的,就是每次写操作都要把操作日志写到文件上,这样会导致文件非常冗余。
假若你要自增一个计数器100次,如果不重写,AOF文件就就会有这100次的自增记录,如INCR a
。如果执行了日志重写,那么文件只会保留set a 100
而不是100条INCR a
。这样拥有相同的结果,但可以大大减少AOF的文件大小,并且可以让AOF载入的时候提升载入的效率。
看回redis.conf
配置,有两项控制rewrite的选项。
- auto-aof-rewrite-percentage 100,aof文件增长比例,指当前aof文件比上次重写的增长比例大小。aof重写即在aof文件在一定大小之后,重新将整个内存写到aof文件当中,以反映最新的状态(相当于bgsave)。这样就避免了,aof文件过大而实际内存数据小的问题(频繁修改数据问题).
- auto-aof-rewrite-min-size 64mb,aof文件重写最小的文件大小,即最开始aof文件必须要达到这个文件时才触发,后面的每次重写就不会根据这个变量了(根据上一次重写完成之后的大小).此变量仅初始化启动redis有效.如果是redis恢复时,则lastSize等于初始aof文件大小.
来实验一下重写的结果,我们先设定一个x值,然后自增多次,查看AOF文件内容。里面有很多INCR的语句记录
然后我们手动执行下BGREWRITEOF
,执行日志重写。
AOF 文件损坏以后如何修复
服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。
当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:
为现有的 AOF 文件创建一个备份。
使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复。
1
redis-check-aof --fix
重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。
AOF优缺点
优点:
- AOF可以设置完全不同步、每秒同步、每次操作同,默认是每秒同步。因为AOF是操作指令的追加,所以可以频繁的大量的同步。
- AOF文件是一个值追加日志的文件,即使服务宕机为写入完整的命令,也可以通过redis-check-aof工具修复这些问题。
- 如果AOF文件过大,Redis会在后台自动地重写AOF文件。重写后会使AOF文件压缩到最小所需的指令集。
- AOF文件是有序保存数据库的所有写入操作,易读,易分析。即使如果不小心误操作数据库,也很容易找出错误指令,恢复到某个数据节点。例如不小心FLUSHALL,可以非常容易恢复到执行命令之前。
缺点
- 相同数据量下,AOF的文件通常体积会比RDB大。因为AOF是存指令的,而RDB是所有指令的结果快照。但AOF在日志重写后会压缩一些空间。
- 在大量写入和载入的时候,AOF的效率会比RDB低。因为大量写入,AOF会执行更多的保存命令,载入的时候也需要大量的重执行命令来得到最后的结果。RDB对此更有优势。
如何选择
以上已经基本了解过RDB和AOF的使用、基本原理以及对应的优缺点。那么在实际当中,我们到底怎么去选择用哪种持久化方式呢?
一般来说,不考虑硬盘大小,最安全的做法是RDB与AOF同时使用,即使AOF损坏无法修复,还可以用RDB来恢复数据。
如果Redis的数据在你的服务中并不是必要的数据,例如只是当简单的缓存,没有缓存也不会造成缓存雪崩。说明数据的安全可靠性并不是首要考虑范围内,那么单独只使用RDB就可以了。
若同时启用RDB和AFO两种持久化方式,则Redis Server启动时,会加载AOF文件以重建数据集,因为AOF可以保证数据是相对最完整的。
不推荐单独使用AOF,因为AOF对于数据的恢复载入来说,比RDB慢。并且Redis官方也说明了,AOF有一个罕见的bug。出了问题无法很好的解决。所以使用AOF的时候,最好还是有RDB作为数据备份。
根据官方的意愿描述,在未来可能会有一种RDB与AOF相结合的持久化模型。到时Redis持久化就不再如此麻烦费劲了,我们拭目以待吧。
在线修改Redis
配置参数
查看当前所有配置
1 | 127.0.0.1:6379> config get * |
查看单项配置
1 | 127.0.0.1:6379> config get appendonly |
配置说明
服务器相关配置
- port :服务端绑定端口,默认6379
- bind:服务端绑定的IP地址
- timeout:当客户端闲置多少秒后自动断开连接
- slaveof
:默认为空,将本机为slave,如果设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步 - masterauth <masterpassword>:当master服务设置了密码保护时,slav服务连接master的密码
- maxclients:设置同一时间最大客户端连接数,为0代表无限制
- requirepass:设置密码,默认没有密码【操作不马上生效】
- databases:设置数据库数量,默认16个【这个只能修改配置文件来生效】
- dbfilename:指定数据库文件名,默认值为dump.rdb
- dir:指定服务端存储数据库的目录
日志相关配置
logfile:日志文件名称
loglevel:指定日志记录级别
debug 记录很多信息,用于开发和测试
varbose 有用的信息,不像 debug 会记录那么多
notice 普通的 verbose ,常用于生产环境
warning 只有非常重要或者严重的信息会记录到日志
服务端保存配置
save:指定在多长时间内,有多少次更新操作,就将数据同步到数据文件第一个jd代表1,第二个代表10,第三个代表10000。
AOF功能开启:
appendonly no:是否开启aof记录功能,指定是否在每次更新操作后进行日志记录,Redis在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为 redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为no
appendfilename:指定aof日志的文件名称
appendfsync:指定aof日志更新条件
no:表示等操作系统进行数据缓存同步到磁盘(快)
always:表示每次更新操作后手动调用fsync()将数据写到磁盘(慢,安全)
everysec:表示每秒同步一次(折衷,默认值)
在线开启aof功能
1 | 127.0.0.1:6379> config get appendonly |
开启后默认在/var/lib/redis目录就会生成appendonly.aof文件
1 | root@ops:/var/lib/redis# pwd |