精华内容
下载资源
问答
  • RDB是Redis内存到硬盘的快照,用于redis持久化,创建RDB二进制文件,将存储在内存中的数据,持久化的放到硬盘中,当我们需要这些数据的时候,启动载入RDB文件,数据将会被存入内存中,其实RDB就是一种快照的方式持久...
  • Redis持久化RDB和AOF 为什么Redis需要持久化? 因为Redis属于内存型数据库,数据是储存在内存当中的,当遇到不可抗力因素,比如断电,那么储存在内存中的数据就会丢失。所以为了保证数据的完整性,我们需要做持久化...

    Redis持久化RDB和AOF

    为什么Redis需要持久化?
    因为Redis属于内存型数据库,数据是储存在内存当中的,当遇到不可抗力因素,比如断电,那么储存在内存中的数据就会丢失。所以为了保证数据的完整性,我们需要做持久化操作,来保证数据的完整性。

    Redis中都有哪些持久化机制?
    Redis早就考虑到了这一点,所以在Redis中,为我们准备了两种持久化的机制,RDB和AOF。
    既然Redis为我们提供了两种持久化的机制,那我们到底该选用哪个呢?其实啊,在Redis配置文件中RDB这种机制是默认开启的,而AOF机制是默认关闭的,也就是说如果你不进行配置,那么Redis就默认你使用了RDB这种持久化的机制。而当你开启AOF机制,那么Redis就会优先使用AOF持久化机制来进行数据的持久化操作。

    下面我们来了解一下什么是RDB,什么又是AOF。

    RDB(Redis Database):

    RDB是Redis用来持久化的一种机制,是把当前内存中的数据集快照写进磁盘中。

    上篇博客中提到过,在redis.conf配置文件中有一个叫做SNAPSHOTTING的配置模块,在里面我们可以看到有save 900 1 ,save 300 10 , save 60 10000。这里的save配置的是触发持久化操作的条件,save 900 1就是指在900秒内至少有一个key发生了改变,那么我就执行持久化操作,同理save 300 10 , save 60 10000也是指在300秒/60秒内有至少10/10000个key发生了改变就进行持久化操作。

    在这里插入图片描述
    当目前的数据修改达到我们配置的save条件之后,Redis就会将内存中的数据保存在dump.rdb(默认是dump.rdb,当然这个也可以在配置文件中进行更改)中。当Redis突然宕机重新启动的时候,Redis会读取dump.rdb文件中的数据加载到内存当中,很好的保证了数据的完整性。

    RDB优点:

    • RDB在执行写操作时是通过从主进程里fork的子进程进行的写入的,能够很好的保证Redis的性能不会受到太大影响。
    • 和AOF机制相比,RDB是通过dump.rdb文件来进行恢复数据的,效率更佳。

    RDB缺点:

    • 即使配置了save 1 1也有可能在1秒之内发生了突发事件导致服务崩溃,进而丢失那一秒钟的数据,适合对数据完整性要求不高的情况下开启此机制。

    AOF(Append Only File):

    Redis是默认关闭AOF机制的,他是通过记录我们操作的命令来达到数据持久化操作的目的的。
    我们可以在配置文件中把他打开appendonly yes(开启AOF机制)

    AOF会把我们执行的命令一条一条追加到文件中的,那么可想而知,随着命令越来越多,那么保存的文件就会越来越大,当文件达到我们配置的一个空间的时候,Redis就会通过BGREWRITEAOF命令来对AOF日志文件进行重写。

    auto-aof-rewrite-percentage 100  #AOF文件大小超过上次重写时文件大小的百分之几开始重写,如果之前没有写过,则根据启动时文件大小。
    auto-aof-rewrite-min-size 64mb   #允许重写的最小占用空间
    

    同步策略可以通过以下进行配置:

    appendfsync always   #当有命令执行时就同步到AOF文件中
    appendfsync everysec #每隔1秒同步一次
    appendfsync no       #不同步
    

    当AOF和RDB同时开启时Redis是如何决定使用哪种机制的呢?
    在这里插入图片描述
    Redis启动时会读取配置文件,先去检查AOF是否开启,如果开启则加载AOF文件到内存中并启动成功,若AOF没有开启,则去加载RDB文件到内存中并启动成功。

    AOF优点:

    • AOF文件通过追加的方式写入,所以不用进行内存寻址,写入效率高。
    • AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewritelog的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。

    AOF缺点:

    • 同RDB一样,当设置AOF同步策略为everysec时,最多也是每秒执行一次同步,有可能会丢失一秒的数据,但当同步策略设置为always虽然能防止数据的丢失,同时也付出了性能的代价,二则不可兼得。
    • 对于相同的数据,AOF文件比RDB文件更占用空间。
    展开全文
  • Redis持久化方案 Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,利用持久化文件实现数据...

    Redis持久化方案

    Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

    Redis提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF。

    RDB持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot),将数据库的快照(snapshot)以二进制的方式保存到磁盘中。

    AOF持久化记录服务器执行的所有更改操作命令,AOF文件中的命令全部以Redis协议的格式来保存,新命令会被追加到文件的末尾。Redis还可以在后台对AOF文件进行重写(rewrite),使得AOF文件的体积不会超出保存数据集状态所需的实际大小。

    Redis可以同时使用AOF持久化和RDB持久化。在这种情况下,当Redis重启时,它会优先使用AOF文件来还原数据集,因为AOF文件保存的数据集通常比RDB文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存在。

    了解RDB持久化和AOF持久化之间的异同是非常重要的,以下几个小节将详细地介绍这这两种持久化功能,并对它们的相同和不同之处进行说明。

    RDB快照

    下面我们说一下Redis的第一个持久化策略,RDB快照。Redis支持将当前内存数据的快照存成一个数据文件的持久化机制,而一个持续写入的数据库如何生成快照呢?Redis巧妙地借助了fork命令的写时复制(copy on write)机制,将当前进程fork出一个子进程,子进程根据内存快照,循环将数据持久化为RDB文件。

    在默认情况下, Redis将数据库快照保存在根目录下,名字为dump.rdb的二进制文件中。可通过参数dir配置指定保存目录,dbfilename指定文件名。你可以对Redis进行设置,如“save N M”,表示N秒内数据项中有M个改动时这一条件被满足时,自动保存一次数据集。比如你可以配置当10分钟以内有100次写入就生成快照,也可以配置当1分钟内有1000次写入就生成快照,支持可以多个规则一起生效,当匹配到哪个就哪个规则生效。这些规则的定义就在Redis的配置文件中,你也可以通过Redis的CONFIG SET命令在Redis运行时设置规则,不需要重启Redis。

    比如说,以下设置会让Redis在满足“60秒内有至少有1000个键被改动”这一条件时,自动保存一次数据集:

    save 60 1000
    

    你也可以通过调用SAVE或者BGSAVE,手动让Redis进行数据集保存操作。SAVE命令执行一个同步操作,以RDB文件的方式保存所有数据的快照,很少在生产环境直接使用SAVE命令,因为它会阻塞所有的客户端的请求,不要在生产环境使用,可以使用BGSAVE命令代替。BGSAVE命令执行过程中是通过fork一个子进程来完成的,所以不会阻塞客户端请求,只有fork子进程时会阻塞服务器。另外,在自动触发RDB持久化时,Redis也会选择BGSAVE而不是SAVE来进行持久化。

    Redis自动RDB持久化在其内部是通过serverCron周期性操作函数、dirty计数器、和lastsave时间戳来实现的。其中serverCron每100ms执行一次,检查服务器状态,其中就包括检查“save N M”是否满足条件,如果满足就执行BGSAVE;当然也包括AOF重写检查。dirty计数器是Redis服务器维持的一个状态,记录了上一次执行BGSAVE/SAVE命令后,服务器状态进行了多少次修改(包括增删改),而当BGSAVE/SAVE执行完成后,会将dirty重新置为0。lastsave时间戳也是Redis服务器维持的一个状态,记录的是上一次成功执行BGSAVE/SAVE的时间,当前时间减去lastsave需满足M。

    除了手动和自动以外,还有一些其他情况会触发BGSAVE:

    在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行BGSAVE命令,并将rdb文件发送给从节点。
    执行shutdown命令时,自动执行rdb持久化。
    另外需要了解的,因为其写操作是在一个新进程中进行的,当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件,这样在任何时候出现故障,Redis的RDB文件都总是可用的。

    这种持久化方式被称为快照(snapshot)。但是,我们可以很明显的看到,RDB有他的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了。在某些业务下,如果可以忍受间隔内数据丢失,我们也推荐这些业务使用RDB的方式进行持久化,因为开启RDB的代价并不高。但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,RDB就无能为力了,所以Redis引入了另一个重要的持久化机制,AOF日志方式持久化。

    为了尽可能使RDB文件体积减小,Redis默认采用LZF算法对RDB文件进行压缩。虽然压缩耗时,但是可以大大减小RDB文件的体积,因此压缩默认开启,参数为rdbcompression。需要注意的是,RDB文件的压缩并不是针对整个文件进行的,而是对数据库中的字符串进行的,且只有在字符串达到一定长度(20字节)时才会进行。

    除了压缩,你也可以检验RDB文件,通过参数rdbchecksum设置,默认为yes。在写入文件和读取文件时都起作用,关闭checksum在写入文件和启动文件时大约能带来10%的性能提升,但是数据损坏时无法发现。

    另外,当bgsave出现错误时,Redis是否停止执行写命令。Redis提供了一个参数stop-writes-on-bgsave-error,设置为yes,则当硬盘出现问题时,可以及时发现,避免数据的大量丢失;设置为no,则Redis无视bgsave的错误继续执行写命令,当对Redis服务器的系统(尤其是硬盘)使用了监控时,该选项考虑设置为no。

    说说FORK的开销?

    父进程通过fork操作可以创建子进程,第一代Unix系统实现了一种傻瓜式的进程创建:当执行fork系统调用时,内核复制父进程的整个用户空间并把复制得到的那一份分配给子进程。这种行为时非常耗时的,因为它需要完成以下几项任务:为子进程的页表分配页面、为子进程的页分配页面、初始化子进程的页表、把父进程的页复制到子进程对应的页中。

    现在Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。这种技术使地址空间上的页的拷贝被推迟到实际发生写入的时候。所以就算fork很大内存的进程,对内存的消耗和耗时都很小。

    现在虽然fork时,子进程不会复制父进程的数据空间,但是会复制内存页表(页表相当于内存的索引、目录);父进程的数据空间越大,内存页表越大,fork时复制耗时也会越多。这个问题也是导致Redis内存不宜过大的原因之一,当然还有导致故障恢复时间延长也是Redis内存不宜过大的原因。

    AOF日志

    通过上面的分析,我们知道RDB快照有大概率丢失最近写入、且仍未保存到快照中的那些数据。尽管对于某些程序来说,数据安全并不是最重要的考虑因素,但是对于那些追求数据安全的程序来说,快照功能就不太适用了。从1.1版本开始,Redis增加了一种实时性更好的持久化方式,即AOF持久化。AOF日志的全称是append only file,从名字上我们就能看出来,它是一个追加写入的日志文件。与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。

    AOF文件与MySQL数据库的binlog不同的是,AOF是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点,它记录的内容就是一个个的Redis标准命令。开启AOF持久化命令如下:

    appendonly yes
    appendfilename "appendonly.aof"
    

    从现在开始,每当Redis执行一个改变数据集的命令时(比如SET),这个命令就会被追加到AOF文件的末尾。这样的话,当Redis重新启时,程序就可以通过重新执行AOF文件中的命令来达到重建数据集的目的。

    由于需要记录Redis的每条写命令,因此AOF不需要触发,下面介绍AOF的执行流程:

    命令追加(append)

    Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。

    文件写入(write)和文件同步(sync)

    Redis提供了多种AOF缓存区的同步文件策略,策略涉及到操作系统的write函数和fsync函数,说明如下:

    为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。

    AOF缓存区的同步文件策略由参数appendfsync控制,各个值的含义如下:

    always:命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命。

    no:命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
    everysec:命令写入aof_buf后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。

    文件重写(rewrite)

    因为AOF的运作方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加,AOF文件的体积也会变得越来越大。举个例子,如果你对一个计数器调用了100次INCR,那么仅仅是为了保存这个计数器的当前值,AOF文件就需要使用100条记录(entry)。然而在实际上,只使用一条SET命令已经足以保存计数器的当前值了,其余99条记录实际上都是多余的。另外还有一些过期的数据,无效的数据也都是可以去除。

    过大的AOF文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长。为了处理这种情况,Redis支持一种有趣的特性,可以在不打断服务客户端的情况下,对AOF文件进行重建(rebuild)。执行BGREWRITEAOF命令, Redis将生成一个新的AOF文件, 这个文件包含重建当前数据集所需的最少命令。

    AOF REWRITE(重写)生成过程和RDB快照类似,都巧妙地利用了写时复制机制。同样也是fork一个子进程(此时主线程是阻塞的),子进程根据内存快照,按照命令合并规则写入到新的AOF文件。当主进程fork完子线程后继续接受请求,所有写命令依然写入AOF缓冲区(aof_buf),并根据appendfsync策略同步到硬盘,保证原有AOF机制的正确。但由于fork操作使用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然在响应命令,因此Redis使用AOF重写缓冲区(aof_rewrite_buf)保存这部分新日志,防止新AOF文件生成期间丢失这部分数据。也就是说,bgrewriteaof执行期间,Redis的写命令同时追加到aof_buf和aof_rewirte_buf两个缓冲区。

    当子进程写完新的AOF文件后,向父进程发信号,父进程更新统计信息,具体可以通过info persistence查看。然后父进程把AOF重写缓冲区的数据写入到新的AOF文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致。然后调用原子性的rename命令用新的AOF文件取代老的AOF文件,完成AOF重写。

    这里需要注意,因为由主进程把aof_rewrite_buf缓存追加到新日志文件。主进程追加日志时,不会处理其他请求,如果aof_rewrite_buf特别大,例如几百M,也可能造成Redis几秒甚至几十秒不响应。

    从上面的流程我们能够看到,RDB和AOF操作都是顺序IO操作,性能都很高。而在通过RDB文件或者AOF日志进行数据库恢复的时候,也是顺序的读取数据加载到内存中。所以也不会造成磁盘的随机读。

    文件重写的触发,分为手动触发和自动触发:

    手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。

    自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数,以及aof_current_size和aof_base_size状态确定触发时机。

    auto-aof-rewrite-min-size表示执行AOF重写时,文件的最小体积,默认值为64MB。

    auto-aof-rewrite-percentage表示执行AOF重写时,当前AOF大小(即aof_current_size)和上一次重写时AOF大小(aof_base_size)的比值,即增长比例达到设定值。

    只有当auto-aof-rewrite-min-size和auto-aof-rewrite-percentage两个参数同时满足时,才会自动触发AOF重写,即bgrewriteaof操作。

    其中,参数可以通过config get命令查看:

    127.0.0.1:6391> CONFIG GET auto-aof-rewrite-min-size
    1) "auto-aof-rewrite-min-size"
    2) "64000000"
    127.0.0.1:6391> CONFIG GET auto-aof-rewrite-percentage
    1) "auto-aof-rewrite-percentage"
    2) "100"
    

    状态可以通过info persistence查看:

    127.0.0.1:6379> info persistence
    # Persistence
    aof_enabled:1
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:0
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_current_size:40876638
    aof_base_size:2217565
    aof_pending_rewrite:0
    aof_buffer_length:0
    aof_rewrite_buffer_length:0
    aof_pending_bio_fsync:0
    aof_delayed_fsync:0
    

    另外在aof rewrite过程中,是否采取增量”文件同步”策略,由参数aof-rewrite-incremental-fsync控制,默认为”yes”,而且必须为yes。rewrite过程中,每32M数据进行一次文件同步,这样可以减少”aof大文件”写入对磁盘的操作次数。

    bgrewriteaof机制,在一个子进程中进行aof的重写,从而不阻塞主进程对其余命令的处理,同时解决了aof文件过大问题。现在问题出现了,同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。

    如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候Redis挂掉,就会丢失数据。丢失多少数据呢?在Linux的操作系统的默认设置下,最多会丢失30s的数据。因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为yes。如果应用系统无法忍受数据丢失,则设置为no。

    AOF刷新策略?

    前面提到过,在AOF中,如果AOF缓冲区的文件同步策略为everysec,则:在主线程中,命令写入aof_buf后调用系统write操作,write完成后主线程返回;fsync同步文件操作由专门的文件同步线程每秒调用一次。这种做法的问题在于,如果硬盘负载过高,那么fsync操作可能会超过1s;如果Redis主线程持续高速向aof_buf写入命令,硬盘的负载可能会越来越大,IO资源消耗更快;如果此时Redis进程异常退出,丢失的数据也会越来越多,可能远超过1s。

    为此,Redis的处理策略是这样的:主线程每次进行AOF会对比上次fsync成功的时间;如果距上次不到2s(也就是延迟了1s),主线程直接返回;如果超过2s,则主线程阻塞直到上一次fsync同步完成。因此,如果系统硬盘负载过大导致fsync速度太慢,会导致Redis主线程的阻塞;此外,使用everysec配置,AOF最多可能丢失2s的数据,而不是1s。具体看Redis AOF刷新策略分析

    AOF追加阻塞问题定位的方法,监控info Persistence中的aof_delayed_fsync,当AOF追加阻塞发生时(即主线程等待fsync而阻塞),该指标累加。另外,AOF阻塞时的Redis日志:Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.

    如果AOF追加阻塞频繁发生,说明系统的硬盘负载太大;可以考虑更换IO速度更快的硬盘,或者通过IO监控分析工具对系统的IO负载进行分析。

    对于pipelining有什么不同?

    对于pipelining的操作,其具体过程是客户端一次性发送N个命令,然后等待这N个命令的返回结果被一起返回。通过采用pipilining就意味着放弃了对每一个命令的返回值确认。由于在这种情况下,N个命令是在同一个执行过程中执行的。所以当设置appendfsync为everysec时,可能会有一些偏差,因为这N个命令可能执行时间超过1秒甚至2秒。但是可以保证的是,最长时间不会超过这N个命令的执行时间和。

    如果AOF文件出错了,怎么办?

    服务器可能在程序正在对AOF文件进行写入时停机,如果停机造成了 AOF 文件出错(corrupt),那么Redis在重启时会拒绝载入这个AOF文件, 从而确保数据的一致性不会被破坏。当发生这种情况时,可以用以下方法来修复出错的 AOF 文件:为现有的AOF文件创建一个备份。然后使用Redis附带的redis-check-aof --fix程序对原来的AOF文件进行修复。

    然后可选使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。再次重启Redis服务器,等待服务器载入修复后的AOF文件,并进行数据恢复。

    但如果是AOF文件结尾不完整(机器突然宕机等容易导致文件尾部不完整),且aof-load-truncated参数开启,则日志中会输出警告,Redis忽略掉AOF文件的尾部,启动成功。aof-load-truncated参数默认是开启的。

    RDB和AOF优缺点

    RDB的优点?

    RDB是一个非常紧凑(compact)的文件,体积小,网络传输快,它保存了Redis在某个时间点上的数据集。这种文件非常适合用于进行备份,恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。

    RDB的缺点?

    RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。

    AOF的优点?

    与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好。你可以设置不同的fsync策略,比如无fsync,每秒钟一次fsync,或者每次执行写入命令时fsync。AOF的默认策略为每秒钟fsync一次,在这种配置下,Redis仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据。AOF文件是一个只进行追加操作的日志文件(append only log),因此对AOF文件的写入不需要进行seek(查找),即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。

    Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写: 重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。 而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。导出(export)AOF文件也非常简单: 举个例子, 如果你不小心执行了FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除AOF文件末尾的FLUSHALL命令,并重启 Redis, 就可以将数据集恢复到FLUSHALL执行之前的状态。

    AOF的缺点?

    AOF文件的体积通常要大于RDB文件的体积、且恢复速度慢。对于相同的数据集来说,根据所使用的fsync策略,AOF的速度可能会慢于RDB。在一般情况下,每秒fsync的性能依然非常高,而关闭fsync可以让AOF的速度和RDB一样快。另外,AOF在过去曾经发生过这样的bug,因为个别命令的原因,导致AOF文件在重新载入时,无法将数据集恢复成保存时的原样。虽然这种bug在AOF文件中并不常见,但是对比来说,RDB几乎是不可能出现这种bug的。

    RDB和AOF,我应该用哪一个?

    首先要明白无论是RDB还是AOF,持久化的开启都是要付出性能方面代价的:对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力。但如果业务能容忍几分钟到10几分钟的数据丢失(且不使用备库),RDB是一个不错的选择;不然,就选择AOF。

    对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO压力更大,甚至可能造成AOF追加阻塞问题(后面会详细介绍这种阻塞),此外,AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的IO压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对Redis主进程性能的影响会更大。

    在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用RDB或AOF的一种,或同时开启RDB和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机master和从机slave可以独立的选择持久化方案。比如完全关闭master持久化(包括RDB和AOF),这样可以让master的性能达到最好;而slave可以只开启AOF。但这种情况下,如果master服务因为故障宕掉了,如果系统中有自动拉起机制(即检测到服务停止后重启该服务)将master自动重启,由于没有持久化文件,那么master重启后数据是空的,slave同步数据也变成了空的,意味着数据丢失。所以尽量避免这种情况出现。

    RDB和AOF之间的相互作用?

    在版本号大于等于2.4的Redis中,BGSAVE执行的过程中,不可以执行BGREWRITEAOF。反过来说,在BGREWRITEAOF执行的过程中,也不可以执行BGSAVE。这可以防止两个Redis后台进程同时对磁盘进行大量的I/O操作。

    如果BGSAVE正在执行,并且用户显示地调用BGREWRITEAOF命令,那么服务器将向用户回复一个OK状态,并告知用户,BGREWRITEAOF已经被预定执行: 一旦BGSAVE执行完毕,BGREWRITEAOF就会正式开始。当Redis启动时,如果RDB持久化和AOF持久化都被打开了,那么程序会优先使用AOF文件来恢复数据集,因为AOF文件所保存的数据通常是最完整的。

    RDB和AOF数据导入

    这些持久化的数据有什么用,当然是用于重启后的数据恢复。Redis是一个内存数据库,无论是RDB还是AOF,都只是其保证数据恢复的措施。所以Redis在利用RDB或AOF进行恢复的时候,会读取RDB或AOF文件,重新加载到内存中。相对于MySQL等数据库的启动时间来说,会长很多,因为MySQL本来是不需要将数据加载到内存中的。

    但是相对来说,MySQL启动后提供服务时,其被访问的热数据也会慢慢加载到内存中,通常我们称之为预热,而在预热完成前,其性能都不会太高。而Redis的好处是一次性将数据加载到内存中,一次性预热。这样只要Redis启动完成,那么其提供服务的速度都是非常快的。

    而在利用RDB和利用AOF启动上,其启动时间有一些差别。RDB的启动时间会更短,原因有两个,一是RDB文件中每一条数据只有一条记录,不会像AOF日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。另一个原因是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不需要再进行数据编码工作。在CPU消耗上要远小于AOF日志的加载。

    注意:当redis启动时,如果rdb持久化和aof持久化都打开了,那么程序会优先使用aof方式来恢复数据集,因为aof方式所保存的数据通常是最完整的。如果aof文件丢失了,则启动之后数据库内容为空。

    注意:如果想把正在运行的redis数据库,从RDB切换到AOF,建议先使用动态切换方式,再修改配置文件,重启数据库。(不能直接修改配置文件,重启数据库,否则数据库中数据就为空了。)
    在Redis 2.2或以上版本,可以在不重启的情况下,从RDB切换到AOF :

    为最新的dump.rdb文件创建一个备份,将备份放到一个安全的地方。执行以下两条命令:

    127.0.0.1:6379> CONFIG SET dir /apps/redis/data/redis-8836
    127.0.0.1:6379> CONFIG SET appendonly yes
    127.0.0.1:6379> CONFIG SET save ""
    

    确保命令执行之后,数据库的键的数量没有改变。确保写命令会被正确地追加到 AOF 文件的末尾。

    步骤2是开启了AOF功能,Redis会阻塞直到初始AOF文件创建完成为止,之后Redis会继续处理命令请求,并开始将写入命令追加到AOF文件末尾。

    步骤3用于关闭RDB功能,这一步是可选的,如果你愿意的话,也可以同时使用RDB和AOF这两种持久化功能。

    展开全文
  • 配置方案:Redis持久化RDB和AOF

    千次阅读 2019-02-18 22:21:55
    Redis持久化方案 Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,利用持久化文件实现数据...

    Redis持久化方案

    Redis是内存数据库,数据都是存储在内存中,为了避免进程退出导致数据的永久丢失,需要定期将Redis中的数据以某种形式(数据或命令)从内存保存到硬盘。当下次Redis重启时,利用持久化文件实现数据恢复。除此之外,为了进行灾难备份,可以将持久化文件拷贝到一个远程位置。

    Redis提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF。

    RDB持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot),将数据库的快照(snapshot)以二进制的方式保存到磁盘中。

    AOF持久化记录服务器执行的所有更改操作命令,AOF文件中的命令全部以Redis协议的格式来保存,新命令会被追加到文件的末尾。Redis还可以在后台对AOF文件进行重写(rewrite),使得AOF文件的体积不会超出保存数据集状态所需的实际大小。

    Redis可以同时使用AOF持久化和RDB持久化。在这种情况下,当Redis重启时,它会优先使用AOF文件来还原数据集,因为AOF文件保存的数据集通常比RDB文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存在。

    了解RDB持久化和AOF持久化之间的异同是非常重要的,以下几个小节将详细地介绍这这两种持久化功能,并对它们的相同和不同之处进行说明。

    RDB快照

    下面我们说一下Redis的第一个持久化策略,RDB快照。Redis支持将当前内存数据的快照存成一个数据文件的持久化机制,而一个持续写入的数据库如何生成快照呢?Redis巧妙地借助了fork命令的写时复制(copy on write)机制,将当前进程fork出一个子进程,子进程根据内存快照,循环将数据持久化为RDB文件。

    在默认情况下, Redis将数据库快照保存在根目录下,名字为dump.rdb的二进制文件中。可通过参数dir配置指定保存目录,dbfilename指定文件名。你可以对Redis进行设置,如“save N M”,表示N秒内数据项中有M个改动时这一条件被满足时,自动保存一次数据集。比如你可以配置当10分钟以内有100次写入就生成快照,也可以配置当1分钟内有1000次写入就生成快照,支持可以多个规则一起生效,当匹配到哪个就哪个规则生效。这些规则的定义就在Redis的配置文件中,你也可以通过Redis的CONFIG SET命令在Redis运行时设置规则,不需要重启Redis。

    比如说,以下设置会让Redis在满足“60秒内有至少有1000个键被改动”这一条件时,自动保存一次数据集:

    save 60 1000
    

    你也可以通过调用SAVE或者BGSAVE,手动让Redis进行数据集保存操作。SAVE命令执行一个同步操作,以RDB文件的方式保存所有数据的快照,很少在生产环境直接使用SAVE命令,因为它会阻塞所有的客户端的请求,不要在生产环境使用,可以使用BGSAVE命令代替。BGSAVE命令执行过程中是通过fork一个子进程来完成的,所以不会阻塞客户端请求,只有fork子进程时会阻塞服务器。另外,在自动触发RDB持久化时,Redis也会选择BGSAVE而不是SAVE来进行持久化。

    Redis自动RDB持久化在其内部是通过serverCron周期性操作函数、dirty计数器、和lastsave时间戳来实现的。其中serverCron每100ms执行一次,检查服务器状态,其中就包括检查“save N M”是否满足条件,如果满足就执行BGSAVE;当然也包括AOF重写检查。dirty计数器是Redis服务器维持的一个状态,记录了上一次执行BGSAVE/SAVE命令后,服务器状态进行了多少次修改(包括增删改),而当BGSAVE/SAVE执行完成后,会将dirty重新置为0。lastsave时间戳也是Redis服务器维持的一个状态,记录的是上一次成功执行BGSAVE/SAVE的时间,当前时间减去lastsave需满足M。

    除了手动和自动以外,还有一些其他情况会触发BGSAVE:

    在主从复制场景下,如果从节点执行全量复制操作,则主节点会执行BGSAVE命令,并将rdb文件发送给从节点。
    执行shutdown命令时,自动执行rdb持久化。
    另外需要了解的,因为其写操作是在一个新进程中进行的,当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件,这样在任何时候出现故障,Redis的RDB文件都总是可用的。

    这种持久化方式被称为快照(snapshot)。但是,我们可以很明显的看到,RDB有他的不足,就是一旦数据库出现问题,那么我们的RDB文件中保存的数据并不是全新的,从上次RDB文件生成到Redis停机这段时间的数据全部丢掉了。在某些业务下,如果可以忍受间隔内数据丢失,我们也推荐这些业务使用RDB的方式进行持久化,因为开启RDB的代价并不高。但是对于另外一些对数据安全性要求极高的应用,无法容忍数据丢失的应用,RDB就无能为力了,所以Redis引入了另一个重要的持久化机制,AOF日志方式持久化。

    为了尽可能使RDB文件体积减小,Redis默认采用LZF算法对RDB文件进行压缩。虽然压缩耗时,但是可以大大减小RDB文件的体积,因此压缩默认开启,参数为rdbcompression。需要注意的是,RDB文件的压缩并不是针对整个文件进行的,而是对数据库中的字符串进行的,且只有在字符串达到一定长度(20字节)时才会进行。

    除了压缩,你也可以检验RDB文件,通过参数rdbchecksum设置,默认为yes。在写入文件和读取文件时都起作用,关闭checksum在写入文件和启动文件时大约能带来10%的性能提升,但是数据损坏时无法发现。

    另外,当bgsave出现错误时,Redis是否停止执行写命令。Redis提供了一个参数stop-writes-on-bgsave-error,设置为yes,则当硬盘出现问题时,可以及时发现,避免数据的大量丢失;设置为no,则Redis无视bgsave的错误继续执行写命令,当对Redis服务器的系统(尤其是硬盘)使用了监控时,该选项考虑设置为no。

    说说FORK的开销?

    父进程通过fork操作可以创建子进程,第一代Unix系统实现了一种傻瓜式的进程创建:当执行fork系统调用时,内核复制父进程的整个用户空间并把复制得到的那一份分配给子进程。这种行为时非常耗时的,因为它需要完成以下几项任务:为子进程的页表分配页面、为子进程的页分配页面、初始化子进程的页表、把父进程的页复制到子进程对应的页中。

    现在Linux的fork()使用写时拷贝(copy-on-write)页实现。写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址空间,而是让父进程和子进程共享同一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。也就是说,资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。这种技术使地址空间上的页的拷贝被推迟到实际发生写入的时候。所以就算fork很大内存的进程,对内存的消耗和耗时都很小。

    现在虽然fork时,子进程不会复制父进程的数据空间,但是会复制内存页表(页表相当于内存的索引、目录);父进程的数据空间越大,内存页表越大,fork时复制耗时也会越多。这个问题也是导致Redis内存不宜过大的原因之一,当然还有导致故障恢复时间延长也是Redis内存不宜过大的原因。

    AOF日志

    通过上面的分析,我们知道RDB快照有大概率丢失最近写入、且仍未保存到快照中的那些数据。尽管对于某些程序来说,数据安全并不是最重要的考虑因素,但是对于那些追求数据安全的程序来说,快照功能就不太适用了。从1.1版本开始,Redis增加了一种实时性更好的持久化方式,即AOF持久化。AOF日志的全称是append only file,从名字上我们就能看出来,它是一个追加写入的日志文件。与RDB相比,AOF的实时性更好,因此已成为主流的持久化方案。

    AOF文件与MySQL数据库的binlog不同的是,AOF是一种纯文本格式,具有兼容性好、可读性强、容易处理、操作简单避免二次开销等优点,它记录的内容就是一个个的Redis标准命令。开启AOF持久化命令如下:

    appendonly yes
    appendfilename "appendonly.aof"
    

    从现在开始,每当Redis执行一个改变数据集的命令时(比如SET),这个命令就会被追加到AOF文件的末尾。这样的话,当Redis重新启时,程序就可以通过重新执行AOF文件中的命令来达到重建数据集的目的。

    由于需要记录Redis的每条写命令,因此AOF不需要触发,下面介绍AOF的执行流程:

    命令追加(append)

    Redis先将写命令追加到缓冲区,而不是直接写入文件,主要是为了避免每次有写命令都直接写入硬盘,导致硬盘IO成为Redis负载的瓶颈。

    文件写入(write)和文件同步(sync)

    Redis提供了多种AOF缓存区的同步文件策略,策略涉及到操作系统的write函数和fsync函数,说明如下:

    为了提高文件写入效率,在现代操作系统中,当用户调用write函数将数据写入文件时,操作系统通常会将数据暂存到一个内存缓冲区里,当缓冲区被填满或超过了指定时限后,才真正将缓冲区的数据写入到硬盘里。这样的操作虽然提高了效率,但也带来了安全问题:如果计算机停机,内存缓冲区中的数据会丢失;因此系统同时提供了fsync、fdatasync等同步函数,可以强制操作系统立刻将缓冲区中的数据写入到硬盘里,从而确保数据的安全性。

    AOF缓存区的同步文件策略由参数appendfsync控制,各个值的含义如下:

    always:命令写入aof_buf后立即调用系统fsync操作同步到AOF文件,fsync完成后线程返回。这种情况下,每次有写命令都要同步到AOF文件,硬盘IO成为性能瓶颈,Redis只能支持大约几百TPS写入,严重降低了Redis的性能;即便是使用固态硬盘(SSD),每秒大约也只能处理几万个命令,而且会大大降低SSD的寿命。

    no:命令写入aof_buf后调用系统write操作,不对AOF文件做fsync同步;同步由操作系统负责,通常同步周期为30秒。这种情况下,文件同步的时间不可控,且缓冲区中堆积的数据会很多,数据安全性无法保证。
    everysec:命令写入aof_buf后调用系统write操作,write完成后线程返回;fsync同步文件操作由专门的线程每秒调用一次。everysec是前述两种策略的折中,是性能和数据安全性的平衡,因此是Redis的默认配置,也是我们推荐的配置。

    文件重写(rewrite)

    因为AOF的运作方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加,AOF文件的体积也会变得越来越大。举个例子,如果你对一个计数器调用了100次INCR,那么仅仅是为了保存这个计数器的当前值,AOF文件就需要使用100条记录(entry)。然而在实际上,只使用一条SET命令已经足以保存计数器的当前值了,其余99条记录实际上都是多余的。另外还有一些过期的数据,无效的数据也都是可以去除。

    过大的AOF文件不仅会影响服务器的正常运行,也会导致数据恢复需要的时间过长。为了处理这种情况,Redis支持一种有趣的特性,可以在不打断服务客户端的情况下,对AOF文件进行重建(rebuild)。执行BGREWRITEAOF命令, Redis将生成一个新的AOF文件, 这个文件包含重建当前数据集所需的最少命令。

    AOF REWRITE(重写)生成过程和RDB快照类似,都巧妙地利用了写时复制机制。同样也是fork一个子进程(此时主线程是阻塞的),子进程根据内存快照,按照命令合并规则写入到新的AOF文件。当主进程fork完子线程后继续接受请求,所有写命令依然写入AOF缓冲区(aof_buf),并根据appendfsync策略同步到硬盘,保证原有AOF机制的正确。但由于fork操作使用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然在响应命令,因此Redis使用AOF重写缓冲区(aof_rewrite_buf)保存这部分新日志,防止新AOF文件生成期间丢失这部分数据。也就是说,bgrewriteaof执行期间,Redis的写命令同时追加到aof_buf和aof_rewirte_buf两个缓冲区。

    当子进程写完新的AOF文件后,向父进程发信号,父进程更新统计信息,具体可以通过info persistence查看。然后父进程把AOF重写缓冲区的数据写入到新的AOF文件,这样就保证了新AOF文件所保存的数据库状态和服务器当前状态一致。然后调用原子性的rename命令用新的AOF文件取代老的AOF文件,完成AOF重写。

    这里需要注意,因为由主进程把aof_rewrite_buf缓存追加到新日志文件。主进程追加日志时,不会处理其他请求,如果aof_rewrite_buf特别大,例如几百M,也可能造成Redis几秒甚至几十秒不响应。

    从上面的流程我们能够看到,RDB和AOF操作都是顺序IO操作,性能都很高。而在通过RDB文件或者AOF日志进行数据库恢复的时候,也是顺序的读取数据加载到内存中。所以也不会造成磁盘的随机读。

    文件重写的触发,分为手动触发和自动触发:

    手动触发:直接调用bgrewriteaof命令,该命令的执行与bgsave有些类似:都是fork子进程进行具体的工作,且都只有在fork时阻塞。

    自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数,以及aof_current_size和aof_base_size状态确定触发时机。

    auto-aof-rewrite-min-size表示执行AOF重写时,文件的最小体积,默认值为64MB。

    auto-aof-rewrite-percentage表示执行AOF重写时,当前AOF大小(即aof_current_size)和上一次重写时AOF大小(aof_base_size)的比值,即增长比例达到设定值。

    只有当auto-aof-rewrite-min-size和auto-aof-rewrite-percentage两个参数同时满足时,才会自动触发AOF重写,即bgrewriteaof操作。

    其中,参数可以通过config get命令查看:

    127.0.0.1:6391> CONFIG GET auto-aof-rewrite-min-size
    1) "auto-aof-rewrite-min-size"
    2) "64000000"
    127.0.0.1:6391> CONFIG GET auto-aof-rewrite-percentage
    1) "auto-aof-rewrite-percentage"
    2) "100"
    

    状态可以通过info persistence查看:

    127.0.0.1:6379> info persistence
    # Persistence
    aof_enabled:1
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:0
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_current_size:40876638
    aof_base_size:2217565
    aof_pending_rewrite:0
    aof_buffer_length:0
    aof_rewrite_buffer_length:0
    aof_pending_bio_fsync:0
    aof_delayed_fsync:0
    

    另外在aof rewrite过程中,是否采取增量”文件同步”策略,由参数aof-rewrite-incremental-fsync控制,默认为”yes”,而且必须为yes。rewrite过程中,每32M数据进行一次文件同步,这样可以减少”aof大文件”写入对磁盘的操作次数。

    bgrewriteaof机制,在一个子进程中进行aof的重写,从而不阻塞主进程对其余命令的处理,同时解决了aof文件过大问题。现在问题出现了,同时在执行bgrewriteaof操作和主进程写aof文件的操作,两者都会操作磁盘,而bgrewriteaof往往会涉及大量磁盘操作,这样就会造成主进程在写aof文件的时候出现阻塞的情形,现在no-appendfsync-on-rewrite参数出场了。

    如果该参数设置为no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为yes呢?这就相当于将appendfsync设置为no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候Redis挂掉,就会丢失数据。丢失多少数据呢?在Linux的操作系统的默认设置下,最多会丢失30s的数据。因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为yes。如果应用系统无法忍受数据丢失,则设置为no。

    AOF刷新策略?

    前面提到过,在AOF中,如果AOF缓冲区的文件同步策略为everysec,则:在主线程中,命令写入aof_buf后调用系统write操作,write完成后主线程返回;fsync同步文件操作由专门的文件同步线程每秒调用一次。这种做法的问题在于,如果硬盘负载过高,那么fsync操作可能会超过1s;如果Redis主线程持续高速向aof_buf写入命令,硬盘的负载可能会越来越大,IO资源消耗更快;如果此时Redis进程异常退出,丢失的数据也会越来越多,可能远超过1s。

    为此,Redis的处理策略是这样的:主线程每次进行AOF会对比上次fsync成功的时间;如果距上次不到2s(也就是延迟了1s),主线程直接返回;如果超过2s,则主线程阻塞直到上一次fsync同步完成。因此,如果系统硬盘负载过大导致fsync速度太慢,会导致Redis主线程的阻塞;此外,使用everysec配置,AOF最多可能丢失2s的数据,而不是1s。具体看Redis AOF刷新策略分析

    AOF追加阻塞问题定位的方法,监控info Persistence中的aof_delayed_fsync,当AOF追加阻塞发生时(即主线程等待fsync而阻塞),该指标累加。另外,AOF阻塞时的Redis日志:Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis.

    如果AOF追加阻塞频繁发生,说明系统的硬盘负载太大;可以考虑更换IO速度更快的硬盘,或者通过IO监控分析工具对系统的IO负载进行分析。

    对于pipelining有什么不同?

    对于pipelining的操作,其具体过程是客户端一次性发送N个命令,然后等待这N个命令的返回结果被一起返回。通过采用pipilining就意味着放弃了对每一个命令的返回值确认。由于在这种情况下,N个命令是在同一个执行过程中执行的。所以当设置appendfsync为everysec时,可能会有一些偏差,因为这N个命令可能执行时间超过1秒甚至2秒。但是可以保证的是,最长时间不会超过这N个命令的执行时间和。

    如果AOF文件出错了,怎么办?

    服务器可能在程序正在对AOF文件进行写入时停机,如果停机造成了 AOF 文件出错(corrupt),那么Redis在重启时会拒绝载入这个AOF文件, 从而确保数据的一致性不会被破坏。当发生这种情况时,可以用以下方法来修复出错的 AOF 文件:为现有的AOF文件创建一个备份。然后使用Redis附带的redis-check-aof --fix程序对原来的AOF文件进行修复。

    然后可选使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。再次重启Redis服务器,等待服务器载入修复后的AOF文件,并进行数据恢复。

    但如果是AOF文件结尾不完整(机器突然宕机等容易导致文件尾部不完整),且aof-load-truncated参数开启,则日志中会输出警告,Redis忽略掉AOF文件的尾部,启动成功。aof-load-truncated参数默认是开启的。

    RDB和AOF优缺点

    RDB的优点?

    RDB是一个非常紧凑(compact)的文件,体积小,网络传输快,它保存了Redis在某个时间点上的数据集。这种文件非常适合用于进行备份,恢复速度比AOF快很多。当然,与AOF相比,RDB最重要的优点之一是对性能的影响相对较小。父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。

    RDB的缺点?

    RDB文件的致命缺点在于其数据快照的持久化方式决定了必然做不到实时持久化,而在数据越来越重要的今天,数据的大量丢失很多时候是无法接受的,因此AOF持久化成为主流。此外,RDB文件需要满足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。

    AOF的优点?

    与RDB持久化相对应,AOF的优点在于支持秒级持久化、兼容性好。你可以设置不同的fsync策略,比如无fsync,每秒钟一次fsync,或者每次执行写入命令时fsync。AOF的默认策略为每秒钟fsync一次,在这种配置下,Redis仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据。AOF文件是一个只进行追加操作的日志文件(append only log),因此对AOF文件的写入不需要进行seek(查找),即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。

    Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写: 重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。 而一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对新AOF文件进行追加操作。AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。导出(export)AOF文件也非常简单: 举个例子, 如果你不小心执行了FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器,移除AOF文件末尾的FLUSHALL命令,并重启 Redis, 就可以将数据集恢复到FLUSHALL执行之前的状态。

    AOF的缺点?

    AOF文件的体积通常要大于RDB文件的体积、且恢复速度慢。对于相同的数据集来说,根据所使用的fsync策略,AOF的速度可能会慢于RDB。在一般情况下,每秒fsync的性能依然非常高,而关闭fsync可以让AOF的速度和RDB一样快。另外,AOF在过去曾经发生过这样的bug,因为个别命令的原因,导致AOF文件在重新载入时,无法将数据集恢复成保存时的原样。虽然这种bug在AOF文件中并不常见,但是对比来说,RDB几乎是不可能出现这种bug的。

    RDB和AOF,我应该用哪一个?

    首先要明白无论是RDB还是AOF,持久化的开启都是要付出性能方面代价的:对于RDB持久化,一方面是bgsave在进行fork操作时Redis主进程会阻塞,另一方面,子进程向硬盘写数据也会带来IO压力。但如果业务能容忍几分钟到10几分钟的数据丢失(且不使用备库),RDB是一个不错的选择;不然,就选择AOF。

    对于AOF持久化,向硬盘写数据的频率大大提高(everysec策略下为秒级),IO压力更大,甚至可能造成AOF追加阻塞问题(后面会详细介绍这种阻塞),此外,AOF文件的重写与RDB的bgsave类似,会有fork时的阻塞和子进程的IO压力问题。相对来说,由于AOF向硬盘中写数据的频率更高,因此对Redis主进程性能的影响会更大。

    在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不同情况,会有各种各样的持久化策略;如完全不使用任何持久化、使用RDB或AOF的一种,或同时开启RDB和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一起考虑,因为主从复制与持久化同样具有数据备份的功能,而且主机master和从机slave可以独立的选择持久化方案。比如完全关闭master持久化(包括RDB和AOF),这样可以让master的性能达到最好;而slave可以只开启AOF。但这种情况下,如果master服务因为故障宕掉了,如果系统中有自动拉起机制(即检测到服务停止后重启该服务)将master自动重启,由于没有持久化文件,那么master重启后数据是空的,slave同步数据也变成了空的,意味着数据丢失。所以尽量避免这种情况出现。

    RDB和AOF之间的相互作用?

    在版本号大于等于2.4的Redis中,BGSAVE执行的过程中,不可以执行BGREWRITEAOF。反过来说,在BGREWRITEAOF执行的过程中,也不可以执行BGSAVE。这可以防止两个Redis后台进程同时对磁盘进行大量的I/O操作。

    如果BGSAVE正在执行,并且用户显示地调用BGREWRITEAOF命令,那么服务器将向用户回复一个OK状态,并告知用户,BGREWRITEAOF已经被预定执行: 一旦BGSAVE执行完毕,BGREWRITEAOF就会正式开始。当Redis启动时,如果RDB持久化和AOF持久化都被打开了,那么程序会优先使用AOF文件来恢复数据集,因为AOF文件所保存的数据通常是最完整的。

    RDB和AOF数据导入

    这些持久化的数据有什么用,当然是用于重启后的数据恢复。Redis是一个内存数据库,无论是RDB还是AOF,都只是其保证数据恢复的措施。所以Redis在利用RDB或AOF进行恢复的时候,会读取RDB或AOF文件,重新加载到内存中。相对于MySQL等数据库的启动时间来说,会长很多,因为MySQL本来是不需要将数据加载到内存中的。

    但是相对来说,MySQL启动后提供服务时,其被访问的热数据也会慢慢加载到内存中,通常我们称之为预热,而在预热完成前,其性能都不会太高。而Redis的好处是一次性将数据加载到内存中,一次性预热。这样只要Redis启动完成,那么其提供服务的速度都是非常快的。

    而在利用RDB和利用AOF启动上,其启动时间有一些差别。RDB的启动时间会更短,原因有两个,一是RDB文件中每一条数据只有一条记录,不会像AOF日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。另一个原因是RDB文件的存储格式和Redis数据在内存中的编码格式是一致的,不需要再进行数据编码工作。在CPU消耗上要远小于AOF日志的加载。

    注意:当redis启动时,如果rdb持久化和aof持久化都打开了,那么程序会优先使用aof方式来恢复数据集,因为aof方式所保存的数据通常是最完整的。如果aof文件丢失了,则启动之后数据库内容为空。

    注意:如果想把正在运行的redis数据库,从RDB切换到AOF,建议先使用动态切换方式,再修改配置文件,重启数据库。(不能直接修改配置文件,重启数据库,否则数据库中数据就为空了。)
    在Redis 2.2或以上版本,可以在不重启的情况下,从RDB切换到AOF :

    为最新的dump.rdb文件创建一个备份,将备份放到一个安全的地方。执行以下两条命令:

    127.0.0.1:6379> CONFIG SET dir /apps/redis/data/redis-8836
    127.0.0.1:6379> CONFIG SET appendonly yes
    127.0.0.1:6379> CONFIG SET save ""
    

    确保命令执行之后,数据库的键的数量没有改变。确保写命令会被正确地追加到 AOF 文件的末尾。

    步骤2是开启了AOF功能,Redis会阻塞直到初始AOF文件创建完成为止,之后Redis会继续处理命令请求,并开始将写入命令追加到AOF文件末尾。

    步骤3用于关闭RDB功能,这一步是可选的,如果你愿意的话,也可以同时使用RDB和AOF这两种持久化功能。

    展开全文
  • Redis持久化RDB和AOF原理及区别

    千次阅读 2018-03-19 22:14:42
    前言:redis持久化方式分为两种:RDB快照和AOF方式(默认为RDB模式),当Redis服务器重启的时候,会自动恢复数据,优先从AOF中恢复,其次才从RDB中恢复 一、RDB快照模式RDB方式原理:当redis需要做持久化时(执行...
    前言:
    redis持久化方式分为两种:RDB快照和AOF方式(默认为RDB模式),当Redis服务器重启的时候,会自动恢复数据,优先从AOF中恢复,其次才从RDB中恢复
     
    一、RDB快照模式
    RDB方式原理:当redis需要做持久化时(执行SAVA或者BGSAVA命令,或者是达到配置条件时执行),redis会fork一个子进程,子进程将数据写到磁盘上一个临时RDB文件中,当子进程完成写临时文件后,将原来的RDB替换掉(默认文件名为dump.rdb)
     
    RDB备份条件和命令:
    1、执行SAVE命令,在当前线程执行,会卡住
    2、执行BGSAVE命令,在后台线程执行,马上返回
    3、当符合用户给定的配置条件时Redis会自动将内存中的所有数据进行快照并存储在硬盘上。由两个参数构成:时间和改动的键的个数。当在指定的时间内被更改的键的个数大于指定的数值时就会进行快照,在配置文件redis.conf中 已经预置了3个条件:
    save 900 1 # 900秒内有至少1个键被更改则进行快照 save 300 10 # 300秒内有至少10个键被更改则进行快照 save 60 10000 # 60秒内有至少10000个键被更改则进行快照
     
    RDB优缺点:
    定时备份,Redis效率高,但是容易造成数据丢失,丢失的多少和备份策略有关,例如:5分钟备份一次,但是第8分时宕机了,那么就丢失了后面的3分钟数据
     
    一、AOF模式
    AOF方式原理:AOF就可以做到全程持久化,Redis每执行一个修改数据的命令,都会把这个命令添加到AOF文件中,当Redis重启时,将会读取AOF文件进行“重放”以恢复到 Redis关闭前的最后时刻。
    由于os会在内核中缓存 write做的修改,所以可能不是立即写到磁盘上。这样aof方式的持久化也还是有可能会丢失部分修改。不过我们可以通过配置文件告诉redis我们想要 通过fsync函数强制os写入到磁盘的时机。有三种方式如下(默认是:每秒fsync一次)
    appendonly yes              //启用aof持久化方式
    # appendfsync always      //每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
    appendfsync everysec     //每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
    # appendfsync no    //完全依赖os,性能最好,持久化没保证
     
    AOF优缺点
    AOF基本可以保证数据不丢失,但是AOF持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。


    redis的 rdb 和 aof 持久化的区别


    两种区别就是,一个是持续的用日志记录写操作,crash后利用日志恢复;一个是平时写操作的时候不触发写,只有手动提交save命令,或者是关闭命令时,才触发备份操作。

    选择的标准,就是看系统是愿意牺牲一些性能,换取更高的缓存一致性(aof),还是愿意写操作频繁的时候,不启用备份来换取更高的性能,待手动运行save的时候,再做备份(rdb)。rdb这个就更有些 eventually consistent的意思了。

    展开全文
  • RDB和AOF都可以Redis持久化两者有一定的区别: Redis默认是开启RDB的,AOF默认关闭,需要手动开启; RDB和AOF同时开启的情况下,会只加载AOF, 两者都有相应的check命令,来进行检测修复--fix, RDB 由系统fork...
  • redis中数据的持久化有两种方式,分别是RDB和AOF,如果没有配置持久化redis重启后数据就全丢失了,所以需要开启redis持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。redis提供两种...
  • 一、redis持久化----两种方式 1、redis提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。 2、RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;...
  • Redis持久化方式?RDBAOFAOF重写两种持久化机制优缺点两种持久化机制工作原理RDB和AOF触发机制RDB和AOF区别 Redis为什么要有持久化? 因为Redis是一个基于内存的数据库,因此数据容易丢失,为了解决数据丢失的问题...
  • Redis解读持久化RDB和AOF原理

    千次阅读 2020-07-04 18:44:24
    为了保证Redis故障重启后仍然可用我们的Redis支持全备(RDB快照备份)增备(AOF日志连续增量备份),下面我们就来解读Redis持久化的原理。 RDB基础知识 RDB文件存在是以一个压缩后的二进制文件,这个RDB文件...
  • 提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF. RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。 AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时...
  • 首先要先说下redis持久化的意义: redis持久化的意义主要在于故障恢复,比如你部署一个redis,作为缓存有可能里边有一些比较重要的数据,如果没有持久化的时候,redis遇到灾难性故障的时候就会丢失所有的数据。 多以...
  • redis持久化rdbaof的关闭、开启

    万次阅读 2019-06-03 15:42:40
    redis.conf默认配置(4.0.14): # save "" save 900 1 save 300 10 save 60 10000 appendonly no ...默认是开启了rdbaof是关闭的。若开启了aof,一般aof更新频率高,所以优先aof还原数据库...
  • AOF持久化策略使用everysecond,每秒钟fsync一次,该策略redis仍可以保持很好的处理性能,当出现问题时,最多丢失0-1秒的数据 注意:由于AOF文件存储体积较大,且恢复速度慢 数据呈现阶段有效性,建议使用RDB持久化方案 ...
  • Redis持久化RDB和AOF

    2020-12-14 22:23:12
    Redis持久化 Redis支持RDB和AOF两种持久化机制,持久化功能有效地避免因进程退出造成的数据丢失问题,当下次重启时利用之前持久化的文件即可实现数据恢复。 1.RDB持久化 RDB持久化是把当前进程数据生成快照保存到...
  • redis持久化RDB和AOF

    2019-09-22 17:40:26
    什么是redis持久化?  redis是一种内存型的数据库,一旦服务器的...redis提供了RDB持久化的功能,这个功能可以将redis在内存中的的状态保存到硬盘中,它可以手动执行。 也可以再redis.conf中配置,定期执行。 ...
  • rdb和aof。分别代表内存数据库两种思路,全量快照保存日志形式保存。 一、RDB 学习rdb最权威的方式就是去看他的redis.conf配置文件,里面有很多详细说明 rdb是全量保存当前时刻内存数据到磁盘。 从文档的描述可以...
  • Redis 提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。 RDB,简而言之,就是在不同的时间点,将Redis 存储的数据生成快照并存储到磁盘等介质上。 AOF,则是换了一个角度来实现持久化,...
  • Redis 持久化RDB 和AOF

    2018-09-26 14:53:00
    一、持久化之全量写入:RDB rdb配置 [redis@6381]$ more redis.conf save 900 1 save 300 10 save 60 10000 dbfilename "dump.rdb" #持久化文件名称 dir "/data/dbs/redis/6381" #持久化数据文件存放的...
  • 数据可以持久化,而且支持的数据类型很丰富。有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交补集(difference)等,还支持多种排序功能。所以Redis也可以被看成是一个数据结构服务器。 Redis为了...
  • 一:持久化redis时内存型的nosql数据库,项目数据时非常重要的,所以数据安全必须考虑,而redis支持...redis一共有两种持久化方法,一个时RDB,一个时AOF 二:RDB(Snapshotting) 原理:首先redis是一个单线程,主...
  • Redis 持久化RDB和AOF Redis 有两种持久化方案,RDBRedis DataBase) AOF (Append Only File)。如果你想快速了解使用RDB和AOF,可以直接跳到文章底部看总结。本章节通过配置文件,触发快照的方式,恢复...
  • Redis持久化RDB和AOF配置对比

    万次阅读 2017-11-28 09:52:12
    Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。 2.RDB持久化 持久化机制:指定的时间间隔内将内存中的数据集以快照写入磁盘 RDB方式的持久化是通过快...
  • Redis(二)、Redis持久化RDB和AOF 一、Redis两种持久化方式 对Redis而言,其数据是保存在内存中的,一旦机器宕机,内存中的数据会丢失,因此需要将数据异步持久化到硬盘中保存。这样,即使机器宕机,数据能从硬盘中...
  • 1. RDB 持久化的优缺点 2. AOF 持久化的优缺点 3. 混合持久化 Redis 是一个键值对数据库服务器,服务器中通常包含着任意个非空数据库,而每个非空数据库中有可以包含任意个键值对,为了方便起见,我们将服务器中...
  • redis基础概念描述 Redis中的网络IO键值对读写是单线程的,但是持久化,异步删除,集群数据同步是多线程的。 ...redis持久化 简述:redis的持久化机制有两种:RDB快照(条件触发),AOP(实时记
  • Redis是一种高级key-value数据库。数据可以持久化,而且支持的数据类型很...Redis为了保证效率,数据缓存在内存中,Redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,以保证数据的持久化。 ...
  • 一、redis持久化----两种方式 1、redis提供了两种持久化的方式,分别是RDB(RedisDataBase)和AOF(AppendOnlyFile)。 2、RDB,简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 45,203
精华内容 18,081
关键字:

redis持久化rdb和aof

redis 订阅