缓存数据库Redis
1、主流应用架构。
1)、客户端向后端发送请求的时候,会先去缓存层查询,查询看看是否有符合的数据。
2)、如果有的话,直接返回。
3)、如果在缓存层没有查询到,才回去存储层去查询。
4)、去存储层查询叫做穿透查询,就是穿透缓存去存储层进行查询。
5)、从存储层查询出的数据回写到缓存层,方便下次查询的时候进行查询,回写的过程就是会种了。
6)、此时,返回给客户端,完成一次查询操作。
7)、缓存层还有一个熔断机制,如果存储层挂掉了,可以让客户端的请求直接打到缓存层上。
8)、不管是否获取到数据,直接进行返回,这样可以在有损的情况了,提供服务。
2、缓存中间件,Memcache和Redis的区别。
1)、Memcache,代码层次类似Hash,非常简单易用。支持简单的数据类型,但是不支持数据的持久化存储,如果服务器宕机了,数据是无法保存的。不支持主从同步,不支持分片机制。
2)、Redis,数据类型丰富,支持数据磁盘持久化存储,支持主从,支持分片。
3、为什么Redis能这么快?
答:Redis官方提供的100000+QPS,(QPS即query per second,每秒内查询次数)。
1)、完全基于内容,绝大部分请求是纯粹的内存操作,执行效率高。Redis是采用单进程单线程模型的K-V数据库,由c语言编写,将数据存储到内存中,读写数据的时候都不会受到硬盘IO速度的限制。
2)、数据结构简单,对数据操作也简单。Redis不使用表,它的数据库不会预定义或者强制要求用户对redis存储的不同数据进行关联,因此性能相比关系型数据库要高出不止一个量级,其存储结构就是键值对,类似于hashMap,hashMap的优势就是查询,查询的时间复杂度是O(1)的。
3)、采用单线程,单线程也能处理高并发请求,想多核也可启动多实例。在面对高并发的请求的时候,首先想要的是多线程来进行处理,将IO线程和业务线程分开,业务线程使用线程池来避免频繁创建线程和销毁线程,即便是一次请求,阻塞了也不会影响到其它请求。Redis单线程结构是指主线程是单线程的,主线程包含IO事件的处理,以及IO对应的相关请求的业务处理,此外,主线程还负责过期键的处理,复制协调,集群协调等等,这些除了IO事件之外的逻辑会被封装成周期性的任务,由主线程周期性的处理,正因为采用单线程的设计,对于客户端的所有读写请求,都由一个主线程串行的处理,因此多个客户端同时对一个键进行写操作的时候,就不会有并发的问题,避免了频繁的上下文切换和锁竞争,使得redis执行起来效率更高。单线程是可以处理高并发的请求的,并发并不是并行,并行性意外着服务器能够同时执行几个事情,具有多个计算的单元,而并发性IO流,意味着能够让一个计算单元来处理来自多个客户端的流请求。Redis使用单线程配合上IO多路复用,将可以大幅度的提升性能,在多核CPU流行的今天,只要一个线程,只用一个核很浪费,CPU不是制约redis的性能瓶颈,此外,可以在多核的服务器中启动多个实例来利用多核的特性。
注意,这里的单线程只是在处理我们的网络请求的时候,只有一个单线程来处理,一个正式的Redis server,在运行的时候,肯定不止一个线程的,例如Redis在进行持久化的时候,会根据实际情况,以子进程子线程的方式执行。
4)、使用多路I/O复用模型,非阻塞IO。Redis是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或者输出都是阻塞的,所以IO操作在一般情况下,往往不能直接返回,就会导致某一文件的IO阻塞,进而导致整个进程无法对其它客户端提供服务。而IO多路复用就是为了解决这个问题而出现的。
4、多路I/O复用模型。
答:FD,File Descriptor文件描述符。在操作系统中,一个打开的文件通过唯一的描述符进行引用,该描述符是打开文件的元素据到文件本身的映射,在linux中,该描述符称为文件描述符即File Descriptor,文件描述符用一个整数来表示。
1)、传统的阻塞I/O模型,当使用read或者write的对某一个文件描述符FD进行读写的时候,如果当前的FD不可读或者不可写,整个Redis服务就不会对其它的操作做出相应,导致整个服务不可用,这也就是传统意义上的阻塞IO模型,阻塞模型会影响其它FD对应的服务,所以在需要处理多个客户端任务的时候,往往都不会使用阻塞模型。此时,需要一种更高效的IO模型来支持Redis的高并发处理,就是IO复用多路模型。
2)、多路I/O复用模型,最重要的函数调用就是Select系统调用。Select可以同时监控多个文件描述符的可读,可写情况,当其中的某些文件描述符可读或者可写的时候,select就会返回可读以及可写的文件描述符个数,也就是说,Selector是负责监听我们的文件是否可读或者可写的,监听的任务交给Selector之后呢,程序就可以做其它的事情了,而不被阻塞了。
3)、与此同时,也有其它的多路IO复用函数,Redis采用的IO多路复用函数:epoll、kqueue、evport、select。epoll、kqueue、evport相比select的性能更加优秀的,同时也可以支撑更多的服务。
a)、Redis采用的多路复用函数是因地制宜的,Redis需要在多个平台下运行,为了最大化的提高执行效率和性能,会根据编译平台的不同选择不同的IO多路复用函数作为子模块,提高给上层同一的接口。
b)、Redis优先选择时间复杂度为O(1)的IO多路复用函数作为底层实现。
c)、以时间复杂度为O(n)的select作为保底。如果没有epoll、kqueue、evport、就会使用select,会扫描全部的文件描述符,性能较差,时间复杂度是O(n)。
d)、基于react设计模式监听I/O事件。Redis采用react设计模式来实现文件处理器的,文件事件处理器使用IO多路复用m模块,同时监听多个FD,当accept,read,write,等事件产生的时候,事件处理器就会回调FD绑定的事件处理器,虽然整个事件处理器是在单线程运行的,但是通过IO多路复用模块的引用,实现了同时对多个FD读写的监控,提高了网络通信模型的性能,同时来保证了整个Redis服务实现的简单。
5、Redis的数据类型(Redis底层数据类型基础,简单动态字符串、链表、字典、跳跃表、整数集合、压缩列表、对象)。
1)、String,最基本的数据类型,二进制安全的。常用的k-v键值对,最大可以存储512兆,String类型二进制安全的,意思是Redis的String包含任何数据,比如图片或者序列化的对应。Redis的单个操作都是原子性的,原子性的意思就是一个事务是一个不可分割的最小工作单位,事务中包括的诸多操作,要么都做,要么都不做。Redis的原子性使得我们不用考虑并发性,可以方便的利用原子性操作Incr来实现简单的计数功能。
2)、Hash,String元素组成的字典,适合用于存储对象,Hash是一个映射表。
3)、List,列表,按照String元素插入顺序排序,是简单的字符串列表。类似栈,先进后出的顺序。可以实现最新消息排行榜的功能,越新插入的消息越能在榜首显示。
4)、Set,String元素组成的无序集合,通过哈希表实现,不允许重复。所以添加、删除、查找的复杂度是O(1)的。提供了并集、交集、叉集功能。
5)、Sorted Set,通过分数来为集合中的成员进行从小到大的排序。Redis的zset和set集合一样,也是String集合组成的集合,且不允许重复的成员,不同的是有序集合每个元素都会关联一个double类型的分数,redis正式通过这个分数呢,来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但是分数呢却可以重复的。分数越小越靠前。
6)、用于计数的HyperLoglog,用于支持存储地理位置信息的Geo等等。
6、在Redis中,从海量Key里面查询出某一固定前缀的Key?
答:比如问题这样的,假如Redis里面有一亿个key,其中十万个key是以某个固定已知的前缀开头的,如何将它们全部找出来。留意细节,摸清楚数据规模,即问清楚边界。如果问题是从Redis里面查询出某一固定前缀的Key,记得问清楚数据量。
1)、此时,如果直接回答,使用keys pattern,这样查找所有符合给定模式pattern的key。注意,使用keys后接pattern便能按照某个指定的模式搜出某种模式的key来。由于keys一次性返回所有的key,如果key的数量过大,会导致客户端被卡住的,如果Redis中的key非常多的时候,对内存的消耗和Redis服务器都是一个隐患。Keys指令一次性返回所有匹配的key,键的数量过大会使服务卡顿。
2)、Scan指令,可以无阻塞的提取出指定的默认的key列表,scan每次执行只会返回少量元素,所以可以用于生产环境的,而不会出现像keys命令带来的可能会阻塞服务器的问题。
3)、Scan指令,模式如下所示:
Scan cursor [MATCH pattern] [COUNT count],其中cursor是游标,MATCH pattern是需要查找的模式。
a)、Scan指令是一个基于游标的迭代器,需要基于上一次的游标延续之前的迭代过程。意味着命令每次被调用都需要使用上一次调用返回的游标作为该次调用的游标参数,依次来延续之前的迭代过程。
b)、以0作为游标开始一次新的迭代,直到命令返回游标0完成一次遍历。当scan指令的游标参数即cursor被置为0的时候,服务器将开始一次新的迭代,而当服务器向用户返回值为0的游标的时候,就表示迭代完成,以0作为游标开始新一次的迭代,一直调用scan指令直到命令返回游标0,称这个过程为一次完整的遍历。
c)、不保证每次执行都返回某个给定数量的元素,支持模糊查询。Scan增量式迭代命令并不保证每次执行都会返回某个给定数量的元素,甚至可能返回0个元素,但只要命令返回的游标不是0,应用程序就不应该将迭代视作结束,命令返回的元素数量总是符合一定的规则的。对于一个大数据集来说,增量式迭代命令每次最多可能会返回数十个元素,而对于一个足够小的数据集来说,可能会一次迭代返回所有的key,类似于keys指令,scan可以通过给定match参数的方式传入要查找键位的模糊匹配方式,让命令只返回和给定模式下向匹配的元素。
d)、一次返回的数量不可控,只能是大概率符合count参数。此外,对于增量式迭代命令是没有办法保证每次迭代所返回的元素数量的,我们可以使用count选项对命令的行为进行一定程度的调整,count选项的作用就是让用户告知迭代命令,在每次迭代中,应该从数据集里返回多少元素,使用count选项对于增量式迭代命令相当于是一种提示,大多数情况下,这种提示都是比较有效的控制返回的数量的。值得注意的是,count数量并不能严格的控制返回的key的数量,只能说是一个大致的约束,并非每次迭代都会返回count数量的约束,用户可以根据自己的需求在每次迭代中随意改变count的值,只要记得将上次迭代返回的游标用到下次迭代的游标里面就可以了。
注意:可能会获取到重复key的问题,所以在程序中进行处理的。
7、分布式锁需要解决的问题?
答:分布式锁是控制分布式系统或者不同系统之间共同访问共享资源的一种锁的实现,如果不同的系统或者同一个系统不同主机之间共享了某个资源的时候,往往需要互斥来防止彼此干扰,进而保证一致性。
1)、互斥性。任意时刻只能有一个客户端获取锁,不能同时有两个客户端获取到锁。
2)、安全性。锁只能被持有该锁的客户端删除,不能由其它客户端删除掉。
3)、死锁。获取锁的客户端因为某些原因而宕机,而未能释放锁,其它客户端再也无法获取到该锁,而导致的死锁,此时需要有机制避免这种问题的发生 。
4)、容错。当部分节点宕机的时候呢,客户端仍然能够获取锁和释放锁。
8、如何通过Redis实现分布式锁?
答:SETNX key value,如果key不存在,则创建并赋值。SETNX是set if not exist即如果key不存在,则创建并赋值。时间复杂度是O(1),返回是设置成功返回1,设置失败返回0。
正因为SETNX的操作是原子性的,因此初期便被用在实现分布式锁,在执行某段代码逻辑的时候,先尝试使用SETNX对某个key设值,如果设值成功,则证明此时没有别的线程在执行该段代码,或者说占用该独占资源,这个时候线程就可以顺利的去执行该段代码逻辑了,如果设值失败,则证明此时有别的程序或者线程占用该资源,那么当前线程就需要等待直至设值SETNX成功,如果设值SETNX的key,这个key就会长久有效了,后续线程如何能再次获得到锁,此时需要给该key设值一个过期时间。
9、如何解决SETNX长期有效的问题?
答:EXPIRE key seconds。
1)、设值key的生存时间,当key过期的时候(生存时间为0),会被自动删除。
2)、使用EXPIRE设值过期时间的缺点就是原子性得不到满足。如果SETNX与EXPIRE结合使用,它们分别都是原子性的,但是组合到一起却不是原子性的。
10、如何通过Redis实现分布式锁?
答:Redis2.6.12之后,通过set操作,将SETNX和EXPIRE柔和到一起去执行,此时就满足了分布式锁的原子性需求。命令格式,SET key value [EX seconds] [PX milliseconds] [NX][XX]。
1)、EX seconds,设值键的过期时间为second秒。
2)、PX milliseconds,设值键的过期时间为millisecond毫秒。
3)、NX,只在键不存在的时候,才对键进行设值操作。效果等同于SETNX。
4)、XX,只在键已经存在的时候,才对键进行设置操作。
5)、SET操作成功完成时候,返回OK,否则返回nil。
11、大量的key同时过期的注意事项,如何避免系统卡断现象?
答:由于大量的key过期时间过于集中,集中过期,到过期的那个时间点,由于清除大量的key很耗时,会出现短暂的卡顿现象。
1)、解决方案,在设值key的过期时间的时候,给每个key加上随机值就行了,使得过期时间分散一些,很大程度上避免卡顿现象的发生。
12、如何实现异步队列,如何使用Redis做异步队列?
答:使用List作为队列,rpush生产消息,lpop消费消息。rpush与lpop组合是先进先出的效果,lpush与lpop组合是先进后出的效果。
1)、在这种生产者和消费者的模式里面,当lpop没有消息的时候,说明消息暂时被消费完毕,并且生产者还没有来得及生产消息。
2)、缺点,就是没有等待队列里有值就直接消费。lpop是不会等待队列里有值才会去消费的。
3)、弥补,可以通过在应用层引入sleep机制去调用lpop重试。进而实现一个简单的异步队列。
4)、如果不想使用sleep重试,可以使用BLPOP的方式。BLPOP key [key...] timeout,阻塞直到队列有消息或者超时。在没有消息的时候会阻塞住,直到消息的到来或者超时。BLPOP可以替代sleep做更精准的阻塞控制。
这种方式的缺点,就是只能供一个消费者消费,让lpop或者blpop。
5)、是否可以只生产一次,就让多个消费者消费呢,可以使用redis的pub/sub,主题订阅者模式。
13、Redis的主题订阅者模式。
答:pub/sub,主题订阅者模式,可以实现一对多的消费队列。通过订阅的方式可以使得消费者可以只获取到需要它们关心的并且消费的数据。
1)、发送者(pub)发送消息,订阅者(sub)接收消息。
2)、 订阅者可以订阅任意数量的频道。频道即topic,是消费者关注的主题。
3)、pub/sub的缺点,就是消息的发布是无状态的,即发布完消息之后,无法保证消息是否被接收到,是否在传输过程中丢失,对于发布者来说,消息是即发即失的,无法保证可达。此时,如果某个消费者在生产者发送消息的时候下线了,重新上线之后是接收不到该消息的。解决这个问题,就要使用专业的消息队列了如kafka等。
14、Redis如何做持久化?
答:Redis提供了三种持久化的方案,将内存中的数据保存到磁盘中。
1)、RDB(快照)持久化,快照方式持久化,保存某个时间点的全量数据快照。是一个二进制文件的。
2)、RDB持久化的缺点,缺点一,内存数据的全量同步,数据量大会由于I/O而严重影响性能的。每次快照持久化都是将快照数据完整的写入到磁盘一次,并不是增量的只同步脏数据,如果数据量大的话,并且写操作比较多的时候b必然会引起大量的磁盘IO操作,可能会严重性能。缺点二,可能会因为Redis挂掉而丢失从当前至最近一次快照期间的数据,由于快照方式是在一定间隔时间做一次的快照后的所有修改,如果应用要求bbu不能丢失任何修改的话,可以采用AOF。
1 ################################ SNAPSHOTTING ################################ 2 # 3 # Save the DB on disk: 4 # 5 # save <seconds> <changes> 6 # 7 # Will save the DB if both the given number of seconds and the given 8 # number of write operations against the DB occurred. 9 # 10 # In the example below the behaviour will be to save: 11 # after 900 sec (15 min) if at least 1 key changed 12 # after 300 sec (5 min) if at least 10 keys changed 13 # after 60 sec if at least 10000 keys changed 14 # 15 # Note: you can disable saving completely by commenting out all "save" lines. 16 # 17 # It is also possible to remove all the previously configured save 18 # points by adding a save directive with a single empty string argument 19 # like in the following example: 20 # 21 # save "" 22 23 # 持久化的时间策略。配置这么多条规则的意思是redis每个时段的读写请求肯定是不均衡的,为了平衡性能与数据安全,可以自由的什么情况下触发备份。可以根据自身redis的写入情况合理配置 24 save 900 1 # 表示900秒之内如果有一条是写入指令就触发产生一次快照。产生一次快照就可以理解为是一次备份了。 25 save 300 10 # 表示300秒以内如果有10条写入就会产生快照。如果变动数是大于0但是还没有到10条的话,就会等到900秒过后才去做备份。 26 save 60 10000 # 表示60秒内如果有一万条写入就进行一次备份。 27 save "" # 禁用RDB配置。 28 29 # By default Redis will stop accepting writes if RDB snapshots are enabled 30 # (at least one save point) and the latest background save failed. 31 # This will make the user aware (in a hard way) that data is not persisting 32 # on disk properly, otherwise chances are that no one will notice and some 33 # disaster will happen. 34 # 35 # If the background saving process will start working again Redis will 36 # automatically allow writes again. 37 # 38 # However if you have setup your proper monitoring of the Redis server 39 # and persistence, you may want to disable this feature so that Redis will 40 # continue to work as usual even if there are problems with disk, 41 # permissions, and so forth. 42 43 # 设值成yes表示当备份进程出错的时候,主进程就停止接收新的写入操作了,这样做是为了保护持久化的数据一致性的问题。如果自己的业务有完善的监控系统,可以禁止此项配置,否则开启。 44 stop-writes-on-bgsave-error yes 45 46 # Compress string objects using LZF when dump .rdb databases? 47 # For default that's set to 'yes' as it's almost always a win. 48 # If you want to save some CPU in the saving child set it to 'no' but 49 # the dataset will likely be bigger if you have compressible values or keys. 50 51 # 和rdb的压缩相关的,设置成yes就表示的是在备份的时候需要将rdb文件进行压缩后才去做保存。建议设置为no,因为redis本身是cpu密集型服务器,再开启压缩,会带来更多的cpu的消耗,相比硬盘成本,cpu更值钱。 52 rdbcompression yes
15、RDB的创建与载入,RDB文件可以通过两个命令来生成。
1)、SAVE,阻塞Redis的服务器进程,直到RDB文件被创建完毕。SAVE很少被使用,因为save操作是在主线程中保存快照的,由于Redis是用一个主线程来处理所有的请求的,这种方式会阻塞所有的客户端请求。
2)、BGSAVE,fork出一个子进程来创建RDB文件,记录接收BGSAVE当时的数据库状态,父进程继续处理接收到的命令,子进程完成文件的创建之后会发送信号给父进程即Redis的主进程,而于此同时,父进程处理命令的同时,通过轮询来接收子进程的信号,不阻塞服务器进程。BGSAVE指令是使用后台方式保存RDB文件的,调用此命令后会立刻返回OK返回码,Redis会产生一个子进程进行处理,并立刻恢复对客户端的服务,在客户端可以使用last save这个指令,产看操作是否成功,last save记录了上一次成功执行save或者bgsave命令的时间。
3)、可以使用java计时器或者quartz来定期调用redis的bgsave指令去备份rdb文件,并按照时间戳存储不同的rdb文件,作为redis某段时间的全量备份脚本。
16、自动化触发RDB持久化的方式。自动触发的场景主要有以下几点。
1)、根据redis.conf配置里面的save m n规则定时触发,使用的bgsave,这里面的save使用的是bgsave异步备份。
2)、主从复制的时候,主节点自动触发。从节点全量复制的时候,主节点发送RDB文件给从节点完成复制操作。主节点就会触发bgsave。
3)、执行Debug Reload。
4)、执行shutdown且没有开启AOF持久化。
17、Redis的GBSAVE的原理
1)、在执行了GBSAVE指令之后,首先回去检查当前子进程有没有正在执行的AOF/RDB子进程,有的话返回错误。这样做是为了防止子进程之间的竞争,也就意味着在执行GBSAVE期间呢,客户端发送的SAVE/GBSAVE命令会被服务器j拒绝执行,如果此时没有发生相关子进程,则会触发持久化。
2)、触发了持久化,就会调用redis源码里面的rdbSaveBackground方法执行fork系统调用。其实执行BGSAVE指令来生成RDB文件的时候,本质就是调用了操作系统的系统调用fork指令。
3)、系统调用fork(),就是用来创建进程的,而Linux下fork系统调用实现了Copy-on-Write写时复制。传统方式下fork函数在创建子进程的时候直接把所有的资源复制给子进程,这种实现方式简单,但是效率低下,而且复制的资源k可能对子进程毫无用处,linux为了降低创建子进程的成本,改进fork实现方式,当父进程创建子进程的时候,内核只为子进程创建虚拟空间,父子两个进程使用的是相同的物理空间,只有父子进程发生更改的时候才会为子进程分配独立的物理空间。
4)、改进的实现方式称为写时复制,Copy-on-Write(简称COW)是计算机程序设计l领域的优化策略,核心思想如果有多个调用者同时要求相同资源(如内存或者磁盘上的数据存储),它们会共同获取相同的指针指向相同的资源,直到某个调用者 试图修改资源的内容的时候,系统才会真正复制一份专用副本给该调用者,而其它调用者所见到的最初的资源仍然保持不变。
18、Redis如何做持久化?
答:AOF(append-only-file)持久化,通过保存Redis服务器所执行的写状态来记录数据库的。
1)、记录下除了查询以外的所有变更数据库状态的指令。AOF(append-only-file)持久化是备份数据库接收到的指令所有被写入AOF的命令都是以redis协议格式来保存的。
2)、在AOF中,以append的形式追加保存到aof文件中,以增量的形式。数据库会记录下所有变更数据库状态的指令,除了指定数据库的查询命令,其它的命令都是来自client的。
3)、注意,aof持久化默认是关闭的,可以通过修改refis.conf的配置appendonly no修改为appendonly yes即可,生成的文件名称是appendonly.aof。修改配置需要重启redis服务器。
4)、appendfsync everysec该配置主要用来配置aof文件的写入方式的,可以接收三个不同的参数分别是,always、everysec、no,always表示一旦缓存区的内容发生变化,就总是及时的将缓存区的内容写入到aof中,everysec是将缓存区的内容每隔一秒去写入到aof中,no是将写入aof的操作交由操作系统来决定,一般而言,为了提高效率,操作系统会将缓存区被填满才会开始同步数据到磁盘中。一般推荐everysec默认的方式,速度比较快,安全性比较高。
5)、AOF日志文件是一个纯追加的文件,就算遇到突然断电也可以尽最大权力去保证数据的无损。
19、AOF持久化,日志重写解决AOF文件大小不断增大的问题,Redis支持在不中断服务的情况下,在后台重建AOF文件,原理如下:
1)、首先调用fork(),创建一个子进程。
2)、子进程把新的AOF写到一个临时文件里面,新的AOF的重写是直接把当前内存的数据生成对应的命令,并不需要读取老的AOF文件进行分析或者合并,不依赖原来的AOF文件。
3)、主进程持续将新的变动同时写到内存和原来的AOF里面。这样即使写入失败,也能保证数据的安全。
4)、主进程获取子进程重写AOF的完成信号,往新AOF同步增量变动。
5)、使用新的AOF文件替换掉旧的AOF文件。
20、Redis数据的恢复,RDB和AOF文件共存情况下的恢复流程,就是一台服务器既有RDB文件,又有AOF文件。
1)、其实想要从这些文件中恢复数据,只要重启Redis即可。
21、RDB和AOF的优缺点?
1)、RDB优点,RDB本质上是一个内存快照,保存了创建RDB文件那个时间点的Redis全量数据,全量数据快照,文件小,创建恢复快。
2)、RDB缺点,无法保存最近一次快照之后的数据。
3)、AOF优点,AOF本质上是一份执行日志,保存所有被Redis更改的指令,可读性高,适合保存增量数据,数据不易丢失。
4)、AOF缺点,文件体积大,恢复时间长。
22、Redis4.0之后,推出了结合AOF和RDB的混合模式,并且作为默认的方式来使用。即使用RDB作为全量备份,AOF作为增量备份,来提升备份的效率。
1)、BGSAVE做镜像全量持久化,AOF做增量持久化,因为BGSAVE会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据的问题,需要AOF配合使用,在Redis重启的时候会使用BGSAVE持久化文件,重新构建内容,再使用AOF重放近期的操作指令,来实现完整恢复之前的状态。AOF和RDB的混合模式目前推荐的持久化方式。
2)、AOF重写机制,它其实y也是先写一份全量数据到AOF文件中,再追加增量,只不过全量数据是以redis命令格式写入的,那么是否可以先以RDB格式写入全量数据,再追加增量数据呢,这样既可以提高重新和恢复速度,也可以减少文件的大小,还同时可以保证数据的完整性,能够结合RDB和AOF的优点,AOF和RDB的混合模式正是在这种需求下诞生的。在此种方式下,子进程在做AOF重写的时候,会通过管道从父进程读取增量数据并缓存下来,那么在以RDB格式保存全量数据的时候,也会从管道读取数据,同时不会造成管道的阻塞,也就是说,AOF文件前半段是RDB格式的全量数据,而后半段是Redis命令格式的增量数据。