redis cluster特性
- 对于每一个节点,都需要配置master,slave。当master down掉的时候,其它仍然alive的节点会promote slave节点作为master节点。关于节点的功能还有
auto-discover other nodes, detect non-working nodes
关于configEpoch
感觉configEpoch是类似于一个版本号的东西,是关于cluster slot的一个版本号。一般来说,每一个master节点的configEpoch都是不同的(假如存在相同的configEpoch,会有冲突处理算法来保证每个节点的configEpoch不同),并且每一个节点的configEpoch不会轻易发生改变(节点改变的情况见下面)。由于configEpoch是单调递增的,因此当某一个节点的configEpoch改变之后,其它节点就会更新对该节点所声称拥有的slots的认识。
关于currentEpoch
configEpoch只是关于slots分布的一个版本号,而currentEpoch才是真正的逻辑时钟。通过gossip协议,集群中的currentEpoch总是一致的(当然,特殊情况除外,如网络分区发生等)。currentEpoch越高,代表节点的配置或者操作越新。
redis cluster中得逻辑时间
- configEpoch : configEpoch should be generate by concensus and should be unique across the cluster(configEpoch可以看做是一个逻辑时间戳)
- currentEpoch
configEpoch的变化
- 在集群初始化的时候,通过读取配置文件nodes.conf中的configEpoch值,对每一个节点的configEpoch进行赋值
- 集群重置(resetCluster)时,configEpoch被置为0
- 当一个槽迁移到某一个节点之后,尤其是集群发生resharding的时候;当发生failover force时,节点的configEpoch会被置为currentEpoch + 1(原因未清楚)
- 若两个节点的configEpoch相同,并且当前节点的nodename更大,则当前节点的configEpoch=currentEpoch+1(configEpoch发生冲突时的处理)
- 当master发生fail的之后,slave获得大多数master的投票时,设置slave的configEpoch为failover_auth_epoch
- cluster set-config-epoch命令强制设置configEpoch
- 当接受到其它节点发来的gossip消息的时候,设置configEpoch为消息中得configEpoch
投票的条件
- 发起投票的节点必须是slave节点,并且它的master节点已经down掉
- 发起投票节点的currentEpoch不低于投票节点的currentEpoch
- slave节点的configEpoch不低于投票节点特定slots的configEpoch(这些特定slots是指投票节点知道的down掉得master节点所拥有的slots)
注意事项
- 在retarding过程中,设计多个key的操作可能失败。
- 任意一个节点都可以接受客户端请求,但是假如请求的key不在本节点,会发送一个MOVED相应。并且,应该客户端来缓存key->node的对应关系。
写数据丢失的可能行
- master接受写请求后,在没有将新数据同步到slave之前,master down掉,这部分数据丢失。(这跟单机的情况一样)
- master由于网络分区而被slave failover,slave成为了master,然后网络分区消失,原来的master又重新与集群连接上了(这是原来的master的configuration仍然是master)。假如client将写请求发送给这个master,写请求会被接受,但是会丢失。原因在于很快,现在的master会将原来的master降级为slave。
- 另外,假如网络分区发生后,并且很长一段时间没有恢复,那么在NODE_TIMEOUT时间内发送给minority分区中得master的写也会丢失。因为在分区发生后的NODE_TIMEOUT时间内fail detection不会检查出有节点unreachable,写请求仍可接受。在NODE_TIMEOUT时间后,fail detection检查到有节点unreachable,就不接受写请求了。
redis cluster specification上的话
Very high performance and scalability while preserving weak but reasonable forms of data safety and availability is the main goal of Redis Cluster.
如何避免gossip消息成指数级增长
注:这里的指数增长主要是指节点数跟gossip消息数的关系。
- 每10个clusterCron(约1s)可能会随机挑选一个节点发送ping
- 在接收到节点的pong消息(node_timeout / 2)s后回给该节点发送一个ping消息
- 每接受到一个ping消息,回复一个pong消息。
因此,正常情况下一个node_timeout时间内,一个节点可以跟另外的节点交换至少4个包(大家互相ping一次,互相pong一次)。那么集群中总共发送的数据包是$$\dfrac{(N + 1) * N * 4}{2} = (N + 1) * N * 2$$增长率是$$2 * (2 * N + 1) = 4 * N + 2$$
从数字上来看,这gossip包得数量还是很惊人的;指数的gossip是多少?
根据实际测试,使用create-cluster脚本创建的集群,大概每10每个节点会发送100个包(默认的node_timeout是15s)。在数量级上跟上述列出的公式是一致的。个人觉得redis cluster在gossip协议上还是有优化的空间的,怎么样在保证及时性和准确性的情况下减少gossip协议的消息数量