Redis 3.0中文官方文档翻译计划(21) ——集群(下)

Redis 3.0中文官方文档翻译计划(21)
——集群(下)


    手动故障转移(Manual failover)
    有时候在主服务器事实上没有任何故障的情况下强制一次故障转移是很有用的。例如,为了升级主服务器节点中的一个进程,可以对其进行故障转移使其变为一个从服务器,这样最小化了对可用性的影响。
    Redis集群支持使用CLUSTER FAILOVER命令来手动故障转移,必须在你想进行故障转移的主服务的其中一个从服务器上执行。
    手动故障转移很特别,和真正因为主服务器失效而产生的故障转移要更安全,因为采取了避免过程中数据丢失的方式,仅当系统确认新的主服务器处理完了旧的主服务器的复制流时,客户端才从原主服务器切换到新主服务器。
    下面是当你手动故障转移时你从从服务器日志中看到的内容:
# Manual failover user request accepted.
# Received replication offset for paused master manual failover: 347540
# All master replication stream processed, manual failover can start.
# Start of election delayed for 0 milliseconds (rank #0, offset 347540).
# Starting a failover election for epoch 7545.
# Failover election won: I'm the new master.

    基本上,连接到我们正在故障转移的主服务器的客户端停止了。与此同时,主服务器发送复制偏移量给从服务器,等待到达这个偏移量。当复制偏移量到达以后,故障转移就开始了,旧的主服务器被通知切换配置。当客户端在旧主服务器上解除阻塞时,就被重定向到新的主服务器。

    添加新节点(Adding a new node)
    添加一个新节点的过程基本上就是,添加一个空节点,然后,如果是作为主节点则移动一些数据进去,如果是从节点则其作为某个节点的副本。
    两种情况我们都会讨论,先从添加一个新的主服务器实例开始。
    两种情况下,第一步要完成的都是添加一个空节点。
    我们使用与其他节点相同的配置(端口号除外)在7006端口(我们已存在的6个节点已经使用了从7000到7005的端口)上开启一个新的节点,那么为了与我们之前的节点布局一致,你得这么做:
  • 在你的终端程序中开启一个新的标签窗口。
  • 进入cluster-test目录。
  • 创建一个名为7006的目录。
  • 在里面创建一个redis.conf的文件,类似于其它节点使用的文件,但是使用7006作为端口号。
  • 最后使用../redis-server ./redis.conf启动服务器。

    此时服务器已经在运行中了。
    现在我们可以像通常一样使用redis-trib来添加节点到已存在的集群中。
./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000

    你可以看到,我使用了addnode命令,指定新的节点地址为第一个参数,集群中一个随机存在的节点的地址作为第二个参数。
    实际上redis-trib在这里对我们只有很少的帮助,只是发送了一个CLUSTER MEET消息到节点,这些也可以手动完成。但是redis-trib也在操作之前检查了集群的状态,所以即便你知道内部是如何工作的,一直通过redis-trib来执行集群操作也是一个不错的主意。
    现在,我们可以连接到这个新的节点,看看它是否真的加入到了集群中:
redis 127.0.0.1:7006> cluster nodes
3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 127.0.0.1:7001 master - 0 1385543178575 0 connected 5960-10921
3fc783611028b1707fd65345e763befb36454d73 127.0.0.1:7004 slave 3e3a6cb0d9a9a87168e266b0a0b24026c0aae3f0 0 1385543179583 0 connected
f093c80dde814da99c5cf72a7dd01590792b783b :0 myself,master - 0 0 0 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543178072 3 connected
a211e242fc6b22a9427fed61285e85892fa04e08 127.0.0.1:7003 slave 97a3a64667477371c4479320d683e4c8db5858b1 0 1385543178575 0 connected
97a3a64667477371c4479320d683e4c8db5858b1 127.0.0.1:7000 master - 0 1385543179080 0 connected 0-5959 10922-11422
3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7005 master - 0 1385543177568 3 connected 11423-16383

    注意,因为这个节点已经连接到集群了,所以也已经可以正确地重定向客户端查询,简而言之,这个节点已经是集群的一部分了。但是它比其他主节点有两个特殊之处:
  • 因为没有分配哈希槽所以没有数据。
  • 因为这个主服务器没有分配哈希槽,所以当有从服务器要变成主服务器时不能参与选举过程。

    现在可以使用redis-trib的重新分片特性来给这个节点赋予哈希槽了。基本上没有必现展示这个了,因为我们已经在之前的小节中展示过了,没有什么不同,只是以空节点为目标的一次重分片。

    添加副本节点(Adding a new node as a replica)
    添加一个新副本可以有两种方式。显而易见的一种方式是再次使用redis-trib,但是要使用—slave选项,像这样:
./redis-trib.rb add-node --slave 127.0.0.1:7006 127.0.0.1:7000

    注意,这里的命令行完全像我们在添加一个新主服务器时使用的一样,所以我们没有指定要给哪个主服务器添加副本。这种情况下,redis-trib会添加一个新节点作为一个具有较少副本的随机的主服务器的副本。
    但是,你可以使用下面的命令行精确地指定你想要的主服务器作为副本的目标:
./redis-trib.rb add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006 127.0.0.1:7000

    这样我们就把一个新的副本赋予了一个指定的主服务器。
    一种更手工的给指定主服务器添加副本的方式,是添加一个新节点作为一个空主服务器,然后使用CLUSTER REPLICATE命令将其变为副本。如果节点被作为从服务器添加,但是你想移动它为另一个不同的主服务器的副本,这也是可行的。
    例如,为了给节点127.0.0.1:7005添加一个副本,这个节点当前服务11432-16383范围内的哈希槽,其节点ID为3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e,所有我们需要去做的,就是连接这个新的节点(已经作为空主服务器被添加)然后发送命令:
redis 127.0.0.1:7006> cluster replicate 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

    就是这样。现在我们有了这组哈希槽的一个新副本了,集群中的其它节点也已经知道了(需要几秒钟来更新配置)。我们可以用下面的命令来核实一下:
$ redis-cli -p 7000 cluster nodes | grep slave | grep 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e
f093c80dde814da99c5cf72a7dd01590792b783b 127.0.0.1:7006 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617702 3 connected
2938205e12de373867bf38f1ca29d31d0ddb3e46 127.0.0.1:7002 slave 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 0 1385543617198 3 connect

    这个3c3a0c…的节点现在有两个从服务器了,分别运行于7002(已存在的)和7006(新的)端口。

    移除节点(Removing a node)
    要移除一个从服务器节点,只要使用redis-trib的del-node命令就可以:
./redis-trib del-node 127.0.0.1:7000 <node-id>

    第一个参数只是集群中的一个随机节点,第二个参数是你想移除的节点的ID。
你也可以用同样的方式移除一个主服务器节点,但是,为了移除一个主服务器节点,它必须是空的。如果主服务器不是空的,你需要先将其数据重分片到其他的主服务器节点。
    另一种移除主服务器节点的方式,就是在其从服务器上执行一次手工故障转移,当它变为了新的主服务器的从服务器以后将其移除。显然,当你需要真的减少你的集群中的主服务器的数量时这个没有什么帮助,如果那样的话,就需要重新分片了。

    副本迁移(Replicas migration)
    在Redis集群中,可以使用下面的命令在任何时候重新配置一个从服务器复制一个不同的主服务器:
CLUSTER REPLICATE <master-node-id>

    但是有一种特殊的场景,你想让副本集自动地从一个主服务器移动到另一个主服务器,而不需要系统管理员的帮助。自动重新配置副本集被称为副本集迁移,这可以改善Redis集群的可靠性。
    注意:你可以在Redis集群规范中阅读到副本集迁移的细节,这里我们只提供一般性的信息,以及为了从中受益你该做什么。
    为什么你想让你的集群副本在某些特定条件下从一个主服务器移动到另一个的原因,是通常情况下Redis集群对失败的抵御能力和连接到指定从服务器的副本数量成正相关。
    例如,每个主服务器只有单个副本组成的集群在主服务器及其副本同时失效时就不能够继续运转,因为没有其他的实例拥有这台主服务器服务的哈希槽的副本。但是,网络断裂可能会在同一时间隔绝若干节点,其他类型的故障,例如单个节点的硬件或者软件错误,是值得注意的一类故障,很可能会同时发生,所以在每个主服务器拥有一个从服务器的集群中,有可能从服务器在下午4点被干掉,而主服务器在下午6点被干掉。这仍然会导致集群不再能运转。
    为了改进系统的可靠性,我们有一些增加额外副本集到每个主服务器的选项,但是这代价昂贵。副本迁移允许添加更多的从服务器到少许的主服务器。所以你可以有10个主服务器,每个有一个从服务器,总共20个实例。但是你为某些主服务器添加例如3个以上的实例,那么有些主服务器会有多余一个的从服务器。
    有了副本集迁移会发生什么?如果一个主服务器没有从服务器,一个来自于拥有多个从服务器的主服务器上的从服务器会迁移到这个孤独的主服务器上。所以像上面我们举的例子中,在你的从服务器下午4点下线以后,另一个从服务器会接替它的位置,当主服务器在下午5点也失效的时候,仍然有一个从服务器可以被选举,这样集群就可以继续运转了。
那么,简而言之,你应该了解副本集迁移的什么呢?
  • 集群会尝试从在某一个指定时刻拥有最多数量副本集的主服务上迁移一个副本。
  • 为了从副本迁移中受益,你需要在集群中添加多一些的副本到单个主服务器,无论是什么主服务器。
  • 有一个称为replica-migration-barrier的控制副本迁移特性的配置参数。你可以在Redis集群提供的示例redis.conf文件中读到更多信息。


    升级节点(Upgrading nodes in a Redis Cluster)
    升级从服务器节点很简单,因为你只需要停止节点然后用已更新的Redis版本重启。如果有客户端使用从服务器节点分离读请求,它们应该能够在某个节点不可用时重新连接另一个从服务器。
    升级主服务器要稍微复杂一些,建议的步骤是:
  1. 使用CLUSTER FAILOVER来触发一次手工故障转移主服务器(请看本文档的手工故障转移小节)。
  2. 等待主服务器变为从服务器。
  3. 像升级从服务器那样升级这个节点。
  4. 如果你想让你刚刚升级的节点成为主服务器,触发一次新的手工故障转移,让升级的节点重新变回主服务器。

    你可以按照这些步骤来一个节点一个节点的升级,直到全部节点升级完毕。

    迁移到Redis集群(Migrating to Redis Cluster)
    想迁移到Redis集群的用户可能只有一个单一的主服务器,或者已经使用了已存在的分片布局,通过使用某种内部算法,或者他们的客户端库实现的分片算法,或者Redis代理,键被分拆到N个节点上。
    这两种情况下迁移到Redis集群都很简单,但是最重要的细节是,如果程序使用了多键操作,怎么办。有三种不同的情况:
  1. 没有使用多键操作,或者事务,或者涉及多个键的Lua脚本。键被独立地访问(即使通过事务或者Lua脚本组合针对同样的键的多个命令一起来访问)。
  2. 使用了多键操作,或者事务,或者涉及多个键的Lua脚本,但是键都有相同的哈希标签(hash tag),也就是说这些一起使用的键都碰巧有相同的{…}子串。例如,下面的多键操作是在相同的哈希标签上下文中定义的:SUNION {user:1000}.foo {user:1000}.bar。
  3. 使用了多键操作,或者事务,或者涉及多个键的Lua脚本,但是键的名字没有一个显式的或者相同的哈希标签。

    Redis不处理第三种情况:应用程序需要被修改为不能使用多键操作,或者只能在相同的哈希标签上下文中使用。
    前两种情况覆盖到了,所以我们会聚焦在这两种情况,它们会用相同的方式来处理,所以本文不会去区别对待。
    假设你的已存在数据集已经被拆分到了N个主服务器上,如果你没有已存在的分片的话N=1,你需要下面的步骤来迁移你的数据集到Redis集群:
  1. 停止你的客户端。当前没有自动在线迁移(live-migration)到Redis集群的可能。你也许可以通过精心策划一次在你的程序或环境上下文中的在线迁移来办到。
  2. 使用BGREWRITEOF命令为所有你的N个主服务器生成一个追加文件,然后等待AOF文件完全生成。
  3. 按照aof-1到af-N保存你的AOF文件到某处。此时愿意的话你可以停掉你的旧实例(这很有用,因为在非虚拟化的部署中,你常常需要重用这些计算机)。
  4. 创建一个由N个主服务器和0个从服务器组成的Redis集群。你可以稍后添加从服务器。确保所有你的节点都是使用追加文件来持久化。
  5. 停止所有的集群节点,用你已存在的追加文件替换他们的朱家文件,aof-1替换第一节点,aof-2替换第二个节点,一直到aof-N。
  6. 使用新的AOF文件来重启你的Redis集群。它们会抱怨按照配置有些键不应该出现。
  7. 使用redis-trib fix命令来修正集群,这样键就会根据每个节点的哈希槽被迁移了。
  8. 最后使用redis-trib check来确保集群是正常的。
  9. 重启被修改为支持Redis集群的客户端。

    还有一个方式从外部实例导入数据到Redis集群,就是使用redis-trib import命令。
    这个命令移动一个运行实例(同时删除源实例上的键)上的所有键到一个指定已存在的Redis集群。但是,注意如果你使用Redis 2.8实例作为来源实例,操作可能很慢,因为2.8没有实现迁移连接缓存(migrate connection caching),所以在执行这个操作之前,你可能得重启你的Redis 3.x版本的源实例。
===============================================================================
    大家好,我是阮威。华中科技大学,计算机软件专业硕士。毕业后加入腾讯,先后在腾讯电子商务部和无线游戏产品部工作,现供职于欢聚时代基础产品部。IT男,至今。欢迎大家收听我的公众账号。

猜你喜欢

转载自powersoft.iteye.com/blog/2153906