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

Redis是如何持久化的?这篇文章就说说RDB和AOF的对比分析

时间:2023-03-12 02:47:10 科技观察

这篇文章会介绍Redis高可用相关的机制。Redis为了实现高可用,主要有以下保障:数据持久化、主从复制、故障自动恢复、集群。在这篇文章中,我们首先介绍Redis的高可用保障基础:数据持久化。因为Redis的主从复制和自动故障恢复都需要依赖Redis持久化相关的东西。同时还可以利用Redis的数据持久化进行数据备份,保证数据安全。Redis是一个内存数据库,它的数据是存储在内存中的。如果实例宕机,所有数据都将丢失。如何保证数据的完整性和安全性,也是提高服务高可用性的重要机制之一。Redis提供了完善的持久化机制,可以将内存中的数据持久化到磁盘中,方便我们备份数据和快速恢复数据。在本文中,我们将分析Redis的数据持久化是如何实现的?我们经常听到的RDB和AOF有什么区别?以及它们不同的使用场景。持久化方式Redis提供的数据持久化方式主要有两种:RDB:生成数据快照文件AOF:实时追加命令日志文件分别对应不同的使用场景,下面我们依次分析。RDB介绍RDB的全称是RedisDatabaseBackupfile(Redis数据备份文件),也称为Redis数据快照。我们可以通过执行save或者bgsave命令让Redis在本地生成一个RDB快照文件。这个RDB文件包含了整个实例几乎完整的数据内容。它的优点是:RDB文件数据是压缩写入的,所以RDB文件的大小小于整个实例内存。实例宕机恢复时,RDB文件的加载速度非常快,可以在短时间内快速恢复。文件中数据的缺点也很明显:由于是某一时刻的数据快照,其数据并不是全部生成的。生成一个RDB文件的代价比较大,会消耗大量的CPU和内存资源。因此,RDB更适合以下场景:主从全量数据同步数据库备份对丢失数据不敏感的业务场景,实例宕机后数据快速恢复Redis主从全量数据同步使用RDB文件,我们将在后面的文章中详细讨论。由此可见,RDB非常适合做数据备份。我们可以定时让Redis生成RDB文件,然后备份快照文件。定时生成RDBRedis也提供了定时触发生成RDB文件的配置项:#Atleast1writeinthelast15minutessave9001#Atleast10writesinthelast5minutesave30010#Atleast10,000writeinthelast1minutesave6010000If满足以上任何一个条件,Redis都会自动生成一个新的RDB文件,以减少RDB数据内容和实例数据的差异。CopyOnWrite在Redis上执行save和bgsave命令生成RDB文件,但是前者是在前台执行的,也就是说在生成RDB文件时,整个实例都会被阻塞。在RDB生成之前,任何请求都不能执行。对于一个大内存的实例,生成一个RDB文件是非常耗时的,这显然是我们无法接受的。所以通常我们会选择执行bgsave让Redis在后台生成RDB文件,这样Redis仍然可以处理客户端请求而不阻塞整个实例。但是并不代表后台生成RDB是免费的。Redis利用操作系统提供的CopyOnWrite技术,在后台将内存数据的快照写入文件,也就是大家熟知的fork系统调用。fork系统调用会产生一个子进程,子进程与父进程共享相同的内存地址空间,这样子进程此时就可以拥有与父进程相同的内存数据。虽然子进程和父进程共享同一个内存地址空间,但是在fork子进程时,操作系统需要将父进程的内存页表复制给子进程。如果整个Redis实例占用的内存很大,那么它的内存页表也会很大,复制的时候会很费时。同时,这个过程会消耗大量的CPU资源。父进程也被阻塞,直到复制完成,无法处理客户端请求。fork执行后,子进程可以扫描自己所有的内存数据,然后将所有数据写入到rdb文件中。之后,父进程仍然处理客户端的请求。在处理写命令时,父进程会重新分配一块新的内存地址空间,向操作系统申请新的内存使用,不再与子进程共享。这个过程就是CopyOnWrite(写实拷贝)名称的由来。这样,父子进程的内存就会逐渐分离,父进程会申请新的内存空间,改变内存数据,而子进程的内存数据不会受到影响。由此可见,在生成RDB文件时,不仅要消耗CPU资源,还需要占用高达一倍的内存空间。我们在Redis中执行info命令,可以看到fork子进程的耗时,可以用来评估fork时间是否达到预期。同时要保证Redis机器有足够的CPU和内存资源,合理设置生成RDB的时机。AOF简介AOF的全称是AppendOnlyFile(追加日志文件)。与RDB不同的是,AOF记录了每条命令的详细信息,包括完整的命令类型、参数等,只要产生写命令,就会实时写入到AOF文件中。我们可以通过配置文件开启AOF:#开启AOFappendonlyyes#AOF文件名appendfilename"appendonly.aof"#文件刷入方式appendfsynceverysec开启AOF后,Redis会将每一次写操作命令记录到一个文件中,持久化到磁盘中,为了保证数据文件的安全,Redis还提供了flash文件的机会:appendfsyncalways:每次写入都会flash,对性能影响最大,占用磁盘IO比较高,数据安全性最高appendfsynceverysec:每秒刷新一次磁盘,对性能影响比较小。当一个节点宕机时,数据最多会丢失1秒。基于操作系统的flashing机制,可以看出AOF相对于RDB的优势在于AOF数据文件比RDB更新更及时,保存的数据更完整,从而在数据恢复时尽可能完整的恢复数据,降低数据丢失的风险。如果RDB文件和AOF文件同时存在,Redis会优先使用AOF文件进行数据恢复。但是它的缺点也很明显:随着时间的推移,AOF文件会越来越大。AOF文件刷写会增加磁盘IO的负担,可能会影响Redis的性能(开启每秒刷写时)。其中一种情况,Redis提供了AOF瘦身功能,可以设置当AOF文件较大时自动触发AOF重写。Redis会扫描整个实例的数据,重新生成一个AOF文件,达到瘦身的效果。但是这个重写过程也消耗了大量的CPU资源。#AOF文件大于上次文件增长的百分比,触发重写auto-aof-rewrite-percentage100#AOF文件的最小大小大于触发重写auto-aof-rewrite-min-size64mb,因为AOF可以最小化数据loss尽可能多的风险,所以一般适用于对数据丢失比较敏感的业务场景,比如涉及金钱交易的业务。性能影响如果将AOF刷写的时机设置为每次写入都刷写,Redis的写性能会大大降低,因为每次写命令都需要写一个文件刷写到磁盘再返回。当写入量较大时,会增加磁盘IO的负担。性能和数据安全不能同时实现。Redis虽然提供了实时刷机的机制,但在实际场景中很少使用。通常我们选择每秒刷盘的方式,这样既能保证良好的写入性能,又能在实例宕机时丢失最多1秒的数据,从而达到性能和安全的平衡。总结我们对RDB和AOF的总结如下。我们需要针对不同的业务场景选择合适的持久化方式,也可以根据RDB和AOF的优势结合使用,既保证Redis数据的安全,又兼顾其性能。