当前位置: 首页 > 科技观察

吃透Redis持久化

时间:2023-03-14 21:00:10 科技观察

前言大家都知道Redis是一个内存数据库,支持两种持久化方式:RDB(Snapshot内存快照)和AOF(appendonlyfile)。持久化功能将内存中的数据同步到磁盘,避免Redis异常导致数据丢失。当Redis实例重启后,可以使用之前持久化的文件进行数据恢复。接下来本文介绍两种持久化的运行机制和优缺点。1、RDBRDB是默认的持久化方式,周期性的对内存中的数据产生快照,并按照一定的策略保存到磁盘。每次持久化快照,将内存数据完整写入磁盘一次,只有脏数据不增量同步。如果数据量大,写操作多,势必造成大量的磁盘io操作,可能会严重影响性能。1.1快照持久化过程1.2触发机制1.save命令当客户端向Redis服务器发送save命令请求进行持久化时,由于Redis使用主线程处理所有,save命令会阻塞Redis服务器处理其他客户端请求。直到数据同步完成。2.bgsave命令与save命令不同。bgsave是异步执行的。bgsave命令执行后,Redis主进程会fork一个子进程来保存rdb文件中的数据。数据同步完成后,替换原文件,然后通知主进程同步完成。3、自动触发Redis除了手动触发RDB持久化外,还有自动触发机制。savemn方法在配置中集中配置,即当数据集在m秒内有n次修改时,系统自动触发bgsave操作。#900s内至少1条写命令save9001#300s内至少10条写命令save3001060s内至少10000条写命令save6010000从节点进行全量复制操作,主节点自动执行bgsave生成RDB文件发送默认情况下,执行shutdown命令时,如果没有开启AOF持久化功能,系统会自动执行bgsave命令。当执行debugreload命令重新加载Redis时,也会自动触发save操作。1.3相关参数#当持久化rdb文件遇到问题时,主进程是否接受写入,yes表示停止写入,如果no表示redis继续提供服务。stop-writes-on-bgsave-erroryes#执行快照镜像时是否进行压缩。yes:压缩,但需要一些CPU消耗。no:不压缩,需要更多的磁盘空间。rdbcompressionyes#CRC64校验和放在文件末尾。在存储或加载rbd文件时,会有10%左右的性能下降。为了最大化性能,你可以关闭这个配置项。rdbchecksumyes#快照的文件名dbfilenamedump.rdb#存放快照的目录dir/var/lib/redis1.4RDB的优缺点优点RDB文件小,非常适合定期备份,用于容灾.因为内存数据直接存放在RDB文件中,而命令存放在AOF文件中,需要应用命令。Redis加载RDB文件的速度比AOF快得多。缺点RDB持久化方式无法实现实时/秒级持久化。实时持久化需要把内存全部刷到磁盘,代价太大。每秒fork子进程也会阻塞主进程,影响性能。RDB文件是二进制文件。由于Redis不断迭代多个版本的RDB文件,不支持跨版本兼容。旧的Redis无法识别新的RDB文件格式。2、AOFAOF(Append-onlyfile)针对RDB的缺点进行了优化。当使用AOF持久化方式时,Redis会通过Write函数将每条接收到的写操作命令追加到文件末尾,类似于MySQL的binlog。当Redis重启时,会通过重新执行保存在文件中的写命令,在内存中重建整个数据库的内容。2.1AOF持久化过程1.客户端发出bgrewriteaof命令。2.redis主进程fork子进程。3、父进程继续处理客户端请求,除了向原aof文件写入写命令。同时将接收到的写命令缓存在AOF重写缓冲区中。这样可以保证如果子进程rewrite失败,不会有问题。4.子进程根据命令合并规则将内存快照写入新的AOF文件。5.当子进程将内存快照写入临时文件时,子进程向父进程发出信号。然后父进程也将缓存的写命令写入临时文件。6、现在父进程可以用临时文件替换旧的aof文件并重命名,后面收到的写命令也会开始追加到新的aof文件中。2.2相关参数#是否开启AOF,默认关闭appendonlyyes#指定AOF文件名appendfilenameappendonly.aof#Redis支持三种写入模式:#appendfsyncalways#每次收到写入命令,强制立即写入磁盘,类似MySQL的sync_binlog=1,是最安全的。但是这种模式也是最慢的,一般不推荐。appendfsynceverysec#每秒强制写入磁盘一次,为了平衡性能和持久性,推荐使用这种方式。#appendfsyncno#完全取决于OS的写法,一般30秒左右一次,性能最好但持久性最不能保证,所以不推荐。#重写日志时,不执行命令append操作,只是放在buffer中,避免命令append对DISKIO造成冲突。#设置为yes表示rewrite时不会fsync新的写操作,暂存在内存中,rewrite完成后再写入,默认是no,yes推荐no-appendfsync-on-rewriteyes#当前AOF文件大小是上一次重写的日志当AOF文件大小翻倍时,会自动启动新的日志重写过程。auto-aof-rewrite-percentage100#当前AOF文件启动新的日志重写过程的最小值,避免Reids刚启动时因为文件小而频繁重写。auto-aof-rewrite-min-size64mb2.3日志重写AOF机制将客户端的每一次写操作追加到aof文件的末尾。比如对一个key多次执行incr和set命令,就会向aof文件写入多个命令,aof文件会越来越大,一些核心业务每天的写入量达到几十G。incrk11setk2asetk2bincrk12incrk13setk2cdelk3...incrk1100恢复Redis实例时,需要很长时间才能加载一个非常大的aof文件。为了解决这个问题,Redis支持aof文件重写——将Redis进程中的数据转换成写入命令,同步到新的AOF文件中的过程。通过重写,可以生成最小的命令集。比如上面的命令可以组合成incrk1100setk2c写入数据的规则。1、进程中的过期数据不需要写入。2.旧的AOF文件包含无效命令delk1,seta1,seta2。rewrite直接使用进程中的数据生成,aof文件保留了最新的一组命令。3.可以将多个命令合并为一个命令。为了防止单个命令导致的客户端缓冲区溢出,对于list、set、hash、zset等类型的操作,以64个元素为界拆分为多个命令。触发机制1.手动触发执行bgrewriteaof命令。2、auto-aof-rewrite-min-size根据配置自动触发,表示AOFrewrite为最小文件大小。默认64M,小于64M不会自动重写。auto-aof-rewrite-percentage表示(aof_current_size-aof_base_size)/aof_base_size的比值。aof文件重写后,当前文件大小增加多少会触发rewrite自动触发时机:aof_current_size>auto-aof-rewrite-min-size&&(aof_current_size-aof_base_size)/aof_base_size>=auto-aof-rewrite-percentage三RDBVSAOF对比具体使用哪种持久化方式,下面是官方的建议:一般情况下,如果要提供高数据安全性,建议同时使用两种持久化方式。如果你能接受因灾难造成几分钟的数据丢失,那么你可以直接使用RDB。很多用户只使用AOF,但是我们建议由于RDB可以不时对数据进行完整的快照并提供更快的重启,所以最好也使用RDB。大多数生产实例不是单点的,而是master-slave,slave也作为持久化方式来满足HA的要求。读者朋友们可以分享自己遇到的redis持久化相关的问题。最后推荐一本书,非常适合运维朋友学习。