什么是 Redis 集群??
Redis 集群是一个分布式(distributed)、容错(fault-tolerant)的 Redis 实现,集群可使用的功能是普通单机 Redis 所能使用的功能的一个子集(subset)。node
Redis 集群中不存在中心(central)节点或者代理(proxy)节点,集群的其中一个主要设计目标是达到线性可扩展性(linear scalability)。redis
Redis 集群为了保证一致性(consistency)而牺牲了一部分容错性:系统会在保证对网络断线(net split)和节点失效(node failure)具备有限(limited)抵抗力的前提下,尽量地保持数据的一致性。算法
Note数据库
集群将节点失效视为网络断线的其中一种特殊状况。缓存
集群的容错功能是经过使用主节点(master)和从节点(slave)两种角色(role)的节点(node)来实现的:安全
主节点和从节点使用彻底相同的服务器实现,它们的功能(functionally)也彻底同样,但从节点一般仅用于替换失效的主节点。
不过,若是不须要保证“先写入,后读取”操做的一致性(read-after-write consistency),那么可使用从节点来执行只读查询。
Redis 集群实现的功能子集?
Redis 集群实现了单机 Redis 中,全部处理单个数据库键的命令。服务器
针对多个数据库键的复杂计算操做,好比集合的并集操做、合集操做没有被实现,那些理论上须要使用多个节点的多个数据库键才能完成的命令也没有被实现。网络
在未来,用户也许能够经过 MIGRATE COPY 命令,在集群的计算节点(computation node)中执行针对多个数据库键的只读操做,但集群自己不会去实现那些须要将多个数据库键在多个节点中移来移去的复杂多键命令。架构
Redis 集群不像单机 Redis 那样支持多数据库功能,集群只使用默认的 0 号数据库,而且不能使用 SELECT 命令。app
Redis 集群协议中的客户端和服务器?
Redis 集群中的节点有如下责任:
持有键值对数据。
记录集群的状态,包括键到正确节点的映射(mapping keys to right nodes)。
自动发现其余节点,识别工做不正常的节点,并在有须要时,在从节点中选举出新的主节点。
为了执行以上列出的任务,集群中的每一个节点都与其余节点创建起了“集群链接(cluster bus)”,该链接是一个 TCP 链接,使用二进制协议进行通信。
节点之间使用 Gossip 协议 来进行如下工做:
传播(propagate)关于集群的信息,以此来发现新的节点。
向其余节点发送 PING 数据包,以此来检查目标节点是否正常运做。
在特定事件发生时,发送集群信息。
除此以外,集群链接还用于在集群中发布或订阅信息。
由于集群节点不能代理(proxy)命令请求,因此客户端应该在节点返回 -MOVED 或者 -ASK 转向(redirection)错误时,自行将命令请求转发至其余节点。
由于客户端能够自由地向集群中的任何一个节点发送命令请求,并能够在有须要时,根据转向错误所提供的信息,将命令转发至正确的节点,因此在理论上来讲,客户端是无须保存集群状态信息的。
不过,若是客户端能够将键和节点之间的映射信息保存起来,能够有效地减小可能出现的转向次数,籍此提高命令执行的效率。
键分布模型?
Redis 集群的键空间被分割为 16384 个槽(slot),集群的最大节点数量也是 16384 个。
Note
推荐的最大节点数量为 1000 个左右。
每一个主节点都负责处理 16384 个哈希槽的其中一部分。
当咱们说一个集群处于“稳定”(stable)状态时,指的是集群没有在执行重配置(reconfiguration)操做,每一个哈希槽都只由一个节点进行处理。
Note
重配置指的是将某个/某些槽从一个节点移动到另外一个节点。
Note
一个主节点能够有任意多个从节点,这些从节点用于在主节点发生网络断线或者节点失效时,对主节点进行替换。
如下是负责将键映射到槽的算法:
HASH_SLOT = CRC16(key) mod 16384
如下是该算法所使用的参数:
算法的名称: XMODEM (又称 ZMODEM 或者 CRC-16/ACORN)
结果的长度: 16 位
多项数(poly): 1021 (也便是 x16 + x12 + x5 + 1)
初始化值: 0000
反射输入字节(Reflect Input byte): False
发射输出 CRC (Reflect Output CRC): False
用于 CRC 输出值的异或常量(Xor constant to output CRC): 0000
该算法对于输入 "123456789" 的输出: 31C3
附录 A 中给出了集群所使用的 CRC16 算法的实现。
CRC16 算法所产生的 16 位输出中的 14 位会被用到。
在咱们的测试中, CRC16 算法能够很好地将各类不一样类型的键平稳地分布到 16384 个槽里面。
集群节点属性?
每一个节点在集群中都有一个独一无二的 ID ,该 ID 是一个十六进制表示的 160 位随机数,在节点第一次启动时由 /dev/urandom 生成。
节点会将它的 ID 保存到配置文件,只要这个配置文件不被删除,节点就会一直沿用这个 ID 。
节点 ID 用于标识集群中的每一个节点。一个节点能够改变它的 IP 和端口号,而不改变节点 ID 。集群能够自动识别出 IP/端口号的变化,并将这一信息经过 Gossip 协议广播给其余节点知道。
如下是每一个节点都有的关联信息,而且节点会将这些信息发送给其余节点:
节点所使用的 IP 地址和 TCP 端口号。
节点的标志(flags)。
节点负责处理的哈希槽。
节点最近一次使用集群链接发送 PING 数据包(packet)的时间。
节点最近一次在回复中接收到 PONG 数据包的时间。
集群将该节点标记为下线的时间。
该节点的从节点数量。
若是该节点是从节点的话,那么它会记录主节点的节点 ID 。若是这是一个主节点的话,那么主节点 ID 这一栏的值为 0000000 。
以上信息的其中一部分能够经过向集群中的任意节点(主节点或者从节点均可以)发送 CLUSTER NODES 命令来得到。
如下是一个向集群中的主节点发送 CLUSTER NODES 命令的例子,该集群由三个节点组成:
$ redis-cli cluster nodes
d1861060fe6a534d42d8a19aeb36600e18785e04 :0 myself - 0 1318428930 connected 0-1364
3886e65cc906bfd9b1f7e7bde468726a052d1dae 127.0.0.1:6380 master - 1318428930 1318428931 connected 1365-2729
d289c575dcbc4bdd2931585fd4339089e461a27d 127.0.0.1:6381 master - 1318428931 1318428931 connected 2730-4095
在上面列出的三行信息中,从左到右的各个域分别是:节点 ID , IP 地址和端口号,标志(flag),最后发送 PING 的时间,最后接收 PONG 的时间,链接状态,节点负责处理的槽。
节点握手(已实现)?
节点老是应答(accept)来自集群链接端口的链接请求,并对接收到的 PING 数据包进行回复,即便这个 PING 数据包来自不可信的节点。
然而,除了 PING 以外,节点会拒绝其余全部并不是来自集群节点的数据包。
要让一个节点认可另外一个节点同属于一个集群,只有如下两种方法:
一个节点能够经过向另外一个节点发送 MEET 信息,来强制让接收信息的节点认可发送信息的节点为集群中的一份子。一个节点仅在管理员显式地向它发送 CLUSTER MEET ip port 命令时,才会向另外一个节点发送 MEET 信息。
另外,若是一个可信节点向另外一个节点传播第三者节点的信息,那么接收信息的那个节点也会将第三者节点识别为集群中的一份子。也便是说,若是 A 认识 B , B 认识 C ,而且 B 向 A 传播关于 C 的信息,那么 A 也会将 C 识别为集群中的一份子,并尝试链接 C 。
这意味着若是咱们将一个/一些新节点添加到一个集群中,那么这个/这些新节点最终会和集群中已有的其余全部节点链接起来。
这说明只要管理员使用 CLUSTER MEET 命令显式地指定了可信关系,集群就能够自动发现其余节点。
这种节点识别机制经过防止不一样的 Redis 集群由于 IP 地址变动或者其余网络事件的发生而产生意料以外的联合(mix),从而使得集群更具健壮性。
当节点的网络链接断开时,它会主动链接其余已知的节点。
MOVED 转向?
一个 Redis 客户端能够向集群中的任意节点(包括从节点)发送命令请求。节点会对命令请求进行分析,若是该命令是集群能够执行的命令,那么节点会查找这个命令所要处理的键所在的槽。
若是要查找的哈希槽正好就由接收到命令的节点负责处理,那么节点就直接执行这个命令。
另外一方面,若是所查找的槽不是由该节点处理的话,节点将查看自身内部所保存的哈希槽到节点 ID 的映射记录,并向客户端回复一个 MOVED 错误。
如下是一个 MOVED 错误的例子:
GET x
-MOVED 3999 127.0.0.1:6381
错误信息包含键 x 所属的哈希槽 3999 ,以及负责处理这个槽的节点的 IP 和端口号 127.0.0.1:6381 。客户端须要根据这个 IP 和端口号,向所属的节点从新发送一次 GET 命令请求。
注意,即便客户端在从新发送 GET 命令以前,等待了很是久的时间,以致于集群又再次更改了配置,使得节点 127.0.0.1:6381 已经再也不处理槽 3999,那么当客户端向节点 127.0.0.1:6381 发送 GET 命令的时候,节点将再次向客户端返回 MOVED 错误,指示如今负责处理槽 3999 的节点。
虽然咱们用 ID 来标识集群中的节点,可是为了让客户端的转向操做尽量地简单,节点在 MOVED 错误中直接返回目标节点的 IP 和端口号,而不是目标节点的 ID 。
虽然不是必须的,但一个客户端应该记录(memorize)下“槽 3999 由节点 127.0.0.1:6381 负责处理“这一信息,这样当再次有命令须要对槽 3999执行时,客户端就能够加快寻找正确节点的速度。
注意,当集群处于稳定状态时,全部客户端最终都会保存有一个哈希槽至节点的映射记录(map of hash slots to nodes),使得集群很是高效:客户端能够直接向正确的节点发送命令请求,无须转向、代理或者其余任何可能发生单点故障(single point failure)的实体(entiy)。
除了 MOVED 转向错误以外,一个客户端还应该能够处理稍后介绍的 ASK 转向错误。
集群在线重配置(live reconfiguration)?
Redis 集群支持在集群运行的过程当中添加或者移除节点。
实际上,节点的添加操做和节点的删除操做能够抽象成同一个操做,那就是,将哈希槽从一个节点移动到另外一个节点:
添加一个新节点到集群,等于将其余已存在节点的槽移动到一个空白的新节点里面。
从集群中移除一个节点,等于将被移除节点的全部槽移动到集群的其余节点上面去。
所以,实现 Redis 集群在线重配置的核心就是将槽从一个节点移动到另外一个节点的能力。由于一个哈希槽实际上就是一些键的集合,因此 Redis 集群在重哈希(rehash)时真正要作的,就是将一些键从一个节点移动到另外一个节点。
要理解 Redis 集群如何将槽从一个节点移动到另外一个节点,咱们须要对 CLUSTER 命令的各个子命令进行介绍,这些命理负责管理集群节点的槽转换表(slots translation table)。
如下是 CLUSTER 命令可用的子命令:
CLUSTER ADDSLOTS slot1 [slot2] ... [slotN]
CLUSTER DELSLOTS slot1 [slot2] ... [slotN]
CLUSTER SETSLOT slot NODE node
CLUSTER SETSLOT slot MIGRATING node
CLUSTER SETSLOT slot IMPORTING node
最开头的两条命令 ADDSLOTS 和 DELSLOTS 分别用于向节点指派(assign)或者移除节点,当槽被指派或者移除以后,节点会将这一信息经过 Gossip 协议传播到整个集群。 ADDSLOTS 命令一般在新建立集群时,做为一种快速地将各个槽指派给各个节点的手段来使用。
CLUSTER SETSLOT slot NODE node 子命令能够将指定的槽 slot 指派给节点 node 。
至于 CLUSTER SETSLOT slot MIGRATING node 命令和 CLUSTER SETSLOT slot IMPORTING node 命令,前者用于将给定节点 node 中的槽 slot 迁移出节点,然后者用于将给定槽 slot 导入到节点 node :
当一个槽被设置为 MIGRATING 状态时,原来持有这个槽的节点仍然会继续接受关于这个槽的命令请求,但只有命令所处理的键仍然存在于节点时,节点才会处理这个命令请求。
若是命令所使用的键不存在与该节点,那么节点将向客户端返回一个 -ASK 转向(redirection)错误,告知客户端,要将命令请求发送到槽的迁移目标节点。
当一个槽被设置为 IMPORTING 状态时,节点仅在接收到 ASKING 命令以后,才会接受关于这个槽的命令请求。
若是客户端没有向节点发送 ASKING 命令,那么节点会使用 -MOVED 转向错误将命令请求转向至真正负责处理这个槽的节点。
上面关于 MIGRATING 和 IMPORTING 的说明有些难懂,让咱们用一个实际的实例来讲明一下。
假设如今,咱们有 A 和 B 两个节点,而且咱们想将槽 8 从节点 A 移动到节点 B ,因而咱们:
向节点 B 发送命令 CLUSTER SETSLOT 8 IMPORTING A
向节点 A 发送命令 CLUSTER SETSLOT 8 MIGRATING B
每当客户端向其余节点发送关于哈希槽 8 的命令请求时,这些节点都会向客户端返回指向节点 A 的转向信息:
若是命令要处理的键已经存在于槽 8 里面,那么这个命令将由节点 A 处理。
若是命令要处理的键未存在于槽 8 里面(好比说,要向槽添加一个新的键),那么这个命令由节点 B 处理。
这种机制将使得节点 A 再也不建立关于槽 8 的任何新键。
与此同时,一个特殊的客户端 redis-trib 以及 Redis 集群配置程序(configuration utility)会将节点 A 中槽 8 里面的键移动到节点 B 。
键的移动操做由如下两个命令执行:
CLUSTER GETKEYSINSLOT slot count
上面的命令会让节点返回 count 个 slot 槽中的键,对于命令所返回的每一个键, redis-trib 都会向节点 A 发送一条 MIGRATE 命令,该命令会将所指定的键原子地(atomic)从节点 A 移动到节点 B (在移动键期间,两个节点都会处于阻塞状态,以避免出现竞争条件)。
如下为 MIGRATE 命令的运做原理:
MIGRATE target_host target_port key target_database id timeout
执行 MIGRATE 命令的节点会链接到 target 节点,并将序列化后的 key 数据发送给 target ,一旦 target 返回 OK ,节点就将本身的 key 从数据库中删除。
从一个外部客户端的视角来看,在某个时间点上,键 key 要么存在于节点 A ,要么存在于节点 B ,但不会同时存在于节点 A 和节点 B 。
由于 Redis 集群只使用 0 号数据库,因此当 MIGRATE 命令被用于执行集群操做时, target_database 的值老是 0 。
target_database 参数的存在是为了让 MIGRATE 命令成为一个通用命令,从而能够做用于集群之外的其余功能。
咱们对 MIGRATE 命令作了优化,使得它即便在传输包含多个元素的列表键这样的复杂数据时,也能够保持高效。
不过,尽管 MIGRATE 很是高效,对一个键很是多、而且键的数据量很是大的集群来讲,集群重配置仍是会占用大量的时间,可能会致使集群没办法适应那些对于响应时间有严格要求的应用程序。
ASK 转向?
在以前介绍 MOVED 转向的时候,咱们说除了 MOVED 转向以外,还有另外一种 ASK 转向。
当节点须要让一个客户端长期地(permanently)将针对某个槽的命令请求发送至另外一个节点时,节点向客户端返回 MOVED 转向。
另外一方面,当节点须要让客户端仅仅在下一个命令请求中转向至另外一个节点时,节点向客户端返回 ASK 转向。
好比说,在咱们上一节列举的槽 8 的例子中,由于槽 8 所包含的各个键分散在节点 A 和节点 B 中,因此当客户端在节点 A 中没找到某个键时,它应该转向到节点 B 中去寻找,可是这种转向应该仅仅影响一次命令查询,而不是让客户端每次都直接去查找节点 B :在节点 A 所持有的属于槽 8 的键没有所有被迁移到节点 B 以前,客户端应该先访问节点 A ,而后再访问节点 B 。
由于这种转向只针对 16384 个槽中的其中一个槽,因此转向对集群形成的性能损耗属于可接受的范围。
由于上述缘由,若是咱们要在查找节点 A 以后,继续查找节点 B ,那么客户端在向节点 B 发送命令请求以前,应该先发送一个 ASKING 命令,不然这个针对带有 IMPORTING 状态的槽的命令请求将被节点 B 拒绝执行。
接收到客户端 ASKING 命令的节点将为客户端设置一个一次性的标志(flag),使得客户端能够执行一次针对 IMPORTING 状态的槽的命令请求。
从客户端的角度来看, ASK 转向的完整语义(semantics)以下:
若是客户端接收到 ASK 转向,那么将命令请求的发送对象调整为转向所指定的节点。
先发送一个 ASKING 命令,而后再发送真正的命令请求。
没必要更新客户端所记录的槽 8 至节点的映射:槽 8 应该仍然映射到节点 A ,而不是节点 B 。
一旦节点 A 针对槽 8 的迁移工做完成,节点 A 在再次收到针对槽 8 的命令请求时,就会向客户端返回 MOVED 转向,将关于槽 8 的命令请求长期地转向到节点 B 。
注意,即便客户端出现 Bug ,过早地将槽 8 映射到了节点 B 上面,但只要这个客户端不发送 ASKING 命令,客户端发送命令请求的时候就会赶上MOVED 错误,并将它转向回节点 A 。
容错?
节点失效检测?
如下是节点失效检查的实现方法:
当一个节点向另外一个节点发送 PING 命令,可是目标节点未能在给定的时限内返回 PING 命令的回复时,那么发送命令的节点会将目标节点标记为PFAIL (possible failure,可能已失效)。
等待 PING 命令回复的时限称为“节点超时时限(node timeout)”,是一个节点选项(node-wise setting)。
每次当节点对其余节点发送 PING 命令的时候,它都会随机地广播三个它所知道的节点的信息,这些信息里面的其中一项就是说明节点是否已经被标记为 PFAIL 或者 FAIL 。
当节点接收到其余节点发来的信息时,它会记下那些被其余节点标记为失效的节点。这称为失效报告(failure report)。
若是节点已经将某个节点标记为 PFAIL ,而且根据节点所收到的失效报告显式,集群中的大部分其余主节点也认为那个节点进入了失效状态,那么节点会将那个失效节点的状态标记为 FAIL 。
一旦某个节点被标记为 FAIL ,关于这个节点已失效的信息就会被广播到整个集群,全部接收到这条信息的节点都会将失效节点标记为 FAIL 。
简单来讲,一个节点要将另外一个节点标记为失效,必须先询问其余节点的意见,而且获得大部分主节点的赞成才行。
由于过时的失效报告会被移除,因此主节点要将某个节点标记为 FAIL 的话,必须以最近接收到的失效报告做为根据。
在如下两种状况中,节点的 FAIL 状态会被移除:
若是被标记为 FAIL 的是从节点,那么当这个节点从新上线时, FAIL 标记就会被移除。
保持(retaning)从节点的 FAIL 状态是没有意义的,由于它不处理任何槽,一个从节点是否处于 FAIL 状态,决定了这个从节点在有须要时可否被提高为主节点。
若是一个主节点被打上 FAIL 标记以后,通过了节点超时时限的四倍时间,再加上十秒钟以后,针对这个主节点的槽的故障转移操做仍未完成,而且这个主节点已经从新上线的话,那么移除对这个节点的 FAIL 标记。
在第二种状况中,若是故障转移未能顺利完成,而且主节点从新上线,那么集群就继续使用原来的主节点,从而免去管理员介入的必要。
集群状态检测(已部分实现)?
每当集群发生配置变化时(多是哈希槽更新,也多是某个节点进入失效状态),集群中的每一个节点都会对它所知道的节点进行扫描(scan)。
一旦配置处理完毕,集群会进入如下两种状态的其中一种:
FAIL :集群不能正常工做。当集群中有某个节点进入失效状态时,集群不能处理任何命令请求,对于每一个命令请求,集群节点都返回错误回复。
OK :集群能够正常工做,负责处理所有 16384 个槽的节点中,没有一个节点被标记为 FAIL 状态。
这说明即便集群中只有一部分哈希槽不能正常使用,整个集群也会中止处理任何命令。
不过节点从出现问题到被标记为 FAIL 状态的这段时间里,集群仍然会正常运做,因此集群在某些时候,仍然有可能只能处理针对 16384 个槽的其中一个子集的命令请求。
如下是集群进入 FAIL 状态的两种状况:
至少有一个哈希槽不可用,由于负责处理这个槽的节点进入了 FAIL 状态。
集群中的大部分主节点都进入下线状态。当大部分主节点都进入 PFAIL 状态时,集群也会进入 FAIL 状态。
第二个检查是必须的,由于要将一个节点从 PFAIL 状态改变为 FAIL 状态,必需要有大部分主节点进行投票表决,可是,当集群中的大部分主节点都进入失效状态时,单凭一个两个节点是没有办法将一个节点标记为 FAIL 状态的。
所以,有了第二个检查条件,只要集群中的大部分主节点进入了下线状态,那么集群就能够在不请求这些主节点的意见下,将某个节点判断为 FAIL 状态,从而让整个集群中止处理命令请求。
从节点选举?
一旦某个主节点进入 FAIL 状态,若是这个主节点有一个或多个从节点存在,那么其中一个从节点会被升级为新的主节点,而其余从节点则会开始对这个新的主节点进行复制。
新的主节点由已下线主节点属下的全部从节点中自行选举产生,如下是选举的条件:
这个节点是已下线主节点的从节点。
已下线主节点负责处理的槽数量非空。
从节点的数据被认为是可靠的,也便是,主从节点之间的复制链接(replication link)的断线时长不能超过节点超时时限(node timeout)乘以REDIS_CLUSTER_SLAVE_VALIDITY_MULT 常量得出的积。
若是一个从节点知足了以上的全部条件,那么这个从节点将向集群中的其余主节点发送受权请求,询问它们,是否容许本身(从节点)升级为新的主节点。
若是发送受权请求的从节点知足如下属性,那么主节点将向从节点返回 FAILOVER_AUTH_GRANTED 受权,赞成从节点的升级要求:
发送受权请求的是一个从节点,而且它所属的主节点处于 FAIL 状态。
在已下线主节点的全部从节点中,这个从节点的节点 ID 在排序中是最小的。
这个从节点处于正常的运行状态:它没有被标记为 FAIL 状态,也没有被标记为 PFAIL 状态。
一旦某个从节点在给定的时限内获得大部分主节点的受权,它就会开始执行如下故障转移操做:
经过 PONG 数据包(packet)告知其余节点,这个节点如今是主节点了。
经过 PONG 数据包告知其余节点,这个节点是一个已升级的从节点(promoted slave)。
接管(claiming)全部由已下线主节点负责处理的哈希槽。
显式地向全部节点广播一个 PONG 数据包,加速其余节点识别这个节点的进度,而不是等待定时的 PING / PONG 数据包。
全部其余节点都会根据新的主节点对配置进行相应的更新,特别地:
全部被新的主节点接管的槽会被更新。
已下线主节点的全部从节点会察觉到 PROMOTED 标志,并开始对新的主节点进行复制。
若是已下线的主节点从新回到上线状态,那么它会察觉到 PROMOTED 标志,并将自身调整为现任主节点的从节点。
在集群的生命周期中,若是一个带有 PROMOTED 标识的主节点由于某些缘由转变成了从节点,那么该节点将丢失它所带有的 PROMOTED 标识。
发布/订阅(已实现,但仍然须要改善)?
在一个 Redis 集群中,客户端能够订阅任意一个节点,也能够向任意一个节点发送信息,节点会对客户端所发送的信息进行转发。
在目前的实现中,节点会将接收到的信息广播至集群中的其余全部节点,在未来的实现中,可能会使用 bloom filter 或者其余算法来优化这一操做。
附录 A: CRC16 算法的 ANSI 实现参考?
/*
* Copyright 2001-2010 Georges Menie (www.menie.org)
* Copyright 2010 Salvatore Sanfilippo (adapted to Redis coding style)
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the University of California, Berkeley nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* CRC16 implementation acording to CCITT standards.
*
* Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the
* following parameters:
*
* Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN"
* Width : 16 bit
* Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1)
* Initialization : 0000
* Reflect Input byte : False
* Reflect Output CRC : False
* Xor constant to output CRC : 0000
* Output for "123456789" : 31C3
*/
static const uint16_t crc16tab[256]= {
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
uint16_t crc16(const char *buf, int len) {
int counter;
uint16_t crc = 0;
for (counter = 0; counter < len; counter++)
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];
return crc;
}
Redis Cluster 功能特性
Redis 集群是分布式的redis 实现,具备如下特性:
1. 高可用性与可线性扩张到1000个节点
2. 数据自动路由到多个节点
3. 节点间数据共享
4. 可动态添加或者删除节点
5. 部分节点不可达时,集群仍可用
6. 数据经过异步复制,不保证数据的强一致性
7. 可动态调整数据分布
Redis 集群架构图
其中
一: Redis 集群协议
一、Redis 集群,节点负责存储数据、记录集群状态,集群节点能自动发现其余节点,检测出节点的状态,并在须要的时候,推选中主节点
二、Redis 集群节点中经过TCP链接和一个二级制协议(cluster bus) 创建通讯。发现新的节点、发送PING包、特定的状况下发送集群消息。集群链接可以发布与订阅消息
三、Redis 集群节点不能代理请求,客户端发起请求后,接收到重定向(MOVED\ASK)错误,会自动重定向到其余节点。理论上来讲,客户端是能够自由地向集群中的全部节点发送请求,在须要的时候把请求重定向到其余节点,因此客户端是不须要保存集群状态。 不过客户端能够缓存键值和节点之间的映射关系,这样能明显提升命令执行的效率。
二: 安全写入
Redis 集群节点之间使用异步复制,在分区过程当中存在窗口,容易致使丢失写入数据,Redis集群即便努力尝试全部写入,可是如下两种状况可能丢失数据:
一、命令操做到达主节点后,但在主节点回复的时候,此时写入可能尚未经过主节点复制到从节点那里。若是这时候主库宕机了,这条命令永久丢失。以防主节点长时间不可达而它的一个从节点已经被提高为主节点。
二、分区致使一个主节点不可达,然而集群发送故障转移(failover),提高从节点为主节点,原来的主节点再次恢复。一个没有更新路由表(routing table)的客户端或许会在集群把这个主节点变成一个从节点(新主节点的从节点)以前对它进行写入操做。致使数据完全丢失
三: 可用性
Redis 集群少数节点不可用后,在通过cluster-node-timeout时间后,集群根据自动故障机制,将从节点提高为主节点。这事集群恢复可用
举个例子,一个由 N 个主节点组成的集群,每一个主节点都只有一个从节点。当有一个节点(由于故障)被分割出去后,集群的多数节点这边仍然是可访问的。当有两个节点(因故障)被分割出去后集群仍可用的几率是 1-(1/(N*2-1))(在第一个节点故障出错后总共剩下 N*2-1 个节点,那么失去冗余备份(即失去从节点)的那个主节点也故障出错的几率是 1/(N*2-1)))。
好比一个拥有6个节点的集群,每一个节点都只有一个从节点,那么在两个节点从多数节点这边分割出去后集群再也不可用的几率是 1/(6*2-1) = 0.0909,即有大约 9% 的几率。
Redis 集群数据分布
Redis 集群没有使用一致性hash,引入了哈希槽(HASH SLOT).
Redis 集群中全部的主节点都负责 16384 个哈希槽中的一部分。当集群处于稳定状态时,集群中没有在执行重配置(reconfiguration)操做,每一个哈希槽都只由一个节点进行处理(不过主节点能够有一个或多个从节点,能够在网络断线或节点失效时替换掉主节点)
slot = CRC16(KEY) / 16384
Redis 集群键HASH标签
目标:
HASH 标签是确保两个KEY 都能在同一个HASH槽的一种方式。
实现方式:
HASH 槽是用另外一种不一样的计算方式计算的。基原本说,若是KEY包含一个"{...}"这样的模式,只有“{” 和 “}” 之间的字符串会被用来作HASH以获取HAS槽。若是同时出现多个“{}” 计算方式以下:
* 若是KEY 包含一个 “{” 字符
* 那么在 “{”的右边就会字符 "}"
* 在字符 "{" 和 "}"直接会有一个或多个字符。可是第一个"}" 必定会出如今第一个"{"以后
* 只有在第一个 { 和它右边第一个 } 之间的内容会被用来计算哈希值
例子:
一、好比这两个键 user:{1000}.following 和user:{1000}.followers 会被哈希到同一个哈希槽里,由于只有 "1000" 这个子串会被用来计算哈希值。
二、对于 user{}{list} 这个键,整个键都会被用来计算哈希值,由于第一个出现的 { 和它右边第一个出现的 } 之间没有任何字符。
三、对于 user{{momoid}}following 这个键,用来计算哈希值的是 "{momoid" 这个子串,由于它是第一个 { 及其右边第一个 } 之间的内容。
四、对于 user{momoid}{following} 这个键,用来计算哈希值的是 "momoid" 这个子串,由于算法会在第一次有效或无效(好比中间没有任何字节)地匹配到 { 和 } 的时候中止。
五、按照这个算法,若是一个键是以 {} 开头的话,那么就看成整个键会被用来计算哈希值。当使用二进制数据作为键名称的时候,这是很是有用的。
Redis 集群相关命令
集群
一、CLUSTER INFO 打印集群的信息
二、CLUSTER NODES 列出集群当前已知的全部节点(node),以及这些节点的相关信息。
三、CLUSTER FAILOVER 手动故障转移,须要在转移的主节点的从节点上执行
节点
一、CLUSTER MEET 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
二、CLUSTER FORGET 从集群中移除 node_id 指定的节点。
三、CLUSTER REPLICATE 将当前节点设置为 node_id 指定的节点的从节点。
四、CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
槽(slot)
一、CLUSTER ADDSLOTS [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
二、CLUSTER DELSLOTS [slot ...] 移除一个或多个槽对当前节点的指派。
三、CLUSTER FLUSHSLOTS 移除指派给当前节点的全部槽,让当前节点变成一个没有指派任何槽的节点。
四、CLUSTER SETSLOT NODE 将槽 slot 指派给 node_id 指定的节点,若是槽已经指派给另外一个节点,那么先让另外一个节点删除该槽,而后再进行指派。
一、CLUSTER SETSLOT MIGRATING 将本节点的槽 slot 迁移到 node_id 指定的节点中。
二、CLUSTER SETSLOT IMPORTING 从 node_id 指定的节点中导入槽 slot 到本节点。
三、CLUSTER SETSLOT STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
键
一、CLUSTER KEYSLOT 计算键 key 应该被放置在哪一个槽上。
二、CLUSTER COUNTKEYSINSLOT 返回槽 slot 目前包含的键值对数量。
三、CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。
不支持的命令:
一、不支持SELECT 命令,集群只使用数据库 0
二、不支持多个KEY的操做 如 MSET、SUION、SINTER等命令 (由于KEYS 没法hash到同一个slot中)
redis-trib.rb 相关命令
一、redis-trib.rb create [--replicas N] host:ip [host:ip ...] 建立集群
二、redis-trib.rb add-node host:ip host:ip 将前面的host:ip 添加到集群中
三、redis-trib.rb check host:ip 检查集群的状态
四、redis-trib.rb reshard host:ip OR redis-trib.rb reshard --from host:port --to host:port --slots --yes集群从新分片
五、redis-trib.rb del-node host:ip 'NODE ID' 将节点从集群中移除
Redis 集群配置
redis 集群须要运行在 集群模式的redis实例,不是普通的redis实例。集群模式须要添加集群相关的配置。开启集群模式的redis实例,可使用集群特有的命令和特性
其中相关配置以下:
必须配置:
cluster-enabled yes --> 开启集群模式
cluster-config-file nodes-30000.conf --> 集群相关的信息
cluster-node-timeout 15000 --> 节点超时时间,用来failover的操做
可选配置:
cluster-slave-validity-factor 10
cluster-migration-barrier 1
cluster-require-full-coverage yes
Redis Cluster 主从搭建
启动集群模式的实例(与普通启动方式一致),不需搭建主从关系
搭建集群: 在上述启动的6个redis实例中,搭建集群。经过redis自带的集群命令行工具 redis-trib.rb 。 redis-trib.rb 位于redis源码包中src文件中。它能够完成建立集群、检查集群、集群reshard、添加节点、删除节点等操做
建立集群 redis-trib.rb create [–replicas [N]] host:ip [host:ip]
redis-trib.rb create --replicas 1 127.0.0.1:30000 127.0.0.1:30001 127.0.0.1:30001 127.0.0.1:31000 127.0.0.1:31001 127.0.0.1:31002
其中 --replicas N 选项代表集群中的每一个节点带几个从节点
输出日志:
[OK] All 16384 slots covered
集群状态检查 redis-trib.rb check host:ip
redis-trib.rb check 127.0.0.1:30000
输出日志:
Connecting to node 127.0.0.1:30000: OK
Connecting to node 127.0.0.1:30002: OK
Connecting to node 127.0.0.1:31000: OK
Connecting to node 127.0.0.1:31001: OK
Connecting to node 127.0.0.1:30001: OK
Connecting to node 127.0.0.1:31002: OK
>>> Performing Cluster Check (using node 127.0.0.1:30000)
M: 36801ef9849f12526be1e954f9e6f6fa24c50d46 127.0.0.1:30000
slots:0-5961,10923-11421 (6461 slots) master
1 additional replica(s)
M: 98c4c66ee189569dec47a9600b057f90626cc6a7 127.0.0.1:30002
slots:11422-16383 (4962 slots) master
1 additional replica(s)
S: 54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 127.0.0.1:31000
slots: (0 slots) slave
replicates 36801ef9849f12526be1e954f9e6f6fa24c50d46
S: 3f5ae989b9b1b6617c53e77ed4853b618408bbe6 127.0.0.1:31001
slots: (0 slots) slave
replicates 6b880ae14f8c9dbfd54f8c4811cf0c039d523216
M: 6b880ae14f8c9dbfd54f8c4811cf0c039d523216 127.0.0.1:30001
slots:5962-10922 (4961 slots) master
1 additional replica(s)
S: 81a3a70ce2fbb8bcce2e9be9ed77e34d9d4d5b21 127.0.0.1:31002
slots: (0 slots) slave
replicates 98c4c66ee189569dec47a9600b057f90626cc6a7
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
添加节点: 启动一个新的集群模式的redis实例。使用 redis-trib.rb add-node host:ip host:ip
redis-trib.rb add-node 127.0.0.1:30004 127.0.0.1:3000
其中 127.0.0.1:30004 为新节点 127.0.0.1:30000 为集群中任意节点
查看集群节点:
redis-cli -c -p 30000
127.0.0.1:30000> CLUSTER NODES
98c4c66ee189569dec47a9600b057f90626cc6a7 127.0.0.1:30002 master - 0 1429686483614 3 connected 11422-16383
54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 127.0.0.1:31000 slave 36801ef9849f12526be1e954f9e6f6fa24c50d46 0 1429686485615 7 connected
3f5ae989b9b1b6617c53e77ed4853b618408bbe6 127.0.0.1:31001 slave 6b880ae14f8c9dbfd54f8c4811cf0c039d523216 0 1429686484614 5 connected
2eb135bf03dbdbc57e704578b2833cc3fb860b6e 127.0.0.1:30004 master - 0 1429686479607 0 connected --> 新节点
6b880ae14f8c9dbfd54f8c4811cf0c039d523216 127.0.0.1:30001 master - 0 1429686481612 2 connected 5962-10922
81a3a70ce2fbb8bcce2e9be9ed77e34d9d4d5b21 127.0.0.1:31002 slave 98c4c66ee189569dec47a9600b057f90626cc6a7 0 1429686482613 6 connected
36801ef9849f12526be1e954f9e6f6fa24c50d46 127.0.0.1:30000 myself,master - 0 0 7 connected 0-5961 10923-11421
输出信息解析:
一、节点ID
二、IP:PORT
三、节点状态标识: master、slave、myself、fail?、fail
四、若是是从节点,表示主节点的ID。若是是主节点,为 '-'
五、集群最近一次向各个节点发送PING命令后,过去多长时间尚未接到回复
六、节点最近一次返回PONG的时间戳
七、节点的配置纪元
八、本节点的网络链接状况: connected、disconnected
九、若是是主节点,表示节点包含的曹
添加从节点: CLUSTER REPLICATE ID
127.0.0.1:31004> CLUSTER REPLICATE 2eb135bf03dbdbc57e704578b2833cc3fb860b6e
其中 2eb135bf03dbdbc57e704578b2833cc3fb860b6e 为主库的集群ID
集群reshard: 为新节点分片slots redis-trib.rb reshard host:port
redis-trib.rb reshard 127.0.0.1:30004
日志输出:
Shell# redis-trib.rb reshard 127.0.0.1:30004
Connecting to node 127.0.0.1:30004: OK
Connecting to node 127.0.0.1:30000: OK
Connecting to node 127.0.0.1:31001: OK
Connecting to node 127.0.0.1:30001: OK
Connecting to node 127.0.0.1:31000: OK
Connecting to node 127.0.0.1:30002: OK
Connecting to node 127.0.0.1:31002: OK
>>> Performing Cluster Check (using node 127.0.0.1:30004)
M: 2eb135bf03dbdbc57e704578b2833cc3fb860b6e 127.0.0.1:30004 --> 新节点信息
slots: (0 slots) master
0 additional replica(s)
M: 36801ef9849f12526be1e954f9e6f6fa24c50d46 127.0.0.1:30000
slots:0-5961,10923-11421 (6461 slots) master
1 additional replica(s)
S: 3f5ae989b9b1b6617c53e77ed4853b618408bbe6 127.0.0.1:31001
slots: (0 slots) slave
replicates 6b880ae14f8c9dbfd54f8c4811cf0c039d523216
M: 6b880ae14f8c9dbfd54f8c4811cf0c039d523216 127.0.0.1:30001
slots:5962-10922 (4961 slots) master
1 additional replica(s)
S: 54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 127.0.0.1:31000
slots: (0 slots) slave
replicates 36801ef9849f12526be1e954f9e6f6fa24c50d46
M: 98c4c66ee189569dec47a9600b057f90626cc6a7 127.0.0.1:30002
slots:11422-16383 (4962 slots) master
1 additional replica(s)
S: 81a3a70ce2fbb8bcce2e9be9ed77e34d9d4d5b21 127.0.0.1:31002
slots: (0 slots) slave
replicates 98c4c66ee189569dec47a9600b057f90626cc6a7
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 1000 --> slot数量
What is the receiving node ID? 2eb135bf03dbdbc57e704578b2833cc3fb860b6e --> 接收集群NODE ID
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1:36801ef9849f12526be1e954f9e6f6fa24c50d46 --> 来源NODE ID
Source node #2:done
......
Redis Cluster failover机制
节点心跳
Redis 集群在运行的过程当中,每一个节点每秒会随机ping几个节点,不过每一个节点都会保证去PING知足这个条件的其余节点:在过去的一半"cluster-node-timeout"时间里都没有发送PING包过去或者没有接收从那节点发来的PONG包的节点。在"cluster-node-timeout"时间过去以前,若TCP链接有问题,节点会尝试去重试链接,确保本身不会被当作不可达的节点。
若是 “cluster-node-time” 被设为一个很小的数而节点数量(N)很是大,那么消息交流数量会比 O(N) 更大,由于每一个节点都会尝试去 ping 每个在过去一半 NODE_TIMEOUT 时间里都没更新信息的节点。
失效检测
Redis 集群失效检测是用来识别出大多数节点什么时候没法访问某一个主节点或从节点。当这个事件发生时,就提高一个从节点来作主节点;若若是没法提高从节点来作主节点的话,那么整个集群就置为错误状态并中止接收客户端的查询
每一个节点都有一份跟其余已知节点相关的标识列表。其中有两个标识是用于失效检测,分别是 PFAIL 和 FAIL.
PFAIL 标识: 表示可能失效(Possible failure),这是一个非公认的(non acknowledged)失效类型。
当一个节点在超过 "cluster-node-timeout" 时间后仍没法访问某个节点,那么它会用 PFAIL 来标识这个不可达的节点。不管节点类型是什么,主节点和从节点都能标识其余的节点为 PFAIL
FAIL 表示一个节点已经失效,并且这个状况已经被大多数主节点在某段固定时间内确认过的了。
知足如下条件,PFAIL 状态升级为 FAIL 状态:(设定集群含有 A B C AS BS CS 六个节点)
一、节点A正常,节点C 状态为 PFAIL
二、节点A 经过gossip字段收集集群中大部分节点标识节点C的状态信息
三、若是大部分节点标识节点C为 PFAIL 状态,或者 cluster-node-timeout * FAIL_REPORT_VALIDITY_MULT 这段时间内处于 PFAIL状态
此时节点A 会标记 节点C 为 FAIL 状态,并向全部的节点发送关于节点C的 FAIL 信息。 FAIL 信息会强制接收的节点把节点C 标识为 FAIL 状态
NOTE:
FAIL 标识基本都是单向的,也就是说,一个节点能从 PFAIL 状态升级到 FAIL 状态. 清除FAIL状态的方法:
一、节点已经恢复可达的,而且它是一个从节点。在这种状况下,FAIL 标识能够清除掉,由于从节点并无被故障转移。
二、节点已经恢复可达的,并且它是一个主节点,但通过了很长时间(N * NODE_TIMEOUT)后也没有检测到任何从节点被提高了。
从选举与提高
从节点的选举与提高都是由从节点处理的,主节点会投票要提高哪一个从节点。当知足如下条件,一个节点能够发起选举:
一、该从节点的主节点处理 FALI 状态
二、这个主节点负责的HASH曹个数不为O
三、从节点和主节点之间的重复链接(replication link)断线不超过一段给定的时间,这是为了确保从节点的数据是可靠
一旦从节点被推选出来,就会想主节点请求投票,一旦从节点赢得投票,它会响全部其余节点发送PING 和 PONG 数据包,宣布本身已经成为主节点,而且提供它的HASH槽信息,并配置 currentEpoch 信息
为了加速其余节点的从新配置,该节点会广播一个 pong 包 给集群里的全部节点(那些如今访问不到的节点最终也会收到一个 ping 包或 pong 包,而且进行从新配置)。其余节点会检测到有一个新的主节点(带着更大的configEpoch)在负责处理以前一个旧的主节点负责的哈希槽,而后就升级本身的配置信息。 旧主节点的从节点,或者是通过故障转移后从新加入集群的该旧主节点,不只会升级配置信息,还会配置新主节点的备份。
模拟宕机(实现故障转移)
集群当期转态:
127.0.0.1:30000> CLUSTER NODES
98c4c66ee189569dec47a9600b057f90626cc6a7 127.0.0.1:30002 master - 0 1429696352375 3 connected 11422-16383
54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 127.0.0.1:31000 slave 36801ef9849f12526be1e954f9e6f6fa24c50d46 0 1429696349869 9 connected
3f5ae989b9b1b6617c53e77ed4853b618408bbe6 127.0.0.1:31001 slave 6b880ae14f8c9dbfd54f8c4811cf0c039d523216 0 1429696346364 5 connected
6b880ae14f8c9dbfd54f8c4811cf0c039d523216 127.0.0.1:30001 master - 0 1429696351373 2 connected 5962-10922
81a3a70ce2fbb8bcce2e9be9ed77e34d9d4d5b21 127.0.0.1:31002 slave 98c4c66ee189569dec47a9600b057f90626cc6a7 0 1429696350370 6 connected
36801ef9849f12526be1e954f9e6f6fa24c50d46 127.0.0.1:30000 myself,master - 0 0 9 connected 0-5961 10923-11421
其中 127.0.0.1:31000 节点为 127.0.0.1:30000 从节点
关闭其中的一个节点后(127.0.0.1:30000)的集群状态:
127.0.0.1:30001> CLUSTER NODES
81a3a70ce2fbb8bcce2e9be9ed77e34d9d4d5b21 127.0.0.1:31002 slave 98c4c66ee189569dec47a9600b057f90626cc6a7 0 1429696448146 6 connected
98c4c66ee189569dec47a9600b057f90626cc6a7 127.0.0.1:30002 master - 0 1429696447143 3 connected 11422-16383
6b880ae14f8c9dbfd54f8c4811cf0c039d523216 127.0.0.1:30001 myself,master - 0 0 2 connected 5962-10922
36801ef9849f12526be1e954f9e6f6fa24c50d46 127.0.0.1:30000 master,fail? - 1429696434521 1429696430116 9 disconnected 0-5961 10923-11421
3f5ae989b9b1b6617c53e77ed4853b618408bbe6 127.0.0.1:31001 slave 6b880ae14f8c9dbfd54f8c4811cf0c039d523216 0 1429696445139 5 connected
54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 127.0.0.1:31000 slave 36801ef9849f12526be1e954f9e6f6fa24c50d46 0 1429696449148 9 connected
其中 127.0.0.1:30000 的状态fail? 表示正在判断是否失败
127.0.0.1:30001> CLUSTER NODES
81a3a70ce2fbb8bcce2e9be9ed77e34d9d4d5b21 127.0.0.1:31002 slave 98c4c66ee189569dec47a9600b057f90626cc6a7 0 1429696473317 6 connected
98c4c66ee189569dec47a9600b057f90626cc6a7 127.0.0.1:30002 master - 0 1429696474317 3 connected 11422-16383
6b880ae14f8c9dbfd54f8c4811cf0c039d523216 127.0.0.1:30001 myself,master - 0 0 2 connected 5962-10922
36801ef9849f12526be1e954f9e6f6fa24c50d46 127.0.0.1:30000 master,fail - 1429696434521 1429696430116 9 disconnected
3f5ae989b9b1b6617c53e77ed4853b618408bbe6 127.0.0.1:31001 slave 6b880ae14f8c9dbfd54f8c4811cf0c039d523216 0 1429696472315 5 connected
54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 127.0.0.1:31000 master - 0 1429696471313 10 connected 0-5961 10923-11421
其中 127.0.0.1:30000 的状态 fail 表示节点失败,127.0.0.1:30000 节点提高为主库。
恢复关闭的实例
127.0.0.1:30001> CLUSTER NODES
81a3a70ce2fbb8bcce2e9be9ed77e34d9d4d5b21 127.0.0.1:31002 slave 98c4c66ee189569dec47a9600b057f90626cc6a7 0 1429696545465 6 connected
98c4c66ee189569dec47a9600b057f90626cc6a7 127.0.0.1:30002 master - 0 1429696542960 3 connected 11422-16383
6b880ae14f8c9dbfd54f8c4811cf0c039d523216 127.0.0.1:30001 myself,master - 0 0 2 connected 5962-10922
36801ef9849f12526be1e954f9e6f6fa24c50d46 127.0.0.1:30000 slave 54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 0 1429696542458 10 connected
3f5ae989b9b1b6617c53e77ed4853b618408bbe6 127.0.0.1:31001 slave 6b880ae14f8c9dbfd54f8c4811cf0c039d523216 0 1429696546467 5 connected
54d7d1241b1d9c24f76d99e9814d8cf8d8db474e 127.0.0.1:31000 master - 0 1429696547470 10 connected 0-5961 10923-11421
其中 127.0.0.1:30000 变成 127.0.0.1:31000的从库
总结:
优势: 一、redis 在主节点下线后,从节点会自动提高为主节点,提供服务 二、redis 宕机节点恢复后,自动会添加到集群中,变成从节点缺点: 一、因为redis的复制使用异步机制,在自动故障转移的过程当中,集群可能会丢失写命令。然而 redis 几乎是同时执行(将命令恢复发送给客户端,以及将命令复制到从节点)这两个操做,因此实际中,命令丢失的窗口很是小。--------------------- 做者:An_angel_of_joy 来源:CSDN 原文:https://blog.csdn.net/u010258235/article/details/50060127 版权声明:本文为博主原创文章,转载请附上博文连接!