中心思想
集群呢将所有数据划到16384个槽中,每个节点负责其中一部分槽位,分而治之的思想发挥到顶了朋友
槽位的信息存储在每个节点中,万一集群中去个节点加个节点的,也方便,这叫花小空间办大事!中国人的智慧被发挥得酣畅淋漓
客户端呢连接集群,将会奖励一份集群的槽位配置信息,将其缓存到本地槽位映射表,需要某个key到时候,问一下自己,直接定位到目标节点,不过可能槽位信息与服务器不一致,所以还需要纠正来及时调整
这上面呢说了一下中心思想,下面具体一些
槽位定位
这个其实比较简单,大家也都知道,我就来啰嗦一下
对key 使用 crc16算法 进行hash得到一个整数值,然后对16384取模
HASH_SLOT = CRC16(key) mod 16384
1、如果客户端定位错误,错误节点发现key所在槽位不是自己,虽然这很令人生气,好在他没有情感,只会向客户端发送跳转指令:你个小傻瓜,你应该去***获取你想要的东西(感谢槽位存储了节点信息)
2、客户端乖乖地跳转到正确的目标地址,同时纠正本地的槽位映射表,从此就没有犯错的机会(这男人的嘴啊,不一定彻底没有,机会多多少少还是有点,复杂的环境杜绝不了)
节点间通信
cluster节点间通信gossip协议,大名鼎鼎 相信大家也都("没")听过
通过集中式或gossip来维护集群元数据:节点信息,主从,节点数量,共享数据等
集中式
元数据读取和修改比较有效率,快到什么程度呢,元数据这边变更了立即更新到集中式的存储中,犹如白驹过隙、特别快
不过所有点元数据更新压力都集中到一个地方,集中式嘛 人如其名,这存储压力就比较大,所以咱可以借助中间件zk或者什么的来集中式存储元数据
gossip
节点都有自己的专属端口:用于节点间通信,具体的端口号就很简单:自己提供服务的端口号+10000
1、 meet:节点发送meet给新加入的节点小弟,让新加入的节点加入集群这个温暖的大家庭,这样新节点就可以和其他节点进行友好通信了
2、ping:节点都会给其他节点ping,像逢年过节的联络,把我的状态和维护的集群元数据,唠唠家常说说八卦,消息互通一下,这样大家数据不打架,相安无事,对不,至少这里过节想喝水一样比较平常
3、pong:事事有回响,这就是回音:对ping和meet消息的返回全靠了咱们的pong:自己的状态,其他八卦信息,也可以信息广播和更新,看看 多有用
4、fail:这是一个不幸的消息,难免有节点挂了,如果我发现有节点挂了(clusternodetimeout),我就发fail给其他节点,互通消息,及时维护了大家的存储信息
4.1 当从节点发现自己的主节点fail,首先先等一会,不能着急,万一主醒了,那就要篡位的嫌疑了,再说集群中自己的主挂的消息还没散开,你出去也没有人承认你,所以咱们先等DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms 然后,尝试failover来变成新的master,注意主有多个从,谁都想成为主人,所以这就是很激烈的竞争过程
- slaveA发现自己master变fail了,将自己记录的集群currentEpoch加1(自认为抢占了先机),然后广播failover_auth_request
- 其他节点收到信息,只要master有资格去响应,判断合法性,发送failover_auth_ack,(此时可能多个slave发送了这个消息so)对每一个epoch只发送一次ack
- 那个slaveA收集master返回ack消息,收到超过半数的ack他就变成新的master,然后很开心,广播pong 广而告之其他的集群节点
DELAY = 500ms + random(0 ~ 500ms) + SLAVE_RANK * 1000ms
SLAVE_RANK表示slave从master复制数据的总量的rank,Rank越小代表数据越新
主要的四个消息,各位看官也能看出来,咱们gossip的元数据解决了集中式的痛点,元数据比较分散,每个节点都有,这样更新请求陆陆续续就八卦到每个节点上,所以陆陆续续就有点小延迟,更新可能会滞后,比较16384 不一定先更新到谁
补充一个小点:
如果cluster-require-full-coverage为no:当负责一个插槽的主库下线并且没有从库来故障恢复,集群还是可用的,yes则这中情况下集群不能用