redis持久化

持久化的意义: crash-safe

 
crash-safe:容灾能力,发生故障可以恢复
redis数据如果只存储在内存中,如果此时redis服务器宕机,则这部分数据全部丢失。
例如redis存放的是商品库存的缓存,结果redis宕机不可用,这部分数据还没写入数据库就丢失掉,出现数据不一致问题,库存没有增减,用户却下单成功或者退款成功。
如果没有持久化的话,redis遇到灾难性故障的时候,就会丢失所有的数据。如果通过持久化将数据搞一份儿在磁盘上去,然后定期比如说同步和备份到一些云存储服务上去,那么就可以保证数据不丢失全部,还是可以恢复一部分数据回来的。做到了一定的crash-safe能力
作为一个企业级的redis集群架构来说,持久化是不可减少的。
notion image

redis持久化方式

Redis 的持久化机制有两种,第一种是RDB快照,第二种是 AOF 日志。
通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说阿里云,云服务如果redis挂了,服务器上的内存和磁盘上的数据都丢了,可以从云服务上拷贝回来之前的数据,放到指定的目录中,然后重新启redis,redis就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务。
如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整。

AOF

redis AOF日志
 
 

RDB

redis的RDB快照

RDB和AOF到底该如何选择

不要仅使用RDB,因为那样会导致你丢失很多数据。
也不要仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快;
第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug
综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择;
用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复

Redis 4.0 混合持久化

Redis 4.0 为了解决这个问题,带来了一个新的持久化选项——混合持久化。
内存快照以一定的频率执行,在两次快照之间,使用 AOF 日志记录这期间的所有命令操作。
这样一来,快照不用很频繁地执行,这就避免了频繁 fork 对主线程的影响。而且,AOF日志也只用记录两次快照间的操作,也就是说,不需要记录所有操作了,因此,就不会出现文件过大的情况了,也可以避免重写开销。
如下图所示,T1 和 T2 时刻的修改,用 AOF 日志记录,等到第二次做全量快照时,就可以清空 AOF 日志,因为此时的修改都已经记录到快照中了,恢复时就不再用日志了。
内存快照和AOF混合使用
内存快照和AOF混合使用
 
 
将 rdb 文件的内容和增量的 AOF 日志文件存在一起。这里的 AOF 日志不再是全量的日志,而是自持久化开始到持久化结束的这段时间发生的增量 AOF 日志,通常这部分 AOF 日志很小。
notion image
于是在 Redis 重启的时候,可以先加载 rdb 的内容,然后再重放增量 AOF 日志就可以完全替代之前的 AOF 全量文件重放,重启效率因此大幅得到提升。
 
 

运维

快照是通过开启子进程的方式进行的,它是一个比较耗资源的操作。 1. 遍历整个内存,大块写磁盘会加重系统负载 2. AOF 的 fsync 是一个耗时的 IO 操作,它会降低 Redis 性能,同时也会增加系统 IO 负担
所以通常 Redis 的主节点是不会进行持久化操作,持久化操作主要在从节点进行。从节点是备份节点,没有来自客户端请求的压力,它的操作系统资源往往比较充沛。
但是如果出现网络分区,从节点长期连不上主节点,就会出现数据不一致的问题,特别是在网络分区出现的情况下又不小心主节点宕机了,那么数据就会丢失,所以在生产环境要做好实时监控工作,保证网络畅通或者能快速修复。另外还应该再增加一个从节点以降低网络分区的概率,只要有一个从节点数据同步正常,数据也就不会轻易丢失。
重启 Redis 时,我们很少使用 rdb 来恢复内存状态,因为会丢失大量数据。我们通常使用 AOF 日志重放,但是重放 AOF 日志性能相对 rdb 来说要慢很多,这样在 Redis 实例很大的情况下,启动需要花费很长的时间。

案例

我们使用一个 2 核 CPU、4GB 内存、500GB 磁盘的云主机运行 Redis,Redis 数据库的数据量大小差不多是 2GB,我们使用了 RDB 做持久化保证。当 时 Redis 的运行负载以修改操作为主,写读比例差不多在 8:2 左右,也就是说,如果有100 个请求,80 个请求执行的是修改操作。你觉得,在这个场景下,用 RDB 做持久化有什么风险吗?你能帮着一起分析分析吗?
  1. 内存不足的风险:
    1. Redis fork 一个 bgsave 子进程进行 RDB 写入,如果主线程再接收到写操作,就会采用写时复制。写时复制需要给写操作的数据分配新的内存空间。本问题中写的比例为 80%,那么,在持久化过程中,为了保存 80% 写操作涉及的数据,写时复制机制会在实例内存中,为这些数据再分配新内存空间,分配的内存量相当于整个实例数据量的 80%,大约是 1.6GB,这样一来,整个系统内存的使用量就接近饱和了。
      此时,如果实例还有大量的新 key 写入或 key 修改,云主机内存很快就会被吃光。如果云主机开启了Swap 机制,就会有一部分数据被换到磁盘上,当访问磁盘上的这部分数据时,性能会急剧下降。如果云主机没有开启 Swap,会直接触发 OOM,整个 Redis 实例会面临被系统kill 掉的风险。
  1. 主线程和子进程竞争使用 CPU 的风险
    1. 生成 RDB 的子进程需要 CPU 核运行,主线程本身也需要 CPU 核运行,而且,如果 Redis 还启用了后台线程,此时,主线程、子进程和后台线程都会竞争 CPU 资源。由于云主机只有 2 核 CPU,这就会影响到主线程处理请求的速度。
 
 

企业级的持久化的配置策略

在企业中,RDB的生成策略,用默认的
save 60 10000:如果你希望尽可能确保说,RDB最多丢1分钟的数据,那么尽量就是每隔1分钟都生成一个快照,低峰期,数据量很少,也没必要
10000条->生成RDB,1000条->RDB,这个根据你自己的应用和业务的数据量,你自己去决定
AOF一定要打开,fsync,everysec
auto-aof-rewrite-percentage 100 就是当前AOF大小膨胀到超过上次100%,上次的两倍
auto-aof-rewrite-min-size 64mb 根据你的数据量来定,16mb,32mb
 

企业级的数据备份方案

RDB非常适合做冷备,每次生成之后,就不会再有修改了
数据备份方案
(1)写crontab定时调度脚本去做数据备份 (2)每小时都copy一份rdb的备份,到一个目录中去,仅仅保留最近48小时的备份 (3)每天都保留一份当日的rdb的备份,到一个目录中去,仅仅保留最近1个月的备份 (4)每次copy备份的时候,都把太旧的备份给删了 (5)每天晚上将当前服务器上所有的数据备份,发送一份到远程的云服务上去
/usr/local/redis 每小时copy一次备份,删除48小时前的数据 crontab -e 0 * * * * sh /usr/local/redis/copy/redis_rdb_copy_hourly.sh redis_rdb_copy_hourly.sh
#!/bin/sh cur_date=`date +%Y%m%d%k` rm -rf /usr/local/redis/snapshotting/$cur_date mkdir /usr/local/redis/snapshotting/$cur_date cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date del_date=`date -d -48hour +%Y%m%d%k` rm -rf /usr/local/redis/snapshotting/$del_date
每天copy一次备份
crontab -e 0 0 * * * sh /usr/local/redis/copy/redis_rdb_copy_daily.sh redis_rdb_copy_daily.sh
#!/bin/sh cur_date=`date +%Y%m%d` rm -rf /usr/local/redis/snapshotting/$cur_date mkdir /usr/local/redis/snapshotting/$cur_date cp /var/redis/6379/dump.rdb /usr/local/redis/snapshotting/$cur_date del_date=`date -d -1month +%Y%m%d` rm -rf /usr/local/redis/snapshotting/$del_date
每天一次将所有数据上传一次到远程的云服务器上去

数据恢复方案

  1. 如果是redis进程挂掉,那么重启redis进程即可,直接基于AOF日志文件恢复数据,fsync everysec,最多就丢一秒的数
  1. 如果是redis进程所在机器挂掉,那么重启机器后,尝试重启redis进程,尝试直接基于AOF日志文件进行数据恢复。
    1. AOF没有破损,也是可以直接基于AOF恢复的,AOF append-only,顺序写入,如果AOF文件破损,那么用redis-check-aof fix
  1. 如果redis当前最新的AOF和RDB文件出现了丢失/损坏,那么可以尝试基于该机器上当前的某个最新的RDB数据副本进行数据恢复。
    1. 当前最新的AOF和RDB文件都出现了丢失/损坏到无法恢复,一般不是机器的故障,人为大数据系统,hadoop,有人不小心就把hadoop中存储的大量的数据文件对应的目录,rm -rf /var/redis/6379下的文件给删除了
      找到RDB最新的一份备份,小时级的备份可以了,小时级的肯定是最新的,copy到redis里面去,就可以恢复到某一个小时的数据。
  1. 如果当前机器上的所有RDB文件全部损坏,那么从远程的云服务上拉取最新的RDB快照回来恢复数据
  1. 如果是发现有重大的数据错误,比如某个小时上线的程序一下子将数据全部污染了,数据全错了,那么可以选择某个更早的时间点,对数据进行恢复