本文我们将了解Redis使用中两个非常重要的机制:Reids持久化和主从复制。图片来自Unsplash什么是Redis持久化?Redis是一个键值内存数据库(NoSQL),数据存储在内存中。在处理客户端请求时,所有操作都在内存中进行,如下图:问题出在哪里?其实稍微有点计算机基础的人都知道,只要服务器关机(各种原因引起),内存中保存的数据就会消失。服务器关闭不仅会导致数据消失,Redis服务器守护进程也会退出,内存中的数据也会消失。对于只使用Redis作为缓存的项目,数据丢失可能问题不大,重新从数据源加载数据即可。但如果直接将用户提交的业务数据存储在Redis中,将Redis作为数据库,将重要的业务数据存储在其中,那么Redis内存数据丢失的影响可能是毁灭性的。为了避免数据在内存中丢失,Redis提供了对持久化的支持。我们可以选择不同的方式将数据从内存保存到硬盘,从而实现数据的持久化。Redis提供了两种不同的数据持久化方式,RDB和AOF。下面就来详细介绍一下这几种不同的持久化方式。RDBRDB是一种快照存储持久化方式。具体来说,就是将Redis在某一时刻的内存数据保存到硬盘上的一个文件中。默认保存的文件名为dump.rdb,当Redis服务器启动时,会重新加载dump.rdb文件的数据恢复到内存中。①启用RDB持久化模式启用RDB持久化模式非常简单。客户端可以向Redis服务器发送Save或Bgsave命令让服务器生成RDB文件,也可以通过服务器配置文件指定触发RDB的条件。保存命令:是一个同步操作。#同步数据到磁盘>save当客户端向服务器发送Save命令请求进行持久化时,服务器会在Save命令后阻塞其他客户端请求,直到数据同步完成。如果数据量太大,同步数据的时间会比较长,这期间Redis服务器是收不到其他请求的,所以生产环境最好不要使用Save命令。Bgsave:与Save命令不同,Bgsave命令是一个异步操作。#将数据集异步保存到磁盘>bgsave当客户端发送服务发出Bgsave命令时,Redis服务器的主进程会fork一个子进程来解决数据同步问题。将数据保存到RDB文件后,子进程就会退出。因此,与Save命令相比,Redis服务器在处理Bgsave时,使用了子线程进行IO写入。主进程仍然可以接收其他请求,但是Forks子进程是同步的,所以当Forks子进程时,它不能接收其他请求。这意味着如果分叉子进程花费的时间太长(通常非常快),Bgsave命令仍会阻止其他客户端请求。服务器配置自动触发:除了通过客户端发送命令外,还有一种方式,就是在Redis配置文件中的Save中指定触发RDB持久化的条件,比如【多少次内达到了多少次写操作seconds]开启RDB数据Synchronize。例如,我们可以在配置文件redis.conf中指定如下选项:至少1个写命令在#900ssave9001至少10个写命令在#300ssave30010至少10000个写命令在#60ssave6010000启动时加载服务器配置文件。#启动服务器加载配置文件redis-serverredis.conf这种通过服务器配置文件触发RDB的方法与Bgsave命令类似。当满足触发条件时,会fork一个子进程进行数据同步。但是这种方式最好不要触发RDB持久化,因为如果触发时间设置的太短,容易频繁写入RDB文件,影响服务器性能,时间设置的太长,会导致数据丢失损失。②RDB文件服务器端生成RDB文件有3种方式,无论是主进程还是子进程生成,过程如下:生成临时RDB文件,写入数据。完成数据写入,将官方RDB文件替换为临时文件。删除原始数据库文件。RDB默认生成的文件名为dump.rdb。当然,我可以通过配置文件进行更详细的配置。例如单机下启动多个Redis服务器进程时,可以通过端口号配置不同的rdb名称,如下:#是否压缩rdb文件rdbcompressionyes#rdb文件名dbfilenameredis-6379.rdb#rdb文件保存目录dir~/redis/RDB的几个优点:与AOF方式相比,通过RDB文件恢复数据速度更快。RDB文件非常紧凑,适合数据备份。通过RDB备份数据,由于使用了subprocessgeneration,对Redis服务器的性能影响很小。RDB的几个缺点:如果服务器宕机,使用RDB会导致一定时间内的数据丢失。比如我们设置10分钟同步一次或者5分钟达到1000次写入时同步一次,那么如果还没有达到触发条件服务器宕机,这个时间段的数据就会丢失。使用Save命令会导致服务器阻塞,数据同步完成后才能接收后续请求。使用Bgsave命令fork子进程时,如果数据量过大,fork进程也会被阻塞。另外,fork子进程会消耗内存。说完AOF中的RDB,再说说Redis的另一种持久化方式:AOF(Append-onlyfile)。与RDB在某个时刻存储快照不同,AOF持久化方式会记录客户端对服务端的每一次写操作命令,并将这些写操作追加保存到Redis协议中后缀为AOF的文件末尾。当Redis服务器重启时,会加载并运行AOF文件的命令,达到恢复数据的目的。①开启AOF持久化模式Redis默认是不开启AOF持久化模式的,我们可以在配置文件中开启并进行更详细的配置,如下redis.conf文件:#Openaofmechanismappendonlyyes#aoffilenameappendfilename"appendonly.aof"#写策略,always表示每次写操作都保存到aof文件中,也可以是everysec或者noappendfsyncalways#默认不重写aof文件no-appendfsync-on-rewriteno#保存目录dir~/redis/②三在上面的配置文件中,我们可以通过appendfsync选项来指定写入策略。共有三个选项:appendfsyncalways#appendfsynceverysec#appendfsyncnoalways:客户端每次写操作都保存到AOF文件中,非常安全。但是每次写操作都有一次IO操作,所以也很慢。everysec:appendfsync默认的写入策略,AOF文件每秒写入一次,因此最多可能丢失1s的数据。no:Redis服务器不负责写入AOF,而是由操作系统来处理何时写入AOF文件。更快,但也是最不安全的选择,不推荐。③AOF文件重写AOF将客户端的每一次写操作都追加到AOF文件的末尾,比如对一个Key多次执行Incr命令。这时候AOF将每条命令都保存到AOF文件中,AOF文件就会变得很大。incrnum1incrnum2incrnum3incrnum4incrnum5incrnum6...incrnum100000AOF文件太大,加载AOF文件恢复数据时会很慢。为了解决这个问题,Redis支持AOF文件重写。通过重写AOF,您可以生成最小的命令集来恢复当前数据。比如上面的例子有那么多条命令,可以改写为:setnum100000AOF文件是一个二进制文件,不直接保存每条命令,使用Redis自带的格式,上面只是为了演示。两种重写方式:通过redis.conf配置文件中的no-appendfsync-on-rewrite选项,可以设置是否开启重写。该方法每次fsync都会被重写,影响服务器性能,所以默认值为no,不推荐。#默认不重写aof文件no-appendfsync-on-rewriteno客户端向服务端发送bgrewriteaof命令,服务端也可以进行AOF重写。#让服务器异步重写appendaof文件命令>bgrewriteaofAOF重写的方式也是异步操作,即如果要写入AOF文件,Redis主进程会Fork一个子进程来处理,如图下图:重写AOF文件的好处:压缩AOF文件,减少磁盘占用。将AOF命令压缩成最小命令集,加速数据恢复。③AOF文件损坏。在写入AOF日志文件时,如果Redis服务器宕机,AOF日志文件会出现格式错误。当Redis服务器重启后,Redis服务器会拒绝加载AOF文件。您可以通过以下步骤修复AOF并恢复数据:备份当前AOF文件,以防万一。使用redis-check-aof命令修复AOF文件。命令格式如下:#Repairaoflogfile$redis-check-aof-fixfile.aof重启Redis服务器,加载修复后的AOF文件,恢复数据。AOF的优点:AOF只是追加日志文件,因此对服务器性能影响较小,比RDB速度快,消耗内存少。AOF的缺点:AOF产生的日志文件太大,即使用AFO重写,文件体积还是很大。恢复数据比RDB慢。选择RDB还是AOF?通过上面的介绍,我们了解了RDB和AOF的优缺点。如何选择?通过下面的表示,我们可以从几个方面比较RDB和AOF。应用的时候,根据自己的实际需求,选择RDB或者AOF。其实如果你希望数据足够安全,可以开启这两种方式,但是两种持久化方式同时进行IO操作,会严重影响服务器的性能,所以有时候不得不做出选择.当同时开启RDB和AOF时,Redis会优先使用AOF日志来恢复数据,因为AOF文件比RDB文件更完整。总结:上面提到了很多关于Redis持久化机制的知识。其实如果只是把Redis当做缓存服务器,根本不需要考虑持久化。然而,在当今的大多数服务器架构中,Redis不仅仅扮演着缓存服务器的角色,同时也作为数据库来存储我们的业务数据。这时候我们就需要了解Redis持久化策略的区别和选择。什么是Reids主从复制?以上,我们了解了Redis的两种不同的持久化方式。Redis服务器通过持久化将Redis内存持久化到硬盘。当Redis宕机时,当我们重启Redis服务器时,我们可以从RDB文件或者AOF文件中恢复内存中的数据。但是,持久化数据仍然只在一台机器上。因此,当硬件出现故障,如主板或CPU坏了,此时无法重启服务器。当服务器出现故障时,有什么办法可以保证数据的安全?或者你可以快速恢复数据呢?为此,我们需要了解Redis的另一种机制:主从复制。Redis的主从复制机制是指从服务器(Slave)可以准确的复制主服务器(Master)的数据,如下图:上图是一个Master服务器和一个Slave服务器的情况.事实上,一个Master服务器也可以对应多个Slave服务器,如下图所示:此外,Slave服务器也可以有自己的Slave服务器,这样的服务器称为Sub-Slave。这些Sub-Slave最终的数据也可以通过主从复制的方式与Master保持一致,如下图所示:主从复制的方式和工作原理Redis主从复制是异步复制,分为分为两个方面:一个是Master服务器在给Slave同步数据的时候是异步的,所以Master服务器在这里仍然可以接收其他请求。一是Slave在接收同步数据时也是异步的。①复制方式Redis主从复制分为以下三种方式:当Master服务器和Slave服务器正常连接时,Master服务器会向Slave服务器发送一个数据命令流,将自己的数据变化复制到Slave服务器。当Master服务器由于各种原因与Slave服务器断开连接时,Slave服务器在重新连接到Master服务器时会尝试重新获取断开连接后未同步的数据,即部分同步,或部分复制。如果无法实现部分同步(例如初始同步),则将请求完全同步。此时Master服务器会将自己的RDB文件发送给Slave服务器进行数据同步,同步时记录其他写入,再发送给Slave服务器。为了达到完全同步的目的,这种方式称为全复制。②工作原理主服务器会记录一个伪随机字符串ReplicationId来标识当前数据集的版本,同时也会记录数据集的偏移量。不管Master是否配置Slave,ReplicationId和Offset总是会被记录下来,并且成对存在。我们可以通过以下命令查看ReplicationId和Offset:>infopliaction通过redis-cli在Master或Slave服务器上执行该命令会打印出类似如下的信息(不同服务器的数据和打印信息不同):connected_slaves:1slave0:ip=127.0.0.1,port=6380,state=online,offset=9472,lag=1master_replid:2cbd65f847c0acd608c69f93010dcaa6dd551ceemaster_repl_offset:9472Master正常连接Slave时,Slave的PSYNC命令发送旧Master的Replicationid和Offset自己记录给大师。Master会计算与Slave的数据偏移量,并将缓冲区中的偏移量同步给Slave。此时Master和Slave的数据是一致的。而如果Slave引用的Replication太旧,Master和Slave之间的数据差异太大,Master和Slave会使用fullreplication进行数据同步。配置主从复制Redis的主从配置非常简单。我们可以使用两种方法来配置主从服务器。这个时候我们先假设Redis的Master服务器地址是192.168.0.101。客户端发送同步命令:#Configurethemasterservertoclientsaveof192.168.1.1016379Slaveserver:这里Slave的redis.conf可以通过saveof选项指定Master服务器,如下:slaveof192.168.1.1016379通过以上两种方式Configuration,Master服务器和Slave服务器就可以开始数据同步了。Master需要验证:以上配置是Master服务器没有设置密码的情况。如果Master设置了密码,可以在Slave服务器连接的redis-cli上执行如下命令:#
