本文转载自微信公众号《Redis开发运维实战》,作者傅雷。本文转载请联系Redis开发运维实战公众号。我经常遇到这样的问题:A:Redis是否启用了持久化?B:没有A:你为什么不打开它?数据丢失怎么办?数据不一致怎么办?Redis的持久化功能被夸大和误解了。这个问题我已经解释过无数次了,想写一个解释很久了。今天“忍无可忍”,我就和大家谈谈我的一些认知。欢迎投诉。一、Redis《3》持久化方式1、简单来说,RDB对Redis做一个快照(使用fork),保存到磁盘上(1)优点:结构紧凑,体积小,加载速度快(相对于AOF)可以done定期备份:比如在非高峰期(顺便说一下,数据分析也可以)(2)缺点:动作大,消耗大:全量运行会消耗磁盘、CPU、内存等,无法实现“实时”备份格式多变(Redis3456版本修改过多次)2.AOF只是简单的把Redis的每一次写操作记录到日志中,比如sethelloworld*3$3set$5hello$5world简单来说,放置磁盘的策略有3种:appendfsyncalways:每个事件周期执行一次同步操作(主线程)appendfsynceverysec:每秒执行一次同步操作(另一个线程)appendfsyncno:同步操作由操作系统控制(操作系统)(1)优势:RESP标准格式:无版本兼容实时性更高,成本更低(2)缺点:体积大:协议+明文加载慢:使用fakeclient做回放AOF重写还是大招(本文不讨论AOF重写)3、RDB-AOF混合持久化充分利用RDB优化文件,增量利用AOF保证体积、实时性和加载速度。(由Redis4提供,本文不讨论)2、AOF的性能会差多少?(注:AOF改写也是一个资源消耗大的问题,这里不讨论)1.测试环境:CPU:Intel(R)Xeon(R)Gold6248CPU@2.50GHz机械盘Redis版本:4.0.14(Redis6多线程不行已测试)压测工具:redis-benchmarkAOF策略:appendfsynceverysec2。压测方法:测试Redis在AOF“开与关”的情况下,在OPS和不同大小(64字节、128字节、512字节)的耗时(1)d=64bytescommandops(开启AOF)ops(offAOF)耗时(openAOF)耗时(offAOF)set97352121624100.00%<=0毫秒(total:5.14s)100.00%<=0毫秒(total:4.11s)get108979109241100.00%<=0毫秒(总计:4.59s)100.00%<(0毫秒总计:4.58s)incr104755113301100.00%<=0毫秒(总计:4.77s)100.00%<=0毫秒(总计:4.41s)lpush95347110889100.00%<=0毫秒(总计:5.24s)100.00%<=0毫秒(总计:4.51s)hset97770113791100.00%<=0毫秒(总计:5.11s)100.00%<=0毫秒(总计:4.39s)(2)d=128bytecommandops(OpenAOF)ops(CloseAOF)time-consuming(openAOF)time-consuming(closeAOF)set108908114077100.00%<=1毫秒100.00%<=2毫秒(总计:4.59s)100.00%<=0毫秒(总计:4.38s)得到107388111756100.00%<=1毫秒(总计:4.66s)100.00%<=0毫秒(总计:4.47s)incr105042113430%<100.000毫秒(总计:4.76秒)100.00%<=0毫秒(总计:4.41秒)lpush103114114025100.00%<=0毫秒(总计:4.85秒)100.00%<=0毫秒(总计:4.39秒)hset101440113791100.00%<=1毫秒(总计:4.93秒)100.00%<(总计秒)):4.93s)(3)d=512bytescommandops(openAOF)ops(closeAOF)time-consuming(openAOF)time-consuming(closeAOF)set9658110879099.99%<=1毫秒99.99%<=2毫秒99.99%<=3毫秒99.99%<=5毫秒100.00%<=6毫秒100.00%<=7毫秒100.00%<=8毫秒100.00%<=8毫秒(总计:5.18秒)100.00%<=1毫秒(:4.60s)得到107898105374100.00%<=0毫秒(总:4.63s)100.00%<=0毫秒(总:4.74s)incr102438107991100.00%<=0毫秒(总:4.88s)100.00%<=0毫秒4.63s)lpush9323110506499.98%<=2毫秒99.98%<=3毫秒99.99%<=4毫秒99.99%<=5毫秒99.99%<=6毫秒100.00%<=7毫秒100.00%0s<=%10<=8毫秒(总:5.36s)100.00%<=0毫秒(总:4.76s)hset96955108225100.00%<=6毫秒100.00%<=8毫秒100.00%<=9毫秒100.00%<=9百万liseconds(total:5.16s)100.00%<=0milliseconds(total:4.62s)3.总结:(注意这里不考虑AOF重写,只能更差)(1)开启AOF后,Redis写入性能读取性能下降了8~25%,读取性能没有下降(注意这里测试的是非读写混合场景)(2)开启AOF后,相关的读写性能会下降随着数据量的增加(3)启用AOF后,实际测试中发现单核CPU也会略有增加。3.一些问题的讨论?1、aof刷机策略改成always能不能不丢数据?(1)答案会丢失。当Redis执行写命令时,会往aof_buf中写入数据,但是写aof_buf和flush还是有事件时间差的。(2)原理:Redis处理命令(server.c)processCommand->call(执行命令),其中包含voidpropagate(structredisCommand*cmd,intdbid,robj**argv,intargc,intflags){//写入aof_bufif(server.aof_state!=AOF_OFF&&flags&PROPAGATE_AOF)feedAppendOnlyFile(cmd,dbid,argv,argc);...}beforesleep(ae.c)voidaeMain(aeEventLoop*eventLoop){eventLoop->stop=0;while(!eventLoop->stop){if(eventLoop->beforesleep!=NULL)eventLoop->beforesleep(eventLoop);aeProcessEvents(eventLoop,AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);}}其中beforesleep包含aof_bufdrop(server.c)voidbeforeSleep(structaeEventLoop*eventLoop){...//aofflushAppendOnlyFile(0);...}flushAppendOnlyFile利用操作系统的write和fsync(加上aof的三种策略)来完成Placement:2、Redis的一致性是什么?最终一致性。client向master写入后,并不等待slave写完。(为什么?Redis的设计目标是什么?快!)3.Redis在主节点故障后如何恢复?(1)关闭AOF:B节点提升为主节点,对外提供服务。节点A恢复后成为slave,依赖全量复制获取所有数据(2)开启AOF:同上...(除了节点A全量复制后AOF重写)所以貌似在这种模式下,对于故障恢复持久化没用!4、理论上不想丢失最少的数据,怎么办?一直开启,没有主从切换,等待A节点恢复,重新加载AOF提供服务,兄弟,这现实吗???五、最佳实践?1.RDB最好(1)自动保存:off,off,off(性能杀手)(2)保存命令:sync,算了(除非你没内存需要RDB)(3)bgsave命令:备份即可可以使用,请注意fork时间(可以查看infostats)(4)Disabled:不能使用,默认使用完整副本。2.AOF最好(1)永远不要用(主线程执行,还有IO影响)(2)everysec,按需不用,如果只想不丢数据,AOF做不到。(3)除非怕master和slave挂掉,可以考虑。不要忘记臭名昭著的AOF:异步AOF同步占用时间太长(磁盘繁忙)。在不等待fsync完成的情况下写入AOF缓冲区,这可能会降低Redis3的速度。单机多实例:你买得起吗?以一台80核500G内存的机器为例,出于成本考虑至少要部署80~90*内存(5G)的实例。这种场景下,CPU、内存、网络开销基本可以控制,但是如果开启AOF,使用普通磁盘,行不行?会有:很多公司会预留“一半”的内存做持久化,所以是40~45和:用SSD解决AOF问题。4、“异端”用法(1)RDB:定时备份(比如在非高峰期),数据分析(分析bigkey、hotkey、idlekey等)(阿里云的做法)(2)AOF原生AOF语义太weak,如果做类似binlog的功能可以修改Redis内核,用于多机房同步。6.总结Redis的持久化功能是一个重要的功能,但是如果你想期望它做到“不丢失数据”和“一致性”,可能会带来:低性能和高成本。有空整理一下Redis3~6AOF的一些变化,附上一张图:继续搬砖(现在有130万个实例..)
