redis 的 持久化
重点: 学会如何在首先保证数据正确的前提下,加快数据操作的执行速度。
现在,让我们来看看Redis是如何将数据存储到硬盘里面,使得数据在redis重启之后仍然存在。
1. 持久化选项
Redis 提供了两种不同的持久化方法来将数据存储到硬盘里面。一种方法叫快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里面。
另一种方法叫只追加文件(append-only file AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面。这两种持久化方法既可以同时使用,又可以单独使用,在某些情况下甚至可以两种方法都不使用,具体选择那种持久化方法需要根据用户的数据以及应用来决定。
将内存中的数据存储到硬盘的一个主要原因是为了在之后重用数据,或者是为了防止系统故障而将数据备份到一个远程位置。例如:存储在redis里面的数据是经过长时间计算得出,用户会希望自己可以将这些数据存储其阿里以便以后使用,这样就不用重新计算。另一种redis应用,redis存储的数据可能是根据数十亿行日志进行聚合分析得出的结果。
两组不同的配置选项控制着redis将数据写入硬盘里面的方式。 快照持久化 save 60 1000 stop-writes-on-bgsave-error no rdbcompression yes dbfilename dump.rdb AOF 持久化 appendonly on appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb dir ./ # 共享选项,这个额选项决定了快照文件和AOF文件的保存位置。
2. 快照持久化
Redis 可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。在创建快照之后,用户可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本,还可以将快照复制到其他服务器从而创建具有相同数据的服务器副本,还可以将快照留在原地以便重启服务器时使用。
根据配置,快照将被写入dbfilename选项指定的文件里面,并存储在dir选项指定的路径上面。如果在新的快照文件创建之前,redis,系统或者硬件这三者之中的任意一个崩溃了,那么redis将丢失最近的一次创建快照之后写入的所有数据。
举个例子,假设Redis目前在内存里面存储了10GB的数据,上一个快照是在下午2:35开始创建的,并且创建成功。下午3:06redis又开始创建新的快照,并且在下午3:08快照文件创建完毕之前,有35个键进行了更新。如果在下午3:06 至 3:08期间,系统发生崩溃,导致redis无法完成新快照的创建工作,那么Redis将丢失下午2:35之后写入的所有数据.
另一方面,如果系统恰好在新的快照文件创建完毕之后崩溃,那么redis将只丢失35个键的更新数据。
创建快照的办法:
- 客户端可以通过向redis发送BGSAVE命令来创建一个快照。对于支持BGSAVE 命令的平台来说(基本上所有平台都支持,除了Windows平台),redis会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程则继续处理命令请求。
- 客户端还可以通过向redis发送save 命令来创建一个快照,接到save 命令的redis 服务器在快照创建完毕之前将不再响应任何其他命令。save 命令并不常用,我们通常只会在没有足够内存 去执行bgsave 命令的情况下,又或者即使等待持久化操作执行完毕也无所谓的情况下,才会使用这个命令。
- 如果用户设置了save 配置选项,比如save 60 10000,那么从redis最近一次创建快照之后开始算起,当 60 秒 之内有10000次写入,这个条件被满足是,redis就会自动触发 bgsave 命令。如果用户设置了多个save配置选项,那么当任意一个save配置选项所设置的条件被满足时,redis就会触发一次bgsave 命令。
- 当redis通过shutdown 命令接受到关闭命令服务器的请求时,或者接收到标准TERM信号是,会执行一个save命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在save命令执行完毕之后关闭服务器。
- 当一个redis服务器连接另一个redis服务器,并向对方发送sync命令来开始一次复制操作的时候,如果主服务器目前没有在执行bgsave 操作,或者主服务器并非刚刚执行完bgsave 操作,那么主服务器就会执行 bgsave命令。
在只使用快照持久化来保存数据时,一定要记住:如果系统真的发生崩溃,用户将丢失最近一次生成的快照之后更改的所有数据。因此,快照持久化只适用于那些机试丢失一部分数据也不会造成问题的应用程序,而不能接受这种数据损失的应用程序则可以考虑AOF持久化。
如果用户能够妥善的处理快照持久化可能带来的大量数据丢失,那么快照持久化对用户来说将是一个不错的选择,但对于很多应用程序来说,丢失15分钟,1小时甚至更长时间的数据都是不可接受的,在这种情况下,我们可以使用AOF持续化来将存储在内存里面的数据尽快地保存到硬盘里面。
3. AOF持久化
简单来说,AOF持久化会将执行的写命令写到AOF文件的末尾,以此来记录数据发生的变化。因此,redis只要从头到尾重新执行一次AOF文件包含的所有写命令,就可以恢复AOF文件所记录的数据集。AOF持久化可以通过设置代码 appendonly yes 配置打开。
appendfsync 配置选项对AOF文件的同步频率的影响。
选项 同步频率
always 每个redis写命令都要同步写入硬盘,这样做会严重降低redis的速度。
everysec 每秒执行一次同步,显式的将多个写命令同步到硬盘。
no 让操作系统来决定应该合适进行同步。
如果用户使用appendfsync always选项的话,那么每个redis写命令都会被写入硬盘,那么每个redis写命令都会被写入硬盘,从而将发生系统崩溃时出现的数据丢失减到最少。不过遗憾的是,因为这种同步策略需要对应硬盘进行大量写入,所以Redis处理命令的速度会受到硬盘性能的限制。
警告: 固态硬盘和appendfsync always 使用固态硬盘的用户请谨慎使用appendfsync always选项,因为这个选项让redis每次只写入一个命令,而不像其他appendfsync 选项那样一次写入多个命令,这种不断地写入少量数据的做法有可能会引发严重的写入放大问题,在某些情况下甚至会将固态硬盘的寿命从原来的几年降低为几个月。
为了兼顾数据安全和写入性能,用户可以考虑使用appendfsync everysec 选项,让redis以每秒一次的频率对AOF文件进行同步。redis 每秒同步一次AOF文件,Redis可以保证,即使出现系统崩溃,用户也最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,redis 还会优雅地放慢自己的速度以便适应硬盘的最大写入速度。
最后,如果用户使用appendsync no 选项,那么redis将不对AOF文件执行任何显式的同步操作,而是由操作系统来决定应该在何时对AOF文件进行同步。这个选项在一般情况下不会对redis的性能带来影响,但系统崩溃导致使用这种选项的Redis服务器丢失不定数量的数据。另外,如果用户的硬盘处理写入 操作的速度不够快的话,那么当缓冲区等待写入硬盘的数据填满是,redis的写入操作将被阻塞,并导致redis处理命令请求的速度变慢。因为这个原因,一般来说并不推荐使用appendfsync no 选项,在这里介绍它只是为了完整列举 appendfsync 选项可用的3个值。
虽然 AOF持久化非常灵活地提供了多种不同的选项来满足不同应用程序对数据安全的不同要求,但AOF持久化也有缺陷---------那就是AOF文件的体积大小。