Python--Redis实战:第四章:数据安全与性能保障:第4节:复制

上一篇文章: Python--Redis实战:第四章:数据安全与性能保障:第3节:AOF持久化
下一篇文章: Python--Redis实战:第四章:数据安全与性能保障:第5节:处理系统故障

对于有扩展平台以适应更高负载经验的工程师和管理员来讲,复制(replication)是不可或缺的。复制可让其余服务器拥有一个不断地更新的数据副本,从而使得拥有数据副本的服务器能够用于处理客户端发送的读请求,。关系数据库一般会使用一个主服务器(数据库

master)向多个从服务器(slave)发送更新,并使用从服务器来处理全部读请求。Redis也采用了一样的方法来实现本身的复制特性,并将其用做扩展性能的一种手段。本节将对Redis的复制配置选项进行讨论,并说明Redis在进行复制的各个步骤。segmentfault

尽管Redis的性能的很是优秀,但它也会赶上没办法快速的处理请求的状况,特别是在对集合和有序集合进行操做的时候,涉及的元素可能会有上万个甚至上百万个,在这种状况下,执行操做所花费的时间可能须要以秒来进行计算,而不是毫秒或者微妙。但即便一个命令值须要花费10毫秒就能完成,单个Redis实例1秒也只能处理100个命令。安全

sunionstore命令的性能:

做为对Redis性能的一个参考,在主频为2.4GHz的英特尔酷睿2处理器上,对两个分别包含10 000个元素的集合执行sunionstore命令并产生一个包含20 000个元素的结果集合,须要花费Redis七八毫秒的时间。服务器

在须要扩展读请求的时候,或者在须要写入临时数据的时候,用户能够经过设置额外的Redis【从服务器】来保存数据集的副本。在接受到主服务器发送的数据初始副本(initial copy of data)以后,客户端每次向【主服务器】进行写入时,【从服务器】都会实时地获得更新。在部署好主从服务器以后,客户端就能够向任意一个服务器发送读请求了,而没必要再像以前同样,老是把每一个读请求都发送给主服务器(客户端一般会随机地选择使用哪一个从服务器,从而将负载平均分配到各个从服务器上)。网络

接下来将介绍配置Redis主从服务器的方法,并说明Redis在整个复制过程当中所作的各项操做。app

对Redis的复制相关选项进行配置

以前介绍过,当从服务器链接主服务器的时候,主服务器会执行bgsave操做。所以为了正确的使用复制特性,用户须要保证主服务已经正确的配置了dir选项和dbfilename选项,而且这两个选项所指示的路径和文件对于Redis进程来讲都是可写的。ide

尽管有多个不一样的选项能够控制从服务器自身的行为,但开启从服务器所必须的选项只有slaveof一个。若是用户在启动Redis服务器的时候,指定了一个包含slaveof host port选项的配置文件,那么Redis服务器将根据该选项给定的IP地址和端口号来链接主服务器。对于一个正在运行的Redis服务器,用户能够经过发送slaveof no one命令来让服务器终止复制操做,再也不接受主服务器的数据更新,也能够经过发送slaveof host port命令来让服务器开始复制一个新的主服务器。函数

开启Redis的主从复制特性并不须要进行太多的配置,但了解Redis服务器是如何变成主服务器或者从服务器的,对于咱们来讲将是很是有用和有趣的过程。性能

Redis复制的启动过程

上面曾将说过,从服务器在链接一个主服务器的时候,主服务器会建立一个快照文件并将其发送至从服务器,但这只是主从复制执行的其中一步,下表完整的列出了当从服务器链接主服务器时,主从服务器执行的全部操做:ui

步骤 主服务器操做 从服务器操做
1 (等待命令进入) 链接(或者重链接)主服务,发送sync命令。
2 开始执行bgsave,并使用缓冲区记录bgsave以后执行的全部写命令 根据配置选项来决定是继续使用现有的数据(若是有的话)来处理客户端的命令请求,仍是向发送请求的客户端返回错误。
3 bgsave执行完毕,向从服务器发送快照文件,并在发送期间继续使用缓冲区记录被执行的写命令 丢弃全部旧数据(若是有的话),开始载入主服务器发来的快照文件。
4 快照文件发送完毕,开始向从服务器发送存储在缓冲区里面的写命令。 完成对快照文件的解释操做,像往常同样开始接受命令请求。
5 缓冲区存储的写命令发送完毕;从如今开始,每执行一个写命令,就向从服务器发送相应的写命令。 执行主服务器发送的全部存储在缓冲区里面的写命令;并从如今开始,接受并执行主服务传来的每一个写命令。

Redis在复制进行期间也会尽量地处理接受到的命令请求,可是,若是主从服务器之间的网络带宽不足,或者主服务器没有足够的内存来建立子进程和建立记录写命令的缓冲区,那么Redis处理命令请求的效率会受到影响。所以,尽管这并非必需的,但在实际中华最好仍是让主服务器只使用50%~65%的内存,预留30%~45%内存用于执行bgsave命令和建立记录写命令的缓冲区。

设置从服务器的步骤很是简单,用户既能够经过配置选项slaveof host port来将一个Redis服务器设置为从服务器,又能够经过向运行中的Redis服务器发送slaveof命令来将其设置为从服务。若是用户使用的是slaveof配置选项,那么Redis在启动时首先载入当前可用的任何快照问价或者AOF文件,而后链接主服务并执行上表的复制过程。若是用户使用的是slaveof命令,那么Redis会当即尝试链接主服务器,并在链接成功后,开始上表所示的复制过程。

从服务器在运行同步时,会清空本身的全部数据:

由于有些用户在第一次使用从服务器时会忘记这件事,因此在这里要特别提醒一下:从服务器在于主服务器进行初始链接时,数据库中原有的全部数据将丢失,并被替换成主服务器发送来的数据。


警告:Redis不支持主主复制:

由于Redis容许用户在服务器启动以后使用slaveof命令来设置从服务器选项,因此可能会有读者误觉得能够经过将两个Redis实例互相设置为对方的主服务器来实现多主复制,遗憾的是,这种作法是行不通的:被互相设置为主服务器的两个Redis实例只会持续的占用大量处理器资环并持续不断的尝试与对方进行通讯,根据客户端连接的服务器的不一样,客户端的请求可能会获得不一致的数据或者彻底得不到数据。

当多个从服务器尝试链接同一个主服务器的时候,就会出现下表所示的两种状况中的一种:

当有新的从服务器链接主服务时 主服务器的操做
当上表步骤3还没有执行 全部从服务器都会接受到相同的快照文件和相同的缓冲区写命令
当上表步骤3正在执行或者已经执行完毕 当主服务器与较早进行连的从服务器执行完复制所需的5个步骤以后,主服务会与新链接的从服务器执行一次进的步骤1至步骤5.

在大部分状况下,Redis都会尽量地减小复制所需的工做,然而,若是从服务器链接主服务器的时间并不凑巧,那么主服务器就须要多作一些额外的工做,。另外一方面,当多个从服务器同时链接主服务器的时候,同步多个主服务器所占用的宽带可能会使得其余命令请求难以传递给主服务器,与主服务器位于同一网络中的其余硬件的网速可能也会所以而下降。

主从链

有些用户发现,建立多个从服务器可能或形成网络不可用:当复制须要经过互联网进行或者须要在不一样数据中心之间进行时,尤其如此。由于Redis的主服务和从服务器并无特别不一样的地方,因此从服务器也能够拥有本身的从服务器,并由此造成主从链。

从服务器对从服务器进行复制在操做上和那个服务器对主服务器进行复制的惟一区别在于,若是从服务器X拥有从服务器Y,那么当从服务器X在执行上节复制步骤的步骤4时,它将断开与从服务器Y的链接,致使从服务器Y须要从新链接并从新同步。

当【读请求】的重要性明显高于【写请求】的重要性,而且读请求的数量远远超出一台Redis服务器能够处理的范围时,用户就须要添加新的从服务器来处理【读请求】。随着负载不断上升,主服务器可能会没法快速地更新全部从服务器,或者由于从新链接和从新同步从服务器而致使系统超载。为了缓解这个问题,用户能够建立一个由Redis主从节点组成的中间层来分担主服务器的复制工做。以下图所示:

图片描述

一个Redis主从复制树示例,树的中层有3个帮助开展复制工做的服务器,底层与9个从服务器。

尽管主从服务器之间并不必定要像上图那样组成一个树状结构,但记住并理解这种树状结构对于Redis复制来讲是可行的而且是合理的,有主于读者理解以后的内容。AOF持久化的同步选项能够控制数据丢失的时间长度:经过将每一个写命令同步到硬盘里面,用户几乎能够不损失任何数据(除非系统崩溃或者硬盘驱动器损坏),但这种作法会对服务器的性能形成影响;另外一方面,若是用户将同步的频率设置为每秒一次,那么服务器的性能将回到正常水平,但故障可能会形成1秒的数据损失。经过同时使用复制和AOF持久化,咱们能够将数据持久化到多台服务器上面。

为了将数据保存到多台服务器上面,用户首先须要为主服务器设置多个从服务器,而后对每一个从服务设置appendonly yes选项和sppendonly everysec选项(若是有须要得我话,也能够对主服务器进行相同的设置),这样的话,用户就可让多台服务器以每秒1次的频率将数据同步到硬盘上了,但这还只是第一步:由于用户还必须等待主服务器发送的写命令到达从服务器,而且在执行后续操做以前,检查数据是否已经被同步到硬盘里面。

检查硬盘写入

为了验证主服务器是否已经将写数据发送至从服务器,用户须要在向主服务器写入真正的数据以后,再向从服务器写入一个惟一的虚构值,而后经过验证虚构值是否存在于从服务器来判断写数据是否已经到达从服务器,这个操做很容易就能够实现。另外一方面,判断数据是否已经被保存到硬盘里面则要困难的多。对于每秒同步一次AOF文件的Redis服务器来讲,用户老是能够经过等待1秒来确保数据已经被保存到硬盘里面,但更节约时间的作法是,检查info命令的输出结果中aof_pending_bio_fsync属性的值是否为0,若是是的话,那么就表示服务器已经将已知的全部数据都保存到硬盘里面了。在向主服务器写入数据以后,用户能够将主服务器和从服务器的链接做为参数,调用下面函数来能自动进行上述的检查操做。

import time
import uuid


def wait_for_sync(mconn,sconn):
    identifier=str(uuid.uuid4())
    #将令牌添加至主服务器
    mconn.zadd('sync:wait',identifier,time.time())

    #若是有必要的话,等待从服务器完成同步
    while not sconn.info()['master_lin_status']!='up':
        time.sleep(.001)

    #等待从服务器接收数据更新
    while not sconn.zscore('sync:wait',identifier):
        time.sleep(.001)

    deadline=time.time()+1.01
    #最多只等待一秒
    while time.time()<deadline:
        #检查数据更新是否已经被同步到了硬盘
        if sconn.info()['aof_pending_bio_fsync']==0:
            break
    #清理刚刚建立的新令牌以及以前可能留下的旧令牌
    mconn.zrem('sync:wait',identifier)
    mconn.zremrangebyscore('sync:wait',0,time.time()-900)
info命令中的其余信息:

info命令提供了大量的与Redis服务器当前状态相关的信息,好比内存占用量、客户端链接数、每一个数据库包含的键的数量、上一次建立快照文件以后执行的命令数量、等待。总的来讲,info命令对于了解Redis服务器的综合状态很是有帮助,网上有不少资源对info命令进行了详细的介绍。

为了确保操做能够正确执行,上面函数会首先确认从服务器已经链接上主服务器,而后检查本身添加到等待同步有序集合里面的值是否已经存在于从服务器。在发现值已经存在于从服务器以后,函数会检查从服务器写入缓冲区的状态,并在一秒以内,等待从服务器将缓冲区中的全部数据写入硬盘里面。虽然函数最多会花费1秒来等待同步完成,但实际上大部分同步都会在很短的时间完成。最后,在确认数据已经被保存到硬盘以后,函数会执行一些清理操做。

经过同步使用复制和AOF持久化,用户能够加强Redis对于系统崩溃的抵抗能力。

上一篇文章: Python--Redis实战:第四章:数据安全与性能保障:第3节:AOF持久化
下一篇文章: Python--Redis实战:第四章:数据安全与性能保障:第5节:处理系统故障
相关文章
相关标签/搜索