Redis持久化
概述
Redis是基于内存的数据库,如果出现了断电或者故障,将会导致全部数据的丢失,Redis提供了两种持久化策略。
RDB方式
RDB持久化可以手动执行
,也可以通过配置文件配置的信息定期执行
。
根据配置规则进行自动快照
Redis允许用户在配置文件中自定义配置规则
所有的条件是"或关系",例如第一条的意思是900秒内有一个或一个以上的键被更改则执行快照。
用户执行save或bgsave命令
当我们需要对服务器进行重启、备份、迁移等操作时也会需要手动进行备份操作。
save命令
save命令会使Redis同步
的执行快照操作,在进行快照的过程中会阻塞
所有客户端的请求,当备份较多数据时会导致Redis在很长一段时间中不响应。
flushall命令
只要快照的执行条件不为空,则Redis会进行一次快照操作,然后清空Redis数据库中的所有数据,如果没有快照条件则直接清空。
bgsave命令
bgsave命令还可以在后台异步
的执行快照操作,执行快照的同时,Redis还可以响应客户端的请求。
步骤:
- Redis使用fork函数复制一份当前进程的副本交给子进程(在进行fork操作时,操作系统会使用写时复制(copy_on_write)策略,在fork时子进程和主进程将会共享
同一内存数据
,当主进程需要进行更改某片诗句时,会将该片数据复制一份,保证修改时子进程的快照不受影响。写时复制策略保证了在fork时内存的占用量不会增加一倍,但是如果在快照时,客户端传来大量的更改请求也有可能导致内存溢出) - Redis继续接收并处理客户端发来的请求,子进程开始将进程的副本写入硬盘的临时文件中
- 当子进程执行完快照后,会使用临时文件将旧的RDB文件替换掉。
save和bgsave对比
save为同步进程
,bgsave为异步进程
。各有优劣,在Redis存储的数据量只有几个GB的时候,使用bgsave是没有问题的,但是随着Redis占用的内存越来越多,bgsave在创建子进程耗费的时间也会越来越长,并且和主进程抢占资源,导致Redis性能低下无法使用,此时save执行的速度将会远快于bgsave,例如可以选择写一个脚本在凌晨进行save保存,对应用程序的影响较小。
RDB方式总结
通过RDB方式持久化,一旦Redis异常退出,所丢失的就是最后一次快照后所修改的数据。RDB快照文件是经过压缩的,所以它占用的空间会小于内存中的数据大小,更有利于传输。
AOF方式
AOF方式是将Redis执行的每一条命令都追加到硬盘文件中,会稍微影响Redis的性能,使用SSD可以提高AOF的性能。
开启方式
在配置文件中设置为yes即可
实现原理
当Redis每执行一条命令时,AOF机制都会将命令追加进硬盘文件中,但是由于操作系统的缓存机制,数据并没有真正的被写到磁盘,而是进入了系统硬盘的缓冲区
中,默认情况下系统每30秒执行一次同步
操作,此时才真正将内容写入了磁盘,但是在这30秒内系统出现异常退出将会导致缓存中的数据丢失,Redis在配置文件中提供了如下策略:
- always 每个Redis写命令都要同步的写入磁盘=
- everysec 每秒执行一次同步,显式地将多个写命令同步到磁盘
- no 由操作系统默认同步
- always 方式会严重影响Redis的性能,因为它的每个写命令都需要写入硬盘,Redis处理命令的速度会受到硬盘性能的限制,转式硬盘每秒大约200个命令,固态硬盘每秒几万个命令。并且可能会影响固态硬盘的寿命(写入放大)
- everysec 是默认策略,对Redis的性能几乎没有影响,即使出现问题丢失的也是一秒内的数据。
- no 由操作系统来决定何时进行AOF同步,一般不会影响Redis的性能,但是一旦出现故障丢失的数据量是不可控的,当硬盘写入速度不够快,缓冲区被填满时,Redis会被阻塞Redis的写请求,导致Redist的处理变慢。
AOF重写
那么问题来了 如果执行了三条命令如下:
set name 1
set name 2
set name 3
Redis会将这三条命令全部写入AOF文件中,但是前两条命令都会被第三条覆盖,所以前两条是冗余命令,随着命令越来越多,AOF文件也会越来越大,而Redis中可能并没有多少数据。Redis对此问题有专门的优化机制。每达到一定条件时Redis会自动重写
AOF文件,这些条件可以在配置文件中自定义。
auto-aof-rewrite-percentage 100 表示当前的AOF文件超过上一次重写时的AOF文件大小百分之100时会再次重写 auto-aof-rewrite-min-size 64mb 限制了重写的最小AOF文件大小
AOF重写的原理:
AOF重写不需要对现有的AOF文件进行读取分析,而是直接通过读取当前数据库的数据来实现的。通俗点说就是读取了数据库的数据,生成所有set他们的命令,类似于导出sql文件。
AOF重写具体步骤:
- fork创建子进程来完成重写工作
- 类似于bgsave,主进程依然可以继续接收请求进行读写,为了让AOF重写后与当前Redis的数据
一致
,设置了一个AOF重写缓冲区
,在重写过程中的新的写请求都会复制一份到缓冲区中。 - 子进程完成了重写以后,将重写缓冲区内的数据写到新的AOF文件中。
- 新AOF文件替换掉旧的。
(图片来自:https://segmentfault.com/a/1190000016951866#articleHeader6)
AOF文件手动优化
手动执行bgrewriteaof命令进行AOF重写。
AOF重写的性能问题
AOF的重写与bgsave十分相似,都需要启动一个子线程,在AOF文件庞大时,子线程也会与主线程抢占资源,出现性能问题,所以需要进行上述的配置,用以控制AOF文件的体积大小,过于频繁的回收会影响系统性能,反之会导致AOF文件体积过大,需要在实际使用中进行调试。
RDB和AOF处理过期的键
- RDB:
- 执行save或者bgsave时,子进程会对数据库中的键进行检查,如果
已经过期就不会存入RDB文件中
。 - 启动服务器载入RDB文件时,程序会对RDB文件的键进行检查,过期的就不会被载入。
- AOF:
- 如果已经存入的键已经过期,并且还没有被定期、惰性删除,AOF文件不会对其进行处理,当过期的键被删除以后,会向AOF文件中追加一条删除的命令。
- 重写AOF文件时,子进程扫描数据库时,会忽略过期的键。
RDB与AOF应该用哪个?
Redis中他们俩不排斥,可以同时使用。如果服务器中同时开了RDB和AOF持久化,那么服务器优先使用AOF文件来还原数据。
RDB:
优点:载入时恢复数据块,备份文件体积小
缺点:在持久化后到下一次持久化之间的数据会丢失。
AOF:
优点:丢失数据较少,默认下只丢失一秒的数据
缺点:恢复数据时比较慢,文件体积大。