redis主从持久化讨论

Redis有两种持久化方式,AOF和RDB,AOF持久化是指追加写命令到aof文件的方式,RDB是指定期保存内存快照到rdb文件的方式。

 

RDB虽然可以通过bgsave指令后台保存快照,但fork()子进程是有开销的,在内存数据集较大的情况下会占用很长的cpu时间,fork新进程时,虽然可共享的数据内容不需要复制,但会复制之前进程空间的内存页表,如果内存空间有40G(考虑每个页表条目消耗 8 个字节),那么页表大小就有80M,这个复制是需要时间的,在有的服务器结点上测试,35G的数据bgsave瞬间会阻塞200ms以上,一般建议Redis使用内存不超过20g。I/O消耗,我们线上是在Slave节点开启rdb持久化,磁盘性能一般,1.2g的rdb文件持久化一分钟一次,一次大概耗时30s左右,所以rdb的频率也不能太频繁,需要根据情况做好配置。

 

AOF是追加写命令到aof文件的方式,优点是可以基本做到数据无损,缺点是文件增长较快,需要间歇性bgrewrite,bgrewrite也是一个既耗cpu又耗磁盘IO的操作,单cpu利用率最高可达100%。bgrewrite期间可以设置将新的写请求暂时缓存,bgrewrite完成后同步写盘,同步会暂时停止处理客户端请求,如果bgrewrite时间较长,缓冲区积压数据较多,核心阻塞时间会很长,所以如果必须要开启aof,一般建议找几个空闲时段设置脚本来做bgrewrite。

 

AOF还有一个比较坑的地方是刷盘策略fsync的设置,这个设置一般有3种方式:always、everysec、no,如果设置为no,就将写盘的时机交给操作系统,这在很大程度上牺牲了aof数据无损的优势,如果设置为always就意味着每条命令都会同步刷盘,会造成频繁I/O,所以一般建议是设置everysec,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。但是当这一次的fsync调用时长超过1秒时。Redis会采取延迟fsync的策略,再等一秒钟。也就是在两秒后再进行fsync,这一次的fsync就不管会执行多长时间都会进行。这时候由于在fsync时文件描述符会被阻塞,所以当前的写操作就会阻塞,因为是同步操作所以核心处理阻塞,开启aof且要求Redis性能无损对磁盘有极高要求。下图是我们一段时间内的磁盘监控截图:

 

这种间歇性的磁盘IO毛刺就会使fsync阻塞,fsync阻塞时一般会输出如下日志:


 

持久化为Redis提供了异常情况下的数据恢复机制,但开启持久化是有代价的,哪一种持久化都可能造成CPU卡顿,影响对客户端请求的处理。不开启持久化又存在风险,如果一旦误重启master节点,或者试想这样一种场景,主从切换失败,很可能因为疏忽直接重启master,这时没有开启持久化的master会把所有slave的数据清0。所以是否开启持久化,怎样开启持久化是一个难题。和运维同事探讨了一些方案,这里总结一下供大家参考:

 

1、极端情况下可以容忍全量数据丢失,那么建议master关闭持久化,slave关闭持久化;

 

2、极端情况下不能容忍全量数据丢失,但可以容忍部分数据丢失,如果内存数据集较小且不会增长建议master开启rdb,slave开启rdb;如果数据集很大,或不确定数据集增长趋势,建议master关闭持久化,slave开启rdb

开启rdb需要cpu和磁盘性能保障。如果master关闭持久化,slave开启rdb需要保证slave的rdb不会被master误重启所覆盖,这里提供几种方案:

 

  • 重启脚本包一层命令先网络请求加载备机备份目录下的rdb文件后再执行start,可以防止误重启,但备机调整部署可能需要调整脚本,主机打开持久化也需要调整脚本

  • 定时将rdb文件通过网络io传给master节点(文件大比较耗时,文件增长需要考虑定时脚本执行间隔,否则会造成持续的网络io),而且也会有一定数据损失

  • 定时备份Slave的rdb到备份目录,不做任何其他操作,误重启时人工拷贝rdb到master节点(会有一定数据损失)

 

3、最大限度需要数据无损,建议master开启aof,slave开启aof

开启aof需要cpu和磁盘性能保障。开启aof建议fsync同步刷盘使用everysec,自定义脚本在应用空闲时定时做bgrewrite,bgrewrite期间增量数据做缓冲。

 

目前大部分业务都允许部分数据丢失,为使Redis性能最大化,关闭了Master持久化,slave开启rdb,为防止误重启对rdb做了5分钟一次备份,保留最近1小时的备份文件,必要时人工copy到master数据目录下恢复数据。后续硬件性能提升后,看情况再调整持久化机制

 

tips:注意,一般是在命令行做主从,同时主关闭持久化

做主从:

redis-cli -h ip -p 6379
ip:6379>slaveof ip 6379

关闭持久化:

config set save ""

 

posted @ 2018-01-11 16:28  行知散人  阅读(2619)  评论(0编辑  收藏  举报