Redis集群是一个分布式、容错的Redis实现,集群实现了单机Redis中所有单个数据键的命令,它是普通单机Redis的一个子集。
Redis集群的键分布模型:Redis的键空间被分割为16384个哈希槽,集群的最大节点数也是16384(推荐最大节点数为1000个左右)。集群为每个节点分配一定的哈希槽,客户端根据(CRC16(key) mod 16384)的值得到哈希槽,并根据哈希槽和节点ID 的映射关系找到目标节点。
Redis集群的MOVED和ASK转向
1、 MOVED转向:客户端向集群中的任意节点发送命令请求,节点先会对命令请求进行分析,如果命令请求是集群可以执行的命令,那么节点会查找这个命令的键所在的哈希槽。如果查找到的哈希槽正好是接收该命令请求的节点负责处理,那么节点直接执行命令,如果查找的哈希槽不在当前节点上,节点将查自身内部所保存的哈希槽到节点ID的映射记录,并向客户端回复一个MOVED转向。
2、 ASK转向:在将哈希槽10从节点A迁移到B的过程中,客户端发送一个命令请求到A节点,A节点检查命令请求的键是否在节点上,如果在则执行命令请求,否则,A节点会响应一个ASK定向给客户端,告知客户端目标节点是B节点。客户端在收到ASK定向之后,向B节点发送一个ASKING的命令,然后再发送命令请求。B节点如果没有收到ASKING的命令,是不会处理客户端的命令请求。
Redis集群的容错机制
1、主从复制:集群中的主节点可以有多个从节点,他们的功能相同,数据一致,当主节点故障,集群选举该主节点的一个从节点当主节点,保障集群能继续使用。
2、节点失效检测:
(1) 当节点向另外一个节点发送PING命令,但目标节点未能在给定时限内返回回复,那么发送PING命令的节点会将目标节点标记为PFAIL(possible failtrue)。
(2) 每当节点向其它节点发送PING命令时,都会随机的广播三个它所知道的节点信息,信息包括PFAIL和FAIL。
(3) 当节点收到其他节点发过来的信息,会记录下那些已经被其他节点标记为失效的节点,这个过程叫失效报告(failure report)。
(4) 如果节点已经将某个节点标记为PFAIL,并根据失效报告知道集群中其他节点也认为这个节点进入失效,那么会将该节点的状态标识为FAIL。
(5) 一旦某个节点被标识为FAIL状态,关于这个节点已失效的信息就会被广播到这个集群,所有接收到这个信息的节点都会将失效节点标识为FAIL状态。
节点的FAIL状态会在以下两种情况下被移除:
(1)被标识的是从节点,从节点重新上线后标识被移除。保持一个从节点的FAIL状态没什么意义,因为它不处理任何哈希槽,一个从节点处于FAIL状态,不能提升为主节点。
(2)如果一个主节点被打上FAIL标识后,经过了节点超时时限的4倍又10秒钟后,针对这个节点的故障尚未移除,主节点重新上线,FAIL标识被移除。
3、集群状态检测:集群进入FAIL状态有以下两种情况,
(1)至少有一个哈希槽不可用,因为负责这个槽的节点进入FAIL状态。
(2)集群中的大部分的节点都进入PFAIL状态,集群也会进入FAIL状态。
4、节点选举机制:一个从节点被选举成为一个主节点的条件:
(1)这个节点是失效节点的从节点。
(2)已失效主节点处理的槽数为空。
(3)从节点的数据被认为是可靠的。也就是,主从节点之间的复制
连接的断线时长不能超过节点超时时限(node timeout)乘以
REDIS_CLUSTER_SLAVE_VALIDITY_MULT 常量得出的积。
以上条件满足后,从节点向其他主节点发送授权请求,请求让自己成为新的主节点。如果授权请求满足以下属性,集群中的主节点将向从节点返回授权:
(1)发送请求的是一个从节点,并且它所属的主节点是FAIL状态。
(2)已下线主节点的从节点中,这个节点的ID在排序中是最小。
(3)这个从节点正常,没有标识为PFAIL或FAIL。
一旦从节点获得大多数主节点的授权,那它会执行以下故障转移:
(1)通过PONG数据包告知其他节点,这个节点已经是主节点了。
(2)通过PONG数据包告知其他节点,这个节点是一个已升级的从
节点。
(3)接管已失效主节点的哈希槽。
(4)向所有节点广播一个PONG数据包,加速其他节点识别该节点。
所有其他节点根据新的主节点更新相应配置:
(1)所有被新的主节点接管的哈希槽都会被更新。
(2)已下线主节点的所有从节点会察觉到 PROMOTED 标志,开始对新的主节点进行复制。
(3)如果已下线的主节点重新回到上线状态, 那么它会察觉到 PROMOTED 标志, 并将自身调整为现任主节点的从节点
Redis集群数据弱一致性
在以下条件下,Redis集群可能会丢失已经被执行过的写入命令。
1、异步复制:
(1)客户端向主节点发送一条写命令;
(2)主节点执行写命令并向客户端返回执行结果;
(3)主节点将刚刚执行的写命令复制给它的从节点。如果主节点在此时失效,数据还未复制到从节点,会导致数据的丢失。
2、网络分裂:产生网络分裂时,集群会分成大多数一方和少数一方,
假如少数一方包括A节点和C客户端,当C客户端写入A节点时,
大多数方已经推举了A节点的从节点A1为新的主节点,此时,C
客户端写入A节点的命令会丢失。
Redis集群的扩容策略
Redis集群支持在线重配置,它包括添加一个新的节点到集群或者从集群上删除一个节点。新添加节点等同于将其他已存在在节点的哈希槽迁移到一个新节点里面,删除一个节点等同于将该节点上的哈希槽迁移到其他节点上。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 将给定的槽迁入节点
当一个哈希槽被设置为MIGRATING时,原来持有这个槽的节点仍然会处理关于这个槽的命令请求,但只有该命令所处理的键仍然存在于节点时,节点才会处理这个命令请求。如果命令所处理的键不在节点上,那么节点将向客户端返回一个ASK转向请求,告知客户端要将命令请求发送到哈希槽的迁移目标上。
当一个哈希槽被设置为IMPORTING时,节点仅在接收到ASKING命令后才处理该哈希槽的命令请求。
如果客户端没有向节点发送 ASKING 命令, 那么节点会使用 -MOVED 转向错误将命令请求转向至真正负责处理这个槽的节点。
假设现在我们有A和B两个节点,并且我们想将槽10从节点A迁移到节点B,于是我们:
• 向节点 B 发送命令 CLUSTER SETSLOT 10 IMPORTING A
• 向节点 A 发送命令 CLUSTER SETSLOT 10 MIGRATING B
每当客户端向其他节点发送关于哈希槽10的的命令请求时,这些节点都会向客户端返回指向节点A的转向信息:
(1)如果要处理的键在槽10里面,那么该命令由A节点处理。
(2)如果命令要处理的键不在槽10里面(比如新增一个键值),那么这个命令由B处理。