首先,redis数据是在内存中的,这也是它快的重要原因,但是内存中的数据在断电、关机后会被擦除,所以需要复制一份到硬盘,用来做数据恢复,这个从内存复制到硬盘的过程就是其持久化(对的是‘复制’,持久化过的数据还在内存,只有被逐出或者过期才会离开内存)。

redis有AOF和RDB两种持久化方案。

AOF

只追加日志(append only file),可以设置每秒写入磁盘或者每次写操作都写入磁盘。

具体在redis.conf中配置:

#开启aof
appendonly yes

#always 每次写都刷盘,everysec每秒刷盘,no不主动刷盘,按系统配置。系统通常配置30s一次
appendfsync always

#写入文件名 可以自行设置,如果多个实例要区分开
appendfilename "appendonly.aof"

优点

服务器故障时丢失的数据较少,只有1秒内或者完全不丢失。

缺点

对性能有一定的影响,尤其是每次写操作都写入磁盘时,如果每秒写入一次又会丢失1秒内的数据。并且AOF文件会越来越大,恢复时间没有RDB快。

bgrewriteaof

redis支持bgrewriteaof,它可以以最小体积重写当前AOF文件,比如执行了set name a,set name b,set name c,set name d,set name e,aof重写时就会只写入set name e,重写时已过期的数据不会放入重写文件。

bgrewriteaof是一个bg进程,需要fork()子进程,支持linux的copy-on-write(写时复制),即在fork()出子进程后,父进程继续接受写命令,并把新的写入命令写入一份到当前AOF文件,再写入一份到aof_rewrite_buf,当新的AOF文件生成成功,就替换原有的,也就是整个过程中只有fork()这个动作是同步的,对父进程有影响,接下来就没有影响了。

aof redis 策略 redis aof配置_redis

简化版,哈

aof redis 策略 redis aof配置_redis_02

redis.conf中相关配置:

注意这里两个条件同时满足才会重写

#AOF自动重写触发文件大小
auto-aof-rewrite-min-size 128mb

#AOF文件增长率 即当新的aof文件比上次压缩后文件增加多少倍时触发重写 比如100 就是比上次重写后的文件大一倍时再次重写
auto-aof-rewrite-percentage 100

#在aof重写期间是否允许不刷盘 yes允许 no 不允许
#aof重写本身就涉及到大量刷盘操作,如果设为no,两者同时刷盘势必对性能有一定影响,但是保证绝不丢数据,如果yes允许不刷,此时redis挂了就可能丢失一部分数据,但是性能较好
no-appendfsync-on-rewrite yes

#aof出错时是否忽略它并启动,如果您有延迟问题,请将此设置为“是”。否则,从耐久性的角度来看,选择“否”是最安全的
aof-load-truncated yes

还涉及到linux的系统设置,/etc/sysctl.conf:

overcommit是linux内存分配里的概念,参考文档有详细介绍这里不详说了,这里推荐设为1,就是在内存不足时依然优先保障来申请的应用(它会根据进程点数来杀死一些正在运行的进程)

#在进行重写时内存分配策略
#默认0 内核检查是否有足够的可用内存供应用进程使用,如果有就允许;否则就申请失败
#建议设为1 内核允许分配所有的物理内存,而不管当前的内存状态如何
#还有一种设置是2 内核允许分配超过所有物理内存和交换空间总和的内存
vm.overcommit_memory 1

 AOF追加阻塞

redis会记录和对比上次刷盘时间,如果距离上次同步时间超过两秒,就会阻塞等待同步完成,这是为了避免同步任务失败后一直有新任务再来,为了保证AOF文件安全性,但是主线程阻塞在很多情况下是不允许的。

aof redis 策略 redis aof配置_redis_03

监测

info aof_delayed_fsync会记录redis阻塞次数,redis日志会记录阻塞问题,linux的top命令也可以查看硬盘状况,总之AOF追加阻塞这种情况是一定要监测和尽量避免的。

RDB

每隔指定周期,fork()出一个子进程执行bgsave,生成当前全部数据的快照文件temp-number.rdb,并在生成完成时替换掉原有rdb文件,这也是linux提供的写时复制技术(copy-on-write

aof redis 策略 redis aof配置_数据_04

具体在redis.conf中配置:

#这三种可以同时写,或者再加也可以,满足其中任何一个都会触发rdb,也可以关掉,自己定义重写方式
#每3600s有1次更改就bgsave一次
save 3600 1
#每300s有100次更改就bgsave一次          
save 300 100
#每60s有10000次更改就bgsave一次      
save 60 10000

#默认文件名 单机多个redis要分开放,二进制文件
dbfilename dump.rdb
#默认路径(这个路径是好几个文件公用的配置)
dir ./

#发生错误是否中断写
stop-writes-on-bgsave-error yes
#是否压缩 压缩对cpu性能要求更高 但是压缩后更省空间,主从间复制时也更快
rdbcompression yes
#是否做校验和
rdbchecksum yes

 其他触发RDB的机制

1.主从架构中全量复制时(当从节点增量复制失败会向主节点申请全量复制)

aof redis 策略 redis aof配置_aof redis 策略_05

优点

可以将数据恢复到指定时间点,对于灾难恢复非常有用。

结构紧凑,用它重启数据集比AOF更快。

父进程只需要fork()出一个子进程来执行快照,在备份期间父进程工作不受影响。

缺点

会丢失上次保存至今的数据。

虽然bgsave是异步的,并且数据量很大或CPU性能不佳时,fork()过程耗时增加,这会造成主进程在一段时间内暂停接受读写请求。

对比

aof redis 策略 redis aof配置_数据_06

在同时开始AOF和RDB时,redis优先加载AOF,虽然它比较慢,但是数据比较新。

方案选择

在大部分情况下,我们可以两种方式结合使用,并且配合bgrewriteaof。在集群或哨兵模式下,可以仅在从节点进行备份工作,以减少主节点的压力。

在某些时候,还可以通过手动save来进行RDB备份,它与真正的RDB相比优势在于可以指定执行时间,另外,虽然save会阻塞redis直到快照生成完毕,但是由于它不需要创建子进程并且没有子进程争抢资源,通常比bgsave快很多。

在redis只用来做缓存并且单点访问压力都不大等情况下,可以考虑不做持久化。

aof redis 策略 redis aof配置_持久化_07


 

优化 

fork()优化

aofbgrewrite、bgsave都需要执行fork(),而fork()这个动作是同步的,一旦fork()卡顿对redis性能影响很大

内存占用适当

 一般情况下,redis占用内存越大,可存储的key越多,缓存命中率越高,但是内存占用过大fork()占用时间就会增大,maxmemory要适当。

硬件保证

CPU性能低下、可用内存不足,都会影响fork()性能

内存设置保障

vm.overcommit 设为1,可以在内存不足时优先保障申请者,给redis设置较小的点数,使其被kill可能降低

频率限制

综合自己业务和硬件条件,配置适当的持久化方案,不要过于频繁。

性能监测

对硬盘、网络、内存、CPU等做监测,并且监测最近一次fork()的费时(info last_fork_usec),出现异常及时报警
 

其他优化

多节点架构

在主从架构中,可以只在从节点进行备份,分散压力。

在多主架构中,分片存储可以让每个节点存储数据降低,减少备份压力。

其他

配置生效

 设置redis.conf需要重启后才能生效,线上不能重启的情况下,在redis-cli再执行一次config set可以即时生效。

#设置
config set appendonly yes
#查看
config get appendonly

config get 有可能造成慢查询,性能要求极高的场景慎用。不过一般没啥大影响,我本机慢查询日志显示19400(微秒)。

aof redis 策略 redis aof配置_linux_08

对其他业务的影响

hash原本key达到其一维数组大小时就进行扩容,在bgsave时hash扩容会被暂停,持久化完成继续,当key达到hash一维数组5倍时会强制扩容,缩容不受持久化影响。