您的位置:首页 > 数据库 > Redis

NoSQL之Redis---主从复制

2016-07-14 08:39 543 查看
[不忘初心]

前文,我们简要翻译了Redis集群的内容,在搭建集群的过程中,我们经常使用的功能就是主从复制,冗余备份。本文我们就来介绍这部分的内容。好了,马上开始我们的正文部分吧。

---------------------------------------------------------------------------------------------------------------------------------------

       Redis的复制功能是非常简单易用的,配置为主从复制功能之后允许Redis的slave服务器复制出与master完全一致的服务器。以下是一些关于Redis复制功能的几个重要方面:

Redis使用异步复制。从2.8版本开始 ,slave服务器将以1s的频率想master服务器报告复制流的处理进度。
一个master服务器可以拥有多个slaves服务器。
slave服务器也能链接到其他slave服务器。除了链接到master服务器之外,slave服务器也能够和多个slave一起构成图状结构。
Redis的复制功能不会阻塞master服务器。话句话说,master服务器能够在向一个或者多个slave进行初始化复制时也能够持续的接受服务请求。
复制功能也不会阻塞slave服务器。当slave在进行初始化复制时,slave也能够处理老版本的数据服务,前提是你在Redis.conf文件中进行了相应的配置。另外,你也可以配置slave在与master断开时,让其返回错误。然而,在异步的初始化之后,旧数据必须被删除,并且新数据必须被加载到slave中。此时,slave将会被阻塞直到复制完成。
复制功能也可以被用于提升扩展性,使得,多个slave提供只读服务(如,繁重的SORT命令操作可以交给复述节点进行)。或者将复制功能单纯的用于数据冗余(datar redundancy)。
使用复制功能来使得master节点避免执行持久化操作。只需要关闭主服务器的持久化功能,然后由从服务器去执行持久化操作即可。特别的:在这种配置之下,请确保master服务器不会自动重启。

在master节点关闭持久化功能时,复制的安全性

       当在设置中开启Redis复制功能时,强烈建议的做法是在master节点中开启持久化功能,或者绝对不可能发生的是:因为延迟问题,将Redis实例被配置为避免自动重启。
       为了更好的理解为什么将关闭持久化功能的master节点配置为自动重启是非常危险的,我们看看下面在数据从master节点与其对应的所有slave节点移除时发生的失败类型:

假设A节点是master节点,B,C节点是其对应的副本。
A发生崩溃时,(配置为自动重启),重新启动了进程。然而因为持久化功能是关闭的,所以重启之后,该节点内的数据为空。
节点B,C将会从A进行复制,这时A中的数据集是空的,因此,这时,B,C将会彻底删除他们之前备份的数据。

       为了高可用性,引入了Redis的哨兵(sentinel),关闭了master节点上的持久化,并且两者都配置为自动重启,这种做法也是非常危险的。举个例子:master节点可能非常快的就完成了重启,以至于sentienl都没有感知到失败的发生,接下来就会发生和上面例子一样的结果。
       在任何时间,数据的安全都是非常重要的,因此,在使用复制功能时,master节点如果没有持久化功能,自动重启的功能是必须被禁止的。

复制功能的运行原理

       当你建立一个slave节点时,slave节点都会将master节点发送一个SYNC命令。无论是首次链接还是重新连接。
       当maste节点接受到SYNC命令时,master节点将会开始后台保存功能,并且开始缓存所有接收到的将会修改数据集的新命令。当后台保存任务完成时,master节点将数据文件传送给slave节点,slave节点将会把数据文件保存到本地磁盘,并且加载到内存中。紧接着,master节点将会把之前还存下的所有命令也传输给slave节点。这项功能将会按照指令流来完成并且是一个与Redis协议本身相同的格式。
       你可以通过telnet命令来亲自验证这个同步过程。首先,连接上一个正在处理命令请求的Redis服务器,然后发送SYNC命令,之后,你将看到大量的数据转移以及master节点上接收到的每一条命令将会被再次运行在telnet的会话中。
       当master节点与slave节点断开时,slave节点能够自动的重写链接到master节点上。如果master节点接收到多个同时进行复制请求时,master节点也只需要执行一次SYNC命令,就可以处理到所有的slave服务器的同步请求。
       当master节点与slave节点断线重连之后,一个完整的SYNC命令将会被执行。在2.8版本之后,slave节点将会根据主服务器的情况来选择是完整同步还是部分同步。

部分重新同步

       从2.8版本开始,master节点和slave节点通常情况下能够在断线重连的情况下进行断点续传的复制功能,而不需要进行完整复制过程。
这个特性需要master服务器在内存中创建一个复制流缓冲区。并且,master和slave需要都记录下一个复制偏移量和一个master节点ID,当网络连接断开时,slave节点将会重新连接,并且向master服务器请求继续执行原来的复制进程。
如果master节点ID与slave节点记录的ID保持一致,并且slave记录的复制偏移量指定的数据在master节点中仍然存在,那么复制流将会从断点继续传输。
       如果上面条件哪怕只有一条不满足的话,那就开始一个完整的复制过程。
       Redis2.8版本的部分重新同步的特性会用到一个新增的PSYNC命令,而之前的版本只有SYNC命令。不过,只要服务器版本高于2.8,其将会自动的选择使用PSYNC还是SYNC。

无磁盘复制

       通常情况下,一个完成的再同步复制请求需要创建一个RDB文件,并且把这个RDB文件从磁盘中加载到slave节点中。
       如果是在一个非常慢的磁盘上进行,这对于master节点是一个压力非常大的操作。从2.8.18版本开始,实验性的支持了无磁盘的复制。在该配置下,子进程能够直接通过网络连接发送RDB给slave,而不磁盘作为中间存储。

配置

配置一个slave服务器是非常简单,只需要在配置文件中增加一下的这一张就行:
slaveof 127.0.0.1 6379
当然,你需要将代码中的IP与端口,替换成你自己的master服务器的IP与端口。另外的一种方法就是:使用SLAVEOF命令,输入master服务器的IP和端口,然后,master节点就会开始同步。
127.0.0.1:6379> SLAVEOF 127.0.0.1 6379
OK
这里也有一些专门为master节点执行部分重新同步的过程中调整内存中的复制存储的参数。
无磁盘复制功能可以使用repl-diskless-sync参数开启。为了在第一个slave节点到达之后等待更多slave节点到达,延迟传输动作,可以被repl-diskless-sync-delay参数控制。更多内容请在redis.conf文件的分布式配置中查看。

只读slave服务器

       从2.6版本开始,slave节点只读模式,并且也是默认的。这个模式也是可以被redis.conf文件中的slave-read-only控制的,也可以通过CONFIG SET命令来设置。
       只读模式下的slave节点将会拒绝一切写命令,因此,也不会出现因为错误操作在slave中写入数据的可能。但是,这不是说,我们可以将一个slave节点暴露给互联网或者不信任的网络客户端,因为,管理类的命令如DEBUG,CONFIG命令仍然是可以使用的。但是,我们可以禁用redis.conf文件中的rename-command命令,来提升只读slave节点的安全性。
       你可能会好奇,为什么可能出现重新覆盖只读配置和slave节点会成为写操作的目标。尽管这些写操作在slave节点与master节点再同步或者slave重新启动时将会被丢弃,但是,在可写的slave节点中,这里仍有对所存储的一些临时数据进行合法的使用。然而,在将来,这可能将会被移除。

slave节点的授权配置

如果master节点通过requirepass设置了访问密码,在配置slave节点中也需要配置相应的password,这样才能进行所有的同步操作。
对于一个正在运行的slave可以使用下面的命令:
config set masterauth <password>
要永久的设置这个密码,那么可以将它加入到配置文件中:
masterauth <password>

master服务器只有在只要N个slave服务器的条件下,才执行写操作

       从 Redis 2.8 开始, 为了保证数据的安全性, 可以通过配置, 让主服务器只在有至少 N 个当前已连接从服务器的情况下, 才执行写命令。

不过, 因为 Redis 使用异步复制, 所以主服务器发送的写数据并不一定会被从服务器接收到, 因此, 数据丢失的可能性仍然是存在的。

以下是这个特性的运作原理:

slave服务器每秒ping一次master服务器,并且报告复制流的处理情况。
master服务器将会记录各个slave服务器最后一次发送ping的时间。
用户可以配置网络延迟的最大时间min-slaves-max-lag(M),以及执行写操作所需的最少slave服务器数量min-slaves-to-write(N).

如果至少存在N个slave服务器,并且延迟都小于M秒,那么写操作将被接受。
       你可以将这个特性看作是CAP理论中的C的宽松条件,尽管不能保证写操作的持久性,但起码丢失数据的窗口会被严格限制在指定的描述中。
如果这些条件没有被满足,master节点将会返回一个错误,并且写操作将会被拒绝。
以下是这个特性的两个选项和所需参数:

min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>

详细的信息可以参考Redis源码中附带的redis.conf示例文件

对带有超期时间key的复制策略

       Redis的超时配置允许key拥有生效的有限时间。该特性以来于Redis实例能够计算有效时间,然而,Redis的slave节点准确的复制这些带有超时时间的key,即使当这些key被lua脚本改变了。
       为了实现这样的特性,Redis不能依靠master与slave之间同步时间的能力,因为,这个同步问题是无法解决的,并且将会导致竞争条件的产生和数据集的不一致问题,因此,Redis使用了下面三种策略实现让带有过期时间的key能够被使用:

slave不会将key过期,而是等待master节点将其过期。当master节点将一个key的时间过期之后,使用DEL命令,通知所有slave节点删除该key。
然而,由于是master驱动过期时间的, 所以在某些时刻,slave仍然有可能保留了一些实际上已经过期的key,原因是master节点没有及时的提供DEL命令。为了处理slave节点使用其正确的时间来报告一个不存在的key,只向一些不违反数据一致性的读操作提供,(因为来自master节点的新命令将会到达)。通过这种方式,slave节点避免了返回一个实际上已经过期的,但未删除的key。
在Lua脚本执行中,将不会执行key的超时设置。在Lua脚本执行过程中,概念上说master上的时间是停止的,因此,在一个给定的脚本执行期的完整时间内一个给定的key将会只能是存在或者不存在。这阻止了key在执行脚本过程中发生超时现象,并且在为了发送相同的脚本到slave中也是十分必要的,其保证了对数据集产生相同的影响。

正如预期的那样,一旦发生故障转移,slave变为master,其将开始独立的判断key的过期时间,而不是向之前的master询问。
-------------------------------------------------------------------------------------------------------------------------------------
至此,NoSQL之Redis---主从复制


参考资料:

官方文档:http://redis.io/topics/replication

其他资料:http://doc.redisfans.com/topic/cluster-tutorial.html

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: