首页  »   NoSQL

NoSQL之Redis-主从复制

网友分享于:2013-07-17  浏览:0次
NoSQL之Redis---主从复制

[不忘初心]

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

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

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

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

       当在设置中开启Redis复制功能时,强烈建议的做法是在master节点中开启持久化功能,或者绝对不可能发生的是:因为延迟问题,将Redis实例被配置为避免自动重启。
       为了更好的理解为什么将关闭持久化功能的master节点配置为自动重启是非常危险的,我们看看下面在数据从master节点与其对应的所有slave节点移除时发生的失败类型:
       为了高可用性,引入了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 使用异步复制, 所以主服务器发送的写数据并不一定会被从服务器接收到, 因此, 数据丢失的可能性仍然是存在的。
以下是这个特性的运作原理:
如果至少存在N个slave服务器,并且延迟都小于M秒,那么写操作将被接受。
       你可以将这个特性看作是CAP理论中的C的宽松条件,尽管不能保证写操作的持久性,但起码丢失数据的窗口会被严格限制在指定的描述中。
如果这些条件没有被满足,master节点将会返回一个错误,并且写操作将会被拒绝。
以下是这个特性的两个选项和所需参数:
详细的信息可以参考Redis源码中附带的redis.conf示例文件

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

       Redis的超时配置允许key拥有生效的有限时间。该特性以来于Redis实例能够计算有效时间,然而,Redis的slave节点准确的复制这些带有超时时间的key,即使当这些key被lua脚本改变了。
       为了实现这样的特性,Redis不能依靠master与slave之间同步时间的能力,因为,这个同步问题是无法解决的,并且将会导致竞争条件的产生和数据集的不一致问题,因此,Redis使用了下面三种策略实现让带有过期时间的key能够被使用:
  1. slave不会将key过期,而是等待master节点将其过期。当master节点将一个key的时间过期之后,使用DEL命令,通知所有slave节点删除该key。
  2. 然而,由于是master驱动过期时间的, 所以在某些时刻,slave仍然有可能保留了一些实际上已经过期的key,原因是master节点没有及时的提供DEL命令。为了处理slave节点使用其正确的时间来报告一个不存在的key,只向一些不违反数据一致性的读操作提供,(因为来自master节点的新命令将会到达)。通过这种方式,slave节点避免了返回一个实际上已经过期的,但未删除的key。
  3. 在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



相关解决方案

最新解决方案