基站建设提速 应用领域拓展
|
9、客户端的读写操作 客户端要读取、写入数据时,虽然client可以连接任意server,但是实际中,client需要根据实际需求连接到server读取、写入数据。client需要先根据key计算出hash slot,连接到负责这个hash slot的节点进行读写操作。这样的话,client就要需要知道hash slot -> node的映射关系,也就是需要知道hash slot map。 前面讲过hash slot map被保存在server端的每个节点上。client可以从任意节点获取hash slot map,并且把它缓存到client本地,下次操作时根据本地缓存直接进行操作,但是需要处理缓存信息过期的问题,如果client发现hash slot map发生变化(即client读取写入数据时server回错误,接下来会详细讲述),会重新从server端获取新的hash slot map。通过hash slot map可以判断某个key应该存在在哪个节点上,client再连接这个节点进行读写操作。 10、MOVED Redirection hash slot map会发生变更,这些变更会复制到所有的节点,但是gossip保证的是最终复制到所有的节点,再加上client会缓存hash slot map,client可能会把某个key的请求发给错误的节点来处理。 错误的节点收到请求后,发现这个key不应该自己来处理,会给客户端返回MOVED的错误,在错误消息中,会告诉客户端,哪个节点应该负责这个slot。Client收到MOVED消息后,会向消息中指定的节点再次发送请求。 client可以将slot的节点信息更新到本地缓存的hash slot map中,但是更好的方法是,重新获取完整的hash slot map,替换本地的缓存。因为在大多数情况下,hash slot map中的变更不仅仅只修改一个slot。 虽然client按照MOVED消息中的节点信息重新发送请求,但是client仍然可能再次从新节点收到MOVED错误消息,因为上一个节点的hash slot map可能也不是最新的。但是因为hash slot map最终会在所有的节点上一致,所以client在几次收到MOVED错误后,最终会获取到最新的hash slot map。 11、Failover、currentEpoch、lastVoteEpoch 当master发生故障宕机后,Redis Cluster会选出一个slave来接替这个master。 如果有多个slave存在,那么每个slave都可能都会发现master发生了宕机,并且试图把自己变成为master,如果有多个slave成为master,那么这些新master都会更新本地hash slot map,把旧master负责的slot更新成自己,并且把自己对hash slot map的更新传播给其他的节点。这会导致hash slot map在节点间出现差异。 从而导致,因为所连接的节点不同,client拿到不同的hash slot map,对于同一个slot,不同的client会连接不同的节点,最终导致节点上的数据出现差异。所以failover要保证,只有一个slave被选成新master。 Redis Cluster采用了类似Raft算法的技术来防止多个slave被选成master。每个节点都会有叫做currentEpoch、lastVoteEpoch的两个值。在集群刚创建时,每个节点的currentEpoch都是0。 当slave发现master宕机时,这个slave会增加currentEpoch(即currentEpoch++)。并且向所有的master发送FAILOVER_AUTH_REQUEST请求,请求中会携带自己currentEpoch,master收到FAILOVER_AUTH_REQUEST,如果请求中的currentEpoch比自己的currentEpoch和lastVoteEpoch都大,则记录请求中的currentEpoch值到自己的currentEpoch、lastVoteEpoch中,并且回复FAILOVER_AUTH_ACK给slave,回复中携带master的currentEpoch。 所以可以看出,FAILOVER_AUTH_ACK中的Epoch一定与slave的currentEpoch相同。Slave从大多数的master收到FAILOVER_AUTH_ACK后,则成为master。 上面的过程保证只有一个slave被选出,我们来举例说明。五个master的集群,master节点分别是A、B、C、D、E,A节点有两个slave,分别是A1和A2。A节点发生宕机,A1增加自己的currentEpoch=5(4+1),A1给所有的master发送FAILOVER_AUTH_REQUEST,节点B、C、D收到FAILOVER_AUTH_REQUEST,把自己的currentEpoch和lastVoteEpoch更新成5,并且给A1回复FAILOVER_AUTH_ACK,A1赢得选举,成为新的master。但是与此同时,A2也发现A宕机,也试图选举成master。A2增加自己的currentEpoch=5(4+1),A2给所有的master发送FAILOVER_AUTH_REQUEST,但这时的B、C、D的lastVoteEpoch已经是5,所以B、C、D不会给A2回复,E还没有收到A1的请求,所以只有E会给A2回复,但是不能形成大多数,所以A2不能称为master。 上面讲述的过程已经可以保证只有一个master被选出,但是除此之外,Redis Cluster还做了一个优化,那就是master回复了一个请求后不会在给这个master的其他的slave发送回复。 12、Configuration epoch failover完成后,新master会修改hash slot map,把相应的slot记录的节点改成自己,并且把这次对hash slot map的改动传播给其他节点。 虽然currentEpoch和lastVoteEpoch能保证每次failover只能有一个节点被选成新的master,但是先后两次failover,可能选出的两个不同的master,但是他们对hash slot map的修改的传播却是异步,也就是后面一次failover的改动可能先于第一次failover的改动到达某个节点,从而导致节点间对hash slot map这个信息产生不一致。
Redis Cluster通过configEpoch来解决这个问题。每个节点会保存一个configEpoch的值。相当于在node table中还会有一列数据叫configEpoch,类似于下面的表: (编辑:济宁站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
