ASK 重定向
在之前的章节我们说了一下ASK重定向,为什么我们不能只是简单的使用 MOVED 重定向?因为如果使用MOVED命令则有可能会为一个key轮询集群中所有的节点,而ASK命令只询问下一个节点。
ASK是必要的因为在对于hash slot8的下一次查询命令依然是发送给A节点,我们希望客户端先尝试在A节点找数据然后在获取不到的情况下再向B节点请求数据。
然后我们真正的需求是客户端在向A节点请求数据失败后仅尝试向B节点请求数据而不再轮询。节点B将只接受带ASKING命令的IMPORTING 数据查询。
简单说,ASKING 命令给IMPORTING slot添加了一个只轮询一次的标记。
TODO Pipelining: use MULTI/EXEC for pipelining.
TODO Persistent connections to nodes.
TODO hash slot guessing algorithm.
单点故障
节点故障侦测
故障侦测使用以下方法实现:
①如果一个节点没有在给定时间内回复PING请求,则该一个节点会被其他节点设置 PFAIL 标志(possible failure 有可能故障)
②如果一个节点被设置 PFAIL 标志,那么对目标节点设置 PFAIL 标志的节点会在节点之间互相进行广播通知并通知其他节点发送PING请求
③如果有一个节点被设置 PFAIL 标志,并且其他节点也认同其为 PFAIL 状态,那么该节点会被设置为 FAIL 状态(故障)
④一旦一个节点被设置 FAIL 标志,那么对故障节点设置 FAIL 标志的节点会通知其余所有节点
所以实际只有大多数节点认同的情况下,一个节点才会被设置为故障状态
(还在努力实现)一旦一个节点被设置为故障,那么其他任何节点收到来自故障节点的PING或者连接请求则会返回“MARK AS FAIL”从而强制故障节点把自己设置为故障
集群状态侦测(目前仅实现了一部分):每当集群配置文件发生变更,所有集群节点都会重新扫描节点列表(这可以是由更改一个hash slot 或者只是一个节点故障造成的)
每个被扫描的节点会返回以下状态中的一个:FAIL:节点故障;OK:节点正常。
这意味着Redis集群被设计为有能力拒绝对故障节点的查询。然而这里有一个特例,就是一个节点从被设置为 PFAIL 到被设置为 FAIL 是有时间差的,如果仅仅是被设置为 PFAIL 还是有可能对该节点尝试连接
另外,Redis集群将不再支持MULTI/EXEC批量方法
从节点推举制度(未实现)
每个主节点可以拥有0个或者多个从节点。当主节点发生故障的时候,从节点有责任/义务推举自己成为主节点。假设我们有A1,A2,A3三个节点,A1是主节点并且A2和A3为A1的从节点
如果A1发生故障并且长时间未回复PING请求,那么其他节点将会将A1标记为故障节点。当这种情况发生的时候,第一个从节点将会尝试推举自己为主节点。
定义第一个从节点非常简单。取所有从节点中节点ID最小的那个。如果第一个从节点也被标记为故障,那么就由第二个从节点推举自己,以此类推。
实际流程是:集群配置被变更(节点故障导致的),故障节点所有的从节点检测自己是否是第一个从节点。从节点在升级为主节点后会通知其他节点更改配置
保护模式(未实现)
如果部分节点由于网络原因被隔离(比如断网),则这些节点会停止判断其他节点是否正常,而会开始从节点推举或者其他操作去更改集群配置。为了防止这种情况发生,节点间一旦发现大部分节点在一段时间内被标记为 PFAIL 或者 FAIL 状态则会立即让集群启动保护模式以阻止集群采取任何行动(更改配置)。
一旦集群状态恢复正常则保护模式会被取消
主节点多数原则(未完成)
对于发生网络故障的情况,2个或者更多的分片有能力处理所有的hash slots。而这会影响集群数据的一致性,所以网络故障应该导致0或者只有1个分区可用。
为了强制此规则生效,所有符合主节点多数原则的节点应该强制不处理任何命令。
Publish/Subscribe(已实现,但是会重定义)
在一个Redis集群中,所有节点都被允许订阅其他节点或者对其他节点进行广播。集群系统会保证所有的广播通知给所有节点。
目前的实现仅仅是简单的一一进行广播,但是在某种程度上广播应该使用bloom filters或者其他算法进行优化。