Redis集群教程
阅读原文时间:2021年04月20日阅读:1

一、集群简介

本文章简要地介绍了Redis集群,它不使用特别深入地来理解分布式系统的概念。 它提供了关于如何设置集群、测试和操作它的说明,而不涉及Redis集群规范中涉及的细节,只是从用户的角度描述了系统的行为。 

然而,本教程试图从最终用户的角度提供关于Redis集群可用性一致性特征的信息,以一种简单易懂的方式进行说明。

        注意:本教程要求Redis 3.0或更高版本。

        如果您计划运行一个正式的Redis集群部署,建议阅读更正式的规范,即使不是严格要求的。不过,最好从本文开始,花些时间使用Redis集群,然后再阅读规范。

1、集群特性

Redis集群提供了一种方法来运行一个Redis安装,其中数据被自动分片到多个Redis节点。 Redis集群还在分区期间提供了一定程度的可用性,即在某些节点失败或无法通信时继续操作的能力。 但是,当出现较大的故障时(例如,当大多数主机不可用时),集群将停止运行。

在实际应用中,你能从Redis集群中得到什么?

  • 在多个节点之间自动分割数据集的能力。

  • 当节点子集发生故障或无法与集群的其他部分通信时,继续运行的能力。

2、 Redis集群TCP端口

每个Redis集群节点都需要打开两个TCP连接。一个是用于服务客户端的常规Redis TCP端口,例如6379,另一个是常规端口加10000所获得的数据端口,因此在示例中为16379。

第二个端口用于集群总线,这是一个使用二进制协议的节点到节点通信通道。 节点使用集群总线进行故障检测、配置更新、故障转移授权等。 客户端永远不应该尝试与集群总线端口通信,而应该始终使用普通的Redis命令端口,但是要确保在防火墙中打开两个端口,否则Redis集群节点将无法通信。

命令端口和集群总线端口偏移量是固定的,总是10000。

请注意,为了让Redis集群正常工作,您需要对每个节点:

1、 用于与客户机通信的普通客户机通信端口(通常为6379)向所有需要到达集群的客户机以及所有其他集群节点(使用客户机端口进行密钥迁移)开放。

2、 集群总线端口(客户机端口+ 10000)必须能够从所有其他集群节点访问。

如果不同时打开两个TCP端口,集群将无法正常工作。

集群总线使用一种不同的二进制协议来进行节点间的数据交换,这种协议更适合于在节点之间交换信息,只需要很少的带宽和处理时间。

3、 Redis集群数据分片

Redis集群不使用一致的散列,而是一种不同的分片形式,其中每个键在概念上都是我们所说的散列槽的一部分。 

Redis集群中有16384个哈希槽,要计算给定键的哈希槽是多少,只需取CRC16(键)%16384。

Redis集群中的每个节点负责哈希槽的子集,例如,您可能有一个包含3个节点的集群,其中:

  • 节点A包含从0到5500的哈希槽。

  • 节点B包含从5501到11000的哈希槽。

  • 节点C包含从11001到16383的哈希槽。

    这使得我们可以轻松地添加和删除集群中的节点。例如,如果我想添加一个新节点D,我需要将一些哈希槽从节点A、B、C移动到D。 类似地,如果我想从集群中删除节点A,我可以将由A提供的哈希槽移动到B和C。 当节点A为空时,我可以将它从集群中完全删除。

         因为将哈希槽从一个节点移动到另一个节点不需要停止操作,所以添加和删除节点,或者更改节点持有的哈希槽的百分比,都不需要任何停机时间。

         只要一个命令执行(或整个事务,或Lua脚本执行)中涉及的所有键都属于同一个散列槽,Redis集群就支持多个键操作。 用户可以使用一个称为哈希标签的概念强制多个键成为同一个哈希槽的一部分。

         散列标签在集群规范有文档说明,但主旨是,如果键在{}里有子字符串,只有这个子字符串被散列,例如 this{foo}key和 another{foo}key是保证在同一散列槽,并可以在使用多个键作为参数的命令中一起使用。

4、 Redis集群主从模型

为了在主节点子集出现故障或无法与大多数节点通信时保持可用性,Redis集群使用主从模型,其中每个哈希槽都有1个(主节点本身)到N个副本(N-1个额外的从节点)。

在节点A、B、C的示例集群中,如果节点B失败,集群将无法继续,因为我们不再能够提供范围为5501-11000的哈希槽。

然而创建集群时(或在稍后的时间)我们从节点添加到每一个主节点,所以最终集群由A,B, C主节点和A1, B1, C1从节点组成,如果节点B失败系统能够继续运行。

节点B1复制B, B失败,集群将提升节点B1为新主节点,并继续正常运行。

但是请注意,如果节点B和B1同时失败,则Redis集群无法继续运行。

5、 Redis集群一致性保证

Redis集群不能保证强一致性。实际上,这意味着在某些条件下,Redis集群可能会丢失系统向客户端确认的写操作。

Redis集群会丢失写操作的第一个原因是它使用异步复制。这意味着在写期间会发生以下情况:

  • 客户端向主B写入。

  • 主节点B向客户端回复OK。

  • 主B将写操作传播到它的从服务器B1、B2和B3。

    可以看到B回复给客户端之前,不等待来自B1, B2, B3的确认回复,因为这将会有延迟,所以如果你的客户写东西,B回复确认写,但崩把数据写入从节点之前崩溃了,一个从节点(没有接受到写操作)可以被选拔为新主人,但是永远失去了这个写操作。

         他的方法与大多数数据库非常类似,这些数据库配置每秒将数据刷新到磁盘,因此,由于过去使用传统数据库系统而不涉及分布式系统的经验,您已经能够推断出这种情况。 类似地,您可以通过强制数据库在响应客户机之前刷新磁盘上的数据来提高一致性,但是这通常会导致非常低的性能。 对于Redis集群,这相当于同步复制。

         基本上,在性能和一致性之间需要进行权衡。

         Redis集群在绝对需要时支持同步写入,通过WAIT命令实现,这使得丢失写入的可能性大大降低,但是请注意,即使使用同步复制,Redis集群也没有实现强一致性: 在更复杂的故障场景下,始终有可能选择无法接收写操作的从服务器作为主服务器。

         另一个值得注意的场景是,Redis集群将丢失写操作,这发生在网络分区期间,其中客户机与少数实例(至少包括一个主实例)隔离。

         例如,我们的6个节点集群由A、B、C、A1、B1、C1组成,有3个主节点和3个从节点。还有一个客户机,我们将其称为Z1。

         一个分区发生后,有可能在划分的一边有a C A1 B1 C1,在另一边有B Z1。 

Z1仍然可以写给B, B会接受它的写操作。如果分区在很短的时间内恢复,集群将正常运行。但是,如果分区持续的时间足够长,使得B1能够在分区的大多数端升级为master,那么Z1发送给B的写操作将会丢失。

         注意,对于Z1能够发送给B的写数量,有一个最大的窗口:如果分区的多数端已经经过了足够的时间来选择一个从端作为主节点,那么少数端中的每个主节点都停止接受写。

这个时间量是Redis集群的一个非常重要的配置指令,称为node time。

当节点超时结束后,一个主节点被认为是失败的,可以用它的一个副本替换。 类似地,在节点超时之后,没有一个主节点能够感知其他大多数主节点,它将进入错误状态并停止接受写操作。

二、 Redis集群配置参数

         我们将创建一个示例集群部署。在继续之前,让我们介绍一下Redis集群在Redis .conf文件中引入的配置参数。 有些是显而易见的,有些则会随着你的阅读而变得更加清晰。

  • cluster-enabled 

    如果是,则在特定的Redis实例中启用Redis集群支持。否则,该实例将像往常一样作为独立实例启动。

  • cluster-config-file 

     注意,不管这个选项的名称是什么,它不是一个用户可编辑的配置文件,而是Redis集群节点在每次发生更改时自动保存集群配置(基本上是状态)的文件,以便能够在启动时重新读取它。 该文件列出了集群中的其他节点、它们的状态、持久变量等等。 通常,由于接收到一些消息,这个文件会被重写并刷新到磁盘上。

  • cluster-node-timeout : 

    Redis集群节点不可用的最长时间。 如果一个主节点的访问时间不能超过指定的时间量,则它的从属节点将对其进行故障转移。 此参数控制Redis集群中的其他重要内容。 值得注意的是,在指定的时间内不能到达大多数主节点的每个节点都将停止接受查询。

  • cluster-slave-validity-factor 

    如果设置为零,则无论主服务器和从服务器之间的连接断开的时间有多长,从服务器总是试图对主服务器进行故障转移。 如果值是正数,最大断开时间为node-timeout*factor。如果节点是一个从节点,主链接断开连接超过指定的时间,它不会试图启动一个故障转移 例如,如果节点超时被设置为5秒,而有效性因子被设置为10秒,断开与主节点连接超过50秒的从节点将不会尝试对其主节点进行故障转移。 请注意,如果没有从服务器能够进行故障转移,那么任何非零的值都可能导致主服务器故障后Redis集群不可用。 在这种情况下,只有当原始主服务器重新加入集群时,集群才会返回可用。

  • cluster-migration-barrier : 

         一个主节点将保持与至少几个从节点的连接,以便其它从节点迁移到一个没有从节点的主节点。

  • cluster-require-full-coverage 

    如果将该值设置为yes(默认情况下为yes),那么如果某个节点没有覆盖key空间的某个百分比,集群将停止接受写操作。 如果将该选项设置为no,即使只处理关于键子集的请求,集群也将提供查询。

三、 创建和使用一个Redis集群

         要创建集群,首先需要在集群模式下运行几个空的Redis实例。 这基本上意味着集群不是使用普通的Redis实例创建的,因为需要配置一个特殊模式,以便Redis实例能够启用集群特定的特性和命令。

         下面是一个最小的Redis集群配置文件:

port 8000
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

        正如您所看到的,启用集群模式 只是简单的cluster-enabled指令。 每个实例还包含存储此节点配置的文件的路径,默认情况下该文件是nodes.conf。 此文件不是人工生成;它只是由Redis集群实例在启动时生成,并在每次需要时更新。

        注意,按预期工作的最小集群需要包含至少三个主节点。对于您的第一个测试,强烈建议启动一个包含三个主节点和三个从节点的6个节点集群。

        为此,输入一个新目录,并创建以下目录,这些目录以我们将在任何给定目录中运行的实例的端口号命名。

mkdir redisCluster
cd redisCluster
mkdir 8000 8001 8002 8003 8004 8005

        在每个目录中创建一个redis.conf文件,从8001到8006。作为配置文件的模板,只需使用上面的小示例,但请确保根据目录名用正确的端口号替换端口号8001。

        赋值redis-server执行文件至redisCluster。

        像这样启动每个实例:

cd 8001
../redis-server ./redis.conf

        从每个实例的日志中可以看到,由于不存在nodes .conf文件,所以每个节点都为自己分配了一个新ID。

[82462] 26 Nov 11:56:55.329 * No cluster configuration found, I'm 97a3a64667477371c4479320d683e4c8db5858b1

此ID将被此特定实例永久使用,以便该实例在集群上下文中具有唯一的名称。 每个节点都使用这个id来记住其他节点,而不是通过IP或端口。IP地址和端口可能会改变,但是唯一的节点标识符在节点的整个生命周期中都不会改变。我们简单地将这个标识符称为节点ID。

1、创建集群

现在已经运行了许多实例,我们需要通过向节点编写一些有意义的配置来创建集群。

如果您使用的是Redis 5,这非常容易实现,因为我们可以借助嵌入到Redis -cli中的Redis集群命令行实用程序来创建新的集群、检查或重新分割现有集群,等等。

对于Redis版本3或4,有一个较老的工具称为Redis -trib.rb与此非常相似。您可以在Redis源代码发行版的src目录中找到它。您需要安装redis gem才能运行redis-trib。

         第一个示例,即集群创建,将同时使用Redis 5中的Redis -cli和Redis 3和4中的Redis -trib来显示。但是,接下来的所有示例都将只使用redis-cli,因为您可以看到语法非常相似,您可以通过使用redis-trib将一个命令行简单地更改为另一个命令行。 redis-trib.rb help 获取关于旧语法的信息。

         请注意,如果您愿意,可以对Redis 4集群使用Redis 5 Redis -cli,而不会出现任何问题。

要用Redis -cli为Redis 5创建集群,只需输入:

./redis-cli --cluster create 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003 127.0.0.1:8004 127.0.0.1:8005 127.0.0.1:8006 --cluster-replicas 1

这里使用的命令是create,因为我们想创建一个新的集群。选项--cluster-replicas 1意味着我们希望为每个创建的主节点创建一个从节点。其他参数是我要用于创建新集群的实例的地址列表。

显然,我们的需求的唯一设置是创建一个包含3个主节点和3个从节点的集群。

        Redis-cli将为您提供一个配置。输入yes接受建议的配置。 

集群将被配置和连接,这意味着实例将被引导到彼此之间进行通信。 最后,如果一切顺利,您将看到这样一条消息:

[OK] All 16384 slots covered

         这意味着至少有一个主实例为16384个可用插槽提供服务。

2、运行集群

在这个阶段,Redis集群的一个问题是缺少客户端库实现。

目前所知有好几种实现,我们现在用redis-cli这个实现,它使用-c开关启动时实现了非常基本的集群支持。

[root@localhost redisCluster]# redis-cli -c -p 8001
127.0.0.1:8001> set name chenzixuan
-> Redirected to slot [5798] located at 127.0.0.1:8002
OK
127.0.0.1:8002> set age 26
-> Redirected to slot [741] located at 127.0.0.1:8001
OK
127.0.0.1:8001> get name
-> Redirected to slot [5798] located at 127.0.0.1:8002
"chenzixuan"
127.0.0.1:8002> get age
-> Redirected to slot [741] located at 127.0.0.1:8001
"26"
127.0.0.1:8001>

         Redis -cli集群支持非常基础,因此它总是使用在这个情况下使用:Redis集群节点能够将客户机重定向到正确的节点。 一个真正的客户端可以做得更好,缓存哈希槽和节点地址之间的映射,从而直接使用到正确节点的正确连接。 只有在集群配置中发生更改时才会刷新映射,例如故障转移之后或系统管理员通过添加或删除节点更改集群布局之后。

3、 集群重新分片

        现在,我们准备尝试集群重新分片。 Resharding基本上意味着将哈希槽从一组节点移动到另一组节点,就像集群创建一样,它是使用redis-cli实用程序完成的。

        要开始重新分片,只需输入:

redis-cli --cluster reshard 127.0.0.1:8001

        您只需要指定一个节点,redis-cli将自动找到其他节点。

        前redis-cli只能在管理员支持下重新分片,您不能只说将5%的插槽从这个节点移动到另一个节点(但是实现起来非常简单)。它以一个问题开始, qq第一个问题是你想做多大的分片:

         我们可以尝试重新切分1000个哈希槽,如果示例仍然在没有sleep调用的情况下运行,那么这些哈希槽应该已经包含了大量的键。 然后redis-cli需要知道重新分片的目标是什么,即接收散列槽的节点。

         我将使用第一个主节点,即127.0.0.1:8001,但是我需要指定实例的节点ID。这已经由redis-cli打印在列表中,但如果需要,我总是可以使用以下命令找到节点的ID:

[root@localhost redisCluster]# redis-cli -p 8001 cluster nodes | grep myself
26f81e7087dd506c083fb370820d18bf40dd4e3c 127.0.0.1:8001@18001 myself,master - 0 1561690318000 1 connected 0-5460

        我的目标节点是26f81e7087dd506c083fb370820d18bf40dd4e3c。

        现在您将被问到希望从哪些节点获取这些键。我将键入all以便从所有其他主节点获取一些哈希槽。

        在最后的确认之后,您将看到redis-cli将从一个节点移动到另一个节点的每个插槽的消息,并且将为从一边移动到另一边的每个实际键打印一个点。

        在重新分片的过程中,您应该能够看到示例程序不受影响地运行。如果需要,可以在重新分片期间多次停止并重新启动它。

         在重新分片结束时,您可以使用以下命令测试集群的健康状况:

redis-cli --cluster check 127.0.0.1:8001

        所有的槽都将像往常一样被覆盖,但是这次127.0.0.1:8001的主槽将有更多的哈希槽,大约在6461左右。

4、 测试故障转移

        注意:在此测试期间,您应该打开一个选项卡,同时运行一致性测试应用程序。

        为了触发故障转移,我们可以做的最简单的事情(这也是分布式系统中可能发生的语义上最简单的故障)是击溃一个进程,在我们的示例中是一个主进程。

         我们可以识别一个集群并使用以下命令击溃它:

[root@localhost redisCluster]# redis-cli -p 8001 cluster nodes | grep master
f80d94dd03440e3171ec6456883db9b01bf7d5e1 127.0.0.1:8002@18002 master - 0 1561691268000 2 connected 5962-10922
26f81e7087dd506c083fb370820d18bf40dd4e3c 127.0.0.1:8001@18001 myself,master - 0 1561691267000 7 connected 0-5961 10923-11421
c00b2868ad2d72e18281d37cf5150dd8234f4bc6 127.0.0.1:8003@18003 master - 0 1561691268000 3 connected 11422-16383

        好的,现在8001,8002,8003是主节点。让我们用DEBUG SEGFAULT命令击溃节点8002:

[root@localhost redisCluster]# redis-cli -p 8002 debug segfault
Error: Server closed the connection

        我们现在可以检查故障转移后的集群设置(注意,在此期间,我重新启动了崩溃的实例,以便它作为一个从节点重新加入集群):

        启动8002前:

[root@localhost redisCluster]# redis-cli -p 8001 cluster nodes
09f624566fafb9d738a499fa8e9455efb66071f8 127.0.0.1:8005@18005 slave c00b2868ad2d72e18281d37cf5150dd8234f4bc6 0 1561691704361 5 connected
fdbfbce9a43434ea28459e28867a38e352cbb9a9 127.0.0.1:8006@18006 slave 26f81e7087dd506c083fb370820d18bf40dd4e3c 0 1561691703354 7 connected
f80d94dd03440e3171ec6456883db9b01bf7d5e1 127.0.0.1:8002@18002 master,fail - 1561691435407 1561691434602 2 disconnected
26f81e7087dd506c083fb370820d18bf40dd4e3c 127.0.0.1:8001@18001 myself,master - 0 1561691703000 7 connected 0-5961 10923-11421
31bf33682824f744681d8028256862f3ad913f84 127.0.0.1:8004@18004 master - 0 1561691704563 8 connected 5962-10922
c00b2868ad2d72e18281d37cf5150dd8234f4bc6 127.0.0.1:8003@18003 master - 0 1561691704000 3 connected 11422-16383

        启动8002后:

[root@localhost redisCluster]# redis-cli -p 8001 cluster nodes
09f624566fafb9d738a499fa8e9455efb66071f8 127.0.0.1:8005@18005 slave c00b2868ad2d72e18281d37cf5150dd8234f4bc6 0 1561691793194 5 connected
fdbfbce9a43434ea28459e28867a38e352cbb9a9 127.0.0.1:8006@18006 slave 26f81e7087dd506c083fb370820d18bf40dd4e3c 0 1561691793000 7 connected
f80d94dd03440e3171ec6456883db9b01bf7d5e1 127.0.0.1:8002@18002 slave 31bf33682824f744681d8028256862f3ad913f84 0 1561691792589 8 connected
26f81e7087dd506c083fb370820d18bf40dd4e3c 127.0.0.1:8001@18001 myself,master - 0 1561691792000 7 connected 0-5961 10923-11421
31bf33682824f744681d8028256862f3ad913f84 127.0.0.1:8004@18004 master - 0 1561691792185 8 connected 5962-10922
c00b2868ad2d72e18281d37cf5150dd8234f4bc6 127.0.0.1:8003@18003 master - 0 1561691792000 3 connected 11422-16383

现在主节点运行在端口8001、8002和7005上。以前的主接节点,也就是运行在端口8002上的Redis实例,现在是8004的从节点。 CLUSTER NODES命令的输出可能看起来有些吓人,但实际上它非常简单,由以下令牌组成:

  • 节点ID

  • ip:port

  • 标志: master, slave, myself, fail, …

  • 如果是从节点,则是主节点的节点ID

  • 仍然在等待回复的最后一次ping的时间。

  • 最后一次收到pong的时间

  • 此节点的配置历元(请参阅集群规范)

  • 指向此节点的链接的状态。

  • 服务的槽

5、手动故障转移

有时,强制进行故障转移而不给主节点造成任何实际问题是很有用的。  例如,为了升级其中一个主节点的Redis进程,最好对其进行故障转移,以便将其转换为对可用性影响最小的从节点。

Redis集群使用CLUSTER FAILOVER命令支持手动故障转移,该命令必须在要进行故障转移的主节点的一个从节点中执行。

         手动故障转移比实际造成的故障更特殊和安全,因为它们在这个过程中避免数据丢失。通过只有当系统是确保新主节点处理了旧主节点的所有复制流,才允许客户端从原来的主节点切换到新主节点。

这是在执行手动故障转移时从日志中看到的:

188821:S 28 Jun 2019 11:56:20.547 # Manual failover user request accepted.
188821:S 28 Jun 2019 11:56:20.561 # Received replication offset for paused master manual failover: 7478
188821:S 28 Jun 2019 11:56:20.640 # All master replication stream processed, manual failover can start.
188821:S 28 Jun 2019 11:56:20.640 # Start of election delayed for 0 milliseconds (rank #0, offset 7478).
188821:S 28 Jun 2019 11:56:20.640 # Starting a failover election for epoch 9.
188821:S 28 Jun 2019 11:56:20.643 # Currently unable to failover: Waiting for votes, but majority still not reached.
188821:S 28 Jun 2019 11:56:20.643 # Failover election won: I'm the new master.

基本上,连接到我们正在故障转移的主服务器的客户端被停止。与此同时,主节点将其复制偏移量发送给等待到达偏移量的从节点。 当到达复制偏移量时,将启动故障转移,并通知旧的主节点有关配置开关。 当客户端在旧主节点上解除阻塞时,它们将被重定向到新主节点。

6、加新节点

添加新节点基本上就是添加一个空节点,然后将一些数据移动到其中(如果它是一个新主节点),或者告诉它设置为一个已知节点的副本(如果它是一个从节点)。

我们将从添加一个新的主节点实例开始展示这两个实例。

在这两种情况下,要执行的第一步都是添加一个空节点。

这很简单,在端口8007上启动一个新节点(从8001年到8006端口年我们已经用于现有6节点)。除了端口号,与其他节点使用相同的配置,所以为了符合我们用于前一节点的设置,你应该做的是:

  • 在终端应用程序中创建一个新选项卡。

  • 进入redisCluster目录

  • 创建一个名为8007的目录。

  • 在其中创建一个redis.conf文件,类似于用于其他节点的文件,但使用8007作为端口号。

  • 最后启动服务器: / redis.conf redis-server

    此时,服务器应该正在运行。

    现在,我们可以像往常一样使用redis-cli将节点添加到现有集群中。

    redis-cli --cluster add-node 127.0.0.1:8007 127.0.0.1:8001

  

        如您所见,我使用add-node命令指定新节点的地址作为第一个参数,并将集群中随机存在节点的地址作为第二个参数。

        实际上,redis-cli对我们的帮助很小,它只是向节点发送了一个 CLUSTER MEET 消息,这也是可以手工完成的。 不过,redis-cli还会在操作之前检查集群的状态,因此,即使知道内部机制如何工作,也应该始终通过redis-cli执行集群操作。现在我们可以连接到新节点,看看它是否真的加入了集群:

127.0.0.1:8007> cluster nodes
fdbfbce9a43434ea28459e28867a38e352cbb9a9 127.0.0.1:8006@18006 slave 26f81e7087dd506c083fb370820d18bf40dd4e3c 0 1561702937426 7 connected
26f81e7087dd506c083fb370820d18bf40dd4e3c 127.0.0.1:8001@18001 master - 0 1561702936000 7 connected 0-5961 10923-11421
09f624566fafb9d738a499fa8e9455efb66071f8 127.0.0.1:8005@18005 slave c00b2868ad2d72e18281d37cf5150dd8234f4bc6 0 1561702936000 3 connected
31bf33682824f744681d8028256862f3ad913f84 127.0.0.1:8004@18004 slave f80d94dd03440e3171ec6456883db9b01bf7d5e1 0 1561702937000 9 connected
c00b2868ad2d72e18281d37cf5150dd8234f4bc6 127.0.0.1:8003@18003 master - 0 1561702936000 3 connected 11422-16383
f80d94dd03440e3171ec6456883db9b01bf7d5e1 127.0.0.1:8002@18002 master - 0 1561702936416 9 connected 5962-10922
24484c3c32940f6e6f6228245129d378dc8dd6f7 127.0.0.1:8007@18007 myself,master - 0 1561702935000 0 connected

         注意,由于这个节点已经连接到集群,所以它已经能够正确地重定向客户机查询,并且通常是集群的一部分。然而,与其他大师相比,它有两个特点:

  • 它不包含任何数据,因为它没有指定的哈希槽。

  • 因为它是一个没有分配插槽的主人,所以当一个奴隶想成为主人时,它不参与选举过程。

        现在可以使用redis-cli的重新分片特性将哈希槽分配给这个节点。 就像我们在前一节中已经做过的那样,这里就不展示了,没有什么区别,只是将空节点作为目标重新分片。

7、 添加一个新节点作为副本

        添加新副本可以通过两种方式执行。一个明显的方法是再次使用redis-cli,但是使用--cluster-slave选项,如下所示:

redis-cli --cluster add-node 127.0.0.1:8007 127.0.0.1:8001 --cluster-slave

        注意,这里的命令行与我们用来添加新主节点的命令行完全相同,所以我们没有指定要将副本添加到哪个主节点。在本例中,redis-cli将添加新节点作为具有较少副本的主节点中的随机主节点的副本。

        不过,你可以用下面的命令行指定你想要的新副本的主节点:

redis-cli --cluster add-node 127.0.0.1:8007 127.0.0.1:8001 --cluster-slave --cluster-master-id f80d94dd03440e3171ec6456883db9b01bf7d5e1

        通过这种方式,我们将新副本分配给特定的主节点。

        向特定主机添加副本的更手动的方法是将新节点添加为空主主节点,然后使用CLUSTER REPLICATE命令将其转换为副本。如果节点是作为一个从节点添加的,但您希望将其作为另一个主节点的副本移动,那么这也可以工作。

         例如为127.0.0.1:8006节点加一个副本,它目前服务散列槽在11422-16383的范围内,节点ID为c00b2868ad2d72e18281d37cf5150dd8234f4bc6,所有我需要做的就是连接新节点(已经添加为空大师)和发送的命令:

127.0.0.1:8007> cluster replicate c00b2868ad2d72e18281d37cf5150dd8234f4bc6
OK

        就是这样。现在,我们为这组哈希槽创建了一个新的副本,集群中的所有其他节点都已经知道了(在更新它们的配置所需的几秒钟之后)。我们可以用下面的命令来验证:

[root@localhost redisCluster]# redis-cli -c -p 8001 cluster nodes | grep slave | grep c00b2868ad2d72e18281d37cf5150dd8234f4bc6
09f624566fafb9d738a499fa8e9455efb66071f8 127.0.0.1:8005@18005 slave c00b2868ad2d72e18281d37cf5150dd8234f4bc6 0 1561711523315 5 connected
3bfca9fbda24673e29dfd1147d00ba3f9e40a1ae 127.0.0.1:8007@18007 slave c00b2868ad2d72e18281d37cf5150dd8234f4bc6 0 1561711524123 9 connected

        节点c00b2868ad2d72e18281d37cf5150dd8234f4bc6现在有两个从节点,运行在端口8005(现有端口)和端口8007(新端口)上。

8、删除节点

        要删除从节点,只需使用redis-cli的del-node命令:

redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`

第一个参数只是集群中的一个随机节点,第二个参数是要删除的节点的ID。

您也可以用同样的方法删除一个主节点,但是它必须是空的。 如果主节点不是空的,则需要在此之前将数据重新切分到其他所有主节点。 删除主节点的另一种方法是对其中一个从属节点执行手动故障转移,并在该节点成为新主节点的从属节点后删除该节点。 显然,当您希望减少集群中的实际主节点数量时,这并没有帮助,在这种情况下,需要重新分片。

比如,我想删除8003端口的主节点,但是它是非空的,所以删除不了:

接下来我就要把它分片给其它的主节点,这里把它分片给8001:

分片完之后,8003就空点了:

此时我再来删除8003,就能成功删除了:

9、副本(Replica)迁移

在Redis集群中,只要使用以下命令,就可以重新配置一个从服务器,以便在任何时候用不同的主服务器进行复制:

CLUSTER REPLICATE <master-node-id>

但是,有一种特殊的场景,您希望副本自动从一个主节点移动到另一个主节点,而不需要系统管理员的帮助。 复本的自动重新配置称为 replicas migration,能够提高Redis集群的可靠性。

注意:您可以在Redis集群规范中阅读副本迁移的详细信息,这里我们只提供一些关于总体思想的信息,以及您应该做些什么才能从中受益。 

您可能想让集群副本在特定条件下从一个主节点移动到另一个主节点的原因是,通常Redis集群对故障的抵抗力与附加到给定主节点上的副本数量相同。

         例如,在一个集群中,如果每个主节点都有一个副本,如果主节点和它的副本同时失败,那么这个集群就不能继续执行操作,原因很简单,因为没有其他实例可以拥有主节点提供的哈希槽的副本。

         然而可能当网络隔离孤立一些节点时,许多其他类型的故障,如,不太可能发生在同一时间的一个节点的硬件或软件故障。所以有可能在您的每个主节点附带一个从节点的集群中,从节点是4点被杀死,主节点早上6点被杀死。这仍然会导致集群无法再运行。

         为了提高系统的可靠性,我们可以选择向每个主节点添加额外的副本,但这是昂贵的。 副本迁移允许向少数几个主节点添加更多的从节点。 因此你有10个主节点,每个主节点附带1个从节点,总共有20个实例。 您添加3个以上的实例作为您的一些主节点的从节点,因此某些主节点将拥有多个从节点。

        使用副本迁移的情况是,如果一个主节点没有从节点,那么一个拥有多个从节点的主节点的副本将迁移到孤立的主节点。

         所以在你的从节点在凌晨4点挂掉之后,就像我们上面做的例子一样,另一个从节点将取代它,当主节点在早上5点也失败时,仍然有一个从节点可以被选举出来,这样集群就可以继续运行。

         那么,关于副本迁移,您应该知道什么呢?

  • 集群将尝试从在给定时刻拥有最多副本的主节点迁移一个副本。

  • 为了从副本迁移中获益,您只需向集群中的单个主节点添加更多的副本,无论哪个主节点都无关紧要。

  • 有一个配置参数控制复制迁移特性,称为 cluster-migration-barrier,您可以在Redis Cluster提供的示例Redis .conf文件中了解更多信息。

10、 升级Redis集群中的节点

升级从节点很容易,因为您只需要停止节点并使用更新版本的Redis重新启动它。 如果有使用从节点读取数据的客户端,它们应该能够在给定的从节点不可用时重新连接到另一个从节点。

升级主节点有点复杂,建议的步骤是:

使用集群故障转移来触发主节点到其从节点的手动故障转移(请参阅本文档的“手动故障转移”部分)。

  • 等待主节点变成从节点。

  • 最后,像对从节点所做的那样升级节点。

  • 如果希望主节点是刚刚升级的节点,请触发一个新的手动故障转移,以便将升级后的节点转换回主节点。

    按照此过程,应该一个节点接着一个节点升级,直到所有节点都升级为止。