当前位置: 首页 > Linux

Redis高可用系列深入解析:持久化AOF和RDB

时间:2023-04-06 07:09:56 Linux

欢迎关注公众号:《码农富哥》,致力于分享后端技术(高并发架构、分布式集群系统、消息队列中间件、网络、微服务、Linux、TCP/IP、HTTP、MySQL、Redis)、Python等原创干货和面试攻略!免费视频福利推荐:2T学习视频教程+免费电子书:BAT面试精讲视频、亿级流量秒杀系统、分布式系统架构、中间件消息队列、PythonGo入门精通、Java实战项目、Linux、网络、MySQL高性能、Redis集群架构、大数据、架构师速成、微服务、容器化DockerK8s、ELKStack日志系统等免费视频教程!Redis高可用概述在介绍Redis高可用之前,先解释一下Redis语境下高可用的含义。我们知道,在Web服务器中,高可用是指服务器可以正常访问的时间,衡量的是可以提供多长时间的正常服务(99.9%、99.99%、99.999%等)。但是,在Redis的语境下,高可用的含义似乎更加广泛。除了保证提供正常的服务(如主从分离、快速容灾技术)外,还需要考虑数据扩容和数据安全无损。在Redis中,实现高可用的技术主要有持久化、复制、哨兵和集群。下面分别介绍它们的作用和解决的问题。持久化:持久化是最简单的高可用方法(有时甚至不属于高可用方法)。它的主要功能是数据备份,即将数据存储在硬盘上,保证数据不会因为进程退出而丢失。复制:复制是Redis高可用的基础。哨兵和集群都是基于复制来实现高可用的。Replication主要实现数据的多机备份,以及读操作的负载均衡和简单的故障恢复。缺陷:故障恢复不能自动化;写操作不能负载均衡;存储容量受限于单机。Sentinel:基于复制,Sentinel实现了故障自动恢复。缺陷:写操作不能负载均衡;存储容量受限于单机。集群:Redis通过集群,解决了写操作无法负载均衡,存储容量受限于单机的问题,实现了比较完善的高可用解决方案。Redis持久化概述Redis的所有数据都在内存中。如果突然停机,所有数据都将丢失。因此,必须有一种机制来保证Redis的数据不会因为故障而丢失。这种机制就是Redis的持久化机制。Redis提供了两种持久化方式:RDB:按指定的时间间隔对你的数据进行快照存储。AOF:记录每一次写入服务器的操作,当服务器重启时,会重新执行这些命令,恢复原来的数据。因为AOF持久化的实时性更好,即进程意外退出时丢失的数据更少,所以AOF是目前主流的持久化方式,但是RDB持久化还是有一席之地的。下面依次介绍RDB持久化和AOF持久化;RDB持久化RDB是默认的持久化方式,会周期性的对内存中的数据产生快照,并按照一定的策略保存到磁盘中。每次持久化快照,将内存数据完整写入磁盘一次,只有脏数据不增量同步。如果数据量大,写操作多,势必造成大量的磁盘io操作,可能会严重影响性能。1、工作原理:Redis调用fork()生成子进程。子进程将数据写入临时RDB文件。当子进程写完新的RDB文件后,替换旧的RDB文件。2.触发机制RDB触发持久化分为手动触发和自动触发保存命令(手动触发)。当客户端向Redis服务器发送save命令请求进行持久化时,由于Redis使用主线程处理一切,save命令会阻塞Redis服务器处理其他客户端的请求,直到数据同步完成。保存命令将阻塞Redis服务器进程,直到创建RDB文件。在Redis服务器阻塞期间,服务器无法处理任何命令请求。因此,不建议在在线环境下使用bgsave命令(手动触发)。与save命令不同的是,bgsave是异步执行的,bgsave命令执行后,Redis主进程会fork一个子进程来保存rdb文件中的数据。数据同步完成后会替换原文件,然后通知主进程同步完成。自动触发除了手动触发RDB持久化外,Redis内部还有自动触发机制。在配置中集中配置savemn的方式是指当数据集在m秒内有n次修改时,系统会自动触发bgsave操作。3.RDB自动持久化配置#timepolicysave9001save30010save6010000#文件名dbfilenamedump.rdb#文件保存路径dir/etc/redis/data/#如果持久化出错,主进程是否应该停止写入stop-writes-on-bgsave-erroryes#是否压缩rdbcompressionyes#导入时是否校验rdbchecksumyesRDB持久化策略比较简单,下面解释一下:save9001表示如果900s内有写命令,asnapshot会被触发,可以理解为abackupsave30010表示300s内有10次写入,生成了下面的snapshot,那为什么要配置那么多规则呢?因为Redis在各个时间段的读写请求肯定是不平衡的,为了平衡性能和数据安全,我们可以自由自定义触发备份的时间。所以这里根据自身的Redis写入情况进行合理的配置。stop-writes-on-bgsave-erroryes这个配置也是一个很重要的配置。当备份进程出错时,主进程停止接受新的写操作,以保护数据的持久一致性。如果您的企业有完整的监控系统,您可以禁用此配置,否则请启用。rdbcompressionyes用于配置是否压缩RDB文件。没有必要启用它。毕竟Redis本身就是一个CPU密集型服务器。启用压缩会带来更多的CPU消耗。与硬盘的成本相比,CPU更有价值。rdbchecksumyes是否开启RDB文件校验,写文件和读文件时起作用;关闭checksum可以在写入文件和启动文件时带来10%左右的性能提升,但是数据损坏时找不到dbfilenamedump.rdbRDB文件名dir./RDB文件和AOF文件所在的目录当然,如果想要禁用RDB配置,也很简单,在save的最后一行写上:save""4.执行流程图1)Redis父进程首先判断:当前是在执行save,还是子进程bgsave/bgrewriteaof(后面会详细介绍命令),如果正在执行,bgsave命令直接返回。bgsave/bgrewriteaof的子进程不能同时执行,主要是出于性能的考虑:两个并发的子进程同时进行大量的磁盘写操作,可能会造成严重的性能问题。2)父进程执行fork操作创建子进程。在这个过程中,父进程被阻塞,Redis无法执行客户端的任何命令。3)父进程fork后,bgsave命令返回“Backgroundsavingstarted”消息,不再阻塞父进程,可以响应其他命令4)子进程创建RDB文件,根据生成临时快照文件父进程的内存快照,完成后自动替换原文件5)子进程向父进程发送信号表示完成,父进程更新统计信息5.数据恢复&Redis开始加载数据RDB文件的加载在服务器启动时自动执行,没有特殊命令。但是由于AOF具有更高的优先级,当AOF开启后,Redis会优先加载AOF文件来恢复数据;只有当AOF被禁用时,Redis服务器启动时才会检测并自动加载RDB文件。服务器在加载RDB文件时被阻塞,直到加载完成。因此,如果Redis的内存数据非常大,恢复数据的时间会很长。所以网上实践更倾向于限制单个Redis的内存。加载执行:Redis在加载RDB文件时,会对RDB文件进行校验。如果文件损坏,日志中会打印错误,Redis将无法启动。如果你对Redis高可用集群架构知识有更系统的了解,可以关注公众号【码农富豪】再回复【Redis】获取Redis高可用集群架构视频。AOF持久化RDB快照不是很可靠。如果你的电脑突然关机,或者断电,或者你不小心杀死了一个进程,你最新的数据就会丢失。AOF文件提供了更可靠的持久化方式。每当Redis接收到修改数据集的命令时,它会将命令追加到AOF文件中。当你重启Redis时,AOF中的命令会重新执行,重建数据。一、工作原理由于Redis的每条写命令都需要记录下来,所以不需要触发AOF。AOF的执行过程包括:命令追加(append):将Redis的写命令追加到缓冲区aof_buf;文件写入(write)和文件同步(sync):根据不同的同步策略将aof_buf中的内容同步到硬盘;文件重写(rewrite):定期重写AOF文件,达到压缩的目的。2.AOF持久化配置#是否开启aofappendonlyyes#文件名appendfilename"appendonly.aof"#同步方式appendfsynceverysec#aofrewrite期间同步no-appendfsync-on-rewriteno#重写触发配置auto-aof-rewrite-percentage100auto-aof-rewrite-min-size64mb#加载aof时出错怎么办aof-load-truncatedyes#文件重写策略aof-rewrite-incremental-fsyncyes3.AOF同步策略的同步步骤划分分为两步:Redis收到写命令后,会先追加到AOF缓冲区aof_buf,而不是直接写入文件系统,因为AOF缓冲区是存放在内存中的,写入速度极高,可以避免写入每次都向硬盘发出命令,导致硬盘IO成为Redis的负载瓶颈。通过调用系统函数fsync(),将AOF缓冲区中的数据真正写入磁盘进行持久化。由于数据首先存储在缓冲存储器中,如果出现断电或宕机,如果不赶到磁盘,缓冲区中的数据就会丢失。因此,我们必须有一个相对可靠的机制来保证数据被丢弃。Rediswrite命令写入磁盘的命令是通过appendfsync配置的。appendfsync的三个值代表三种磁盘放置策略:always:命令写入aof缓冲区后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。在这种情况下,每一个写命令都要同步到AOF文件中,硬盘IO成为性能瓶颈。no:命令写入aof缓冲区后调用系统写操作,不对AOF文件进行fsync同步;同步由操作系统负责,同步周期一般为30秒。在这种情况下,文件同步的时机不可控,缓冲区中会堆积大量数据,数据安全得不到保证。everysec:命令写入aof缓冲区后,调用系统写操作,写完成后线程返回;fsync同步文件操作由专用线程每秒调用一次。Everysec是上述两种策略的折衷,是性能和数据安全的平衡。因此,它是Redis的默认配置,也是我们推荐的配置。4、AOF文件重写(rewrite)随着写操作的不断增加,AOF文件会越来越大。比如你把一个计数器自增100次,最后的结果是数据集中计数器的值就是最后的自增结果,但是AOF文件会完整的记录这100次操作。其实恢复这条记录只需要一条命令,也就是说AOF文件中的100条命令其实可以缩减为一条。所以Redis支持这样一个功能:在不中断服务的情况下,在后台重建AOF文件。AOF改写过程:关于文件改写过程,有两点需要特别注意:(1)改写是由父进程fork子进程进行的;(2)Redis在重写时执行的写命令需要追加到新的AOF文件中,为此Redis引入了aof_rewrite_buf缓存。与上图相比,文件重写过程如下:1)Redis父进程首先判断当前是否有子进程在执行bgsave/bgrewriteaof。如果存在,bgrewriteaof命令直接返回。如果有bgsave命令,等待bgsave执行完成再执行。前面说了,这主要是基于性能的考虑。2)父进程执行fork操作创建子进程,父进程在此过程中被阻塞。3.1)父进程fork后,bgrewriteaof命令返回消息“Backgroundappendonlyfilerewritestarted”,不再阻塞父进程,可以响应其他命令。Redis的所有写命令仍然写入AOF缓冲区,按照appendfsync策略同步到硬盘,保证原有AOF机制的正确性。3.2)由于fork操作使用了copy-on-write技术,子进程只能共享fork操作过程中的内存数据。由于父进程还在响应命令,Redis使用AOF重写缓冲区(图中的aof_rewrite_buf)保存这部分数据,防止在生成新的AOF文件的过程中丢失这部分数据。也就是说,在执行bgrewriteaof的过程中,Redis写命令同时追加到aof_buf和aof_rewrite_buf两个缓冲区。4)子进程根据内存快照,按照命令合并规则写入新的AOF文件。5.1)子进程写入新的AOF文件后,向父进程发送信号,父进程更新统计信息,可以通过info持久化查看。5.2)父进程将AOF重写缓冲区中的数据写入新的AOF文件,从而保证新的AOF文件中保存的数据库状态与服务器当前状态一致。5.3)用新的AOF文件替换旧文件,完成AOF改写。重写触发器:手动触发器:直接调用bgrewriteaof命令,这个命令的执行有点类似于bgsave:都是fork子进程执行特定的工作,都只在fork时阻塞。自动触发:通过配置auto-aof-rewrite-percentage和auto-aof-rewrite-min-sizeauto-aof-rewrite-percentage100:Redis记住自上次重写以来AOF文件的大小(如果auto-aof-rewrite-min-sizeRedis启动后没有被重写,记住启动时使用的AOF文件的大小)。如果当前文件大小超过指定百分比的记忆大小,则会触发重写。auto-aof-rewrite-min-size64mb:同时需要设置一个最小文件大小。只有大于此值的文件才会被重写,以防文件很小但已达到百分比。禁用日志自动重写功能,我们可以将百分比设置为0:auto-aof-rewrite-percentage0:禁用日志重写功能5.数据恢复&Redis开始加载数据前面说过,当启用AOF时,当Redis启动时,会先加载AOF文件来恢复数据;只有当AOF关闭时,它才会加载RDB文件来恢复数据。当启用AOF且AOF文件存在时,Redis启动日志:持久化方案选择1.RDB和AOF的优缺点RDB和AOF各有优缺点:RDB持久化优点:RDB文件紧凑,体积小,网络传输速度快。适合全文复制;恢复速度比AOF快很多。当然,RDB相对于AOF最重要的优势之一就是对性能的影响相对较小。缺点:RDB文件的致命缺点是数据快照的持久化方式决定了无法实现实时持久化。在数据越来越重要的今天,大量的数据丢失往往是不可接受的,所以AOF持久化成为主流。另外,RDB文件需要满足特定的格式,兼容性较差(比如旧版本的Redis不兼容新版本的RDB文件)。AOF持久化对应RDB持久化。AOF的优点是支持秒级持久化,兼容性好。缺点是文件较大,恢复速度慢,对性能影响较大。2.性能与实践通过上面的分析,我们都知道RDB快照和AOF重写都需要fork,这是一个重量级的操作,会阻塞Redis。因此,为了不影响Redis主进程的响应,我们需要尽可能的减少阻塞。减少fork的频率,比如可以手动触发RDB生成快照,用AOF重写;控制Redis使用的最大内存,防止fork时间过长;使用更强大的硬件;合理配置Linux内存分配策略,避免物理问题内存不足导致fork失败。我们应该在网上做什么?我提供一些我自己的实践经验。如果Redis中的数据不是特别敏感或者可以通过其他方式改写生成数据,可以关闭持久化,丢失数据可以通过其他方式弥补;制定自己的策略,定期检查Redis的状态,然后可以手动触发备份和恢复写入数据;如果单机部署多个实例,需要防止多台机器同时运行持久化和重写操作,防止内存、CPU、IO资源竞争,持久化串行化;可以加入主从机,使用一台从机进行备份处理,其他机器正常响应客户端命令;RDB持久化和AOF持久化可以同时存在,一起使用。总结一下Redis的高可用系列:持久化已经讲完了。持久化主要有两种技术,RDB和AOF。根据上面介绍的原理和流程,大家可以根据自己具体的上网需求选择适合自己的持久化方案。另外,原创的技术文章也不容易写,需要花费大量的时间和精力。希望大家看完文章都能有所收获!您的点赞和收藏可以成为我继续输出原创文章的动力!大家也可以关注我的公众号,订阅我更多的文章哦!欢迎关注公众号:“码农富哥”,致力于分享后端技术(高并发架构、分布式集群系统、消息队列中间件、网络、微服务、Linux、TCP/IP、HTTP、MySQL、Redis)、Python等原创干货和面试攻略!关注公众号,回复【资源】免费获取2T编程视频和电子书,回复【Redis】获取Redis高可用集群架构视频