Cluster
Redis Cluster是Redis的“亲儿子”,是作者自己提供的Redis集群化方案,Redis Cluster是去中心化的,每个节点负责整个集群的一部分数据,每个节点负责的数据多少可能不一样。这三个节点相互连接组成一个对等的集群,它们之间通过一种特殊的二进制协议交互集群信息。
Redis Cluster将所有数据划分为16384个槽位,比Codis的1024个槽位划分得更为精细,每个节点负责其中一部分槽位。槽位的信息存储于每个节点中,它不像Coids,不需要另外的分布式存储空间来存储节点槽位信息
当Redis Cluster的客户端来连接集群时,也会得到一份集群的槽位配置信息,这样当客户端要查找某个key时,可以直接定位到目标节点。不像codis需要通过Proxy来定位
客户端为了可以直接定位某个具体的key所在的节点,需要缓存槽位相关信息,这样可以快速定位到相应的节点,同时因为可能会存在客户端与服务器存储槽位的信息不一致的情况,还需要纠正机制来实现槽位信息的校验调整。
Redis Cluster的每个节点会将集群的配置信息持久化到配置文件中,所以必须确保配置文件可写,而且尽量不要依靠人工修改。
槽位定位算法
Redis Cluster默认会对key值使用crc16算法进行hash,得到一个整数值,然后用这个整数值对16384进行取模来得到具体槽位。
Redis Cluster允许用户强制把某个key挂在特定槽位上,通过在key字符串里嵌入tag标记,就可以强制key所挂的槽位等于tag所在槽位
跳转
当客户端向一个错误的节点发出指令后,该节点会发现指令的key所在的槽位并不归自己管理,这时它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端连接这个节点来获取数据。
客户端收到MOVED指令后,要立即纠正本地的槽位映射表,后续所有key将使用最新的槽位映射表
迁移
Redis Cluster提供了工具redis-trib可以让运维人员手动调整槽位的分配情况。
Redis迁移的单位是槽,Redis一个槽一个槽地进行迁移,当一个槽在迁移时,这个槽就处于中间的过度状态,这个槽在源节点的状态为migrating,在目标节点的状态为importing。表示数据正在从源节点流向目标节点。
迁移工具redis-trib首先会在源节点和目标节点设置好中间过渡状态,然后一次性获取源节点槽位的所有key列表,再挨个key进行迁移。
大致流程:从源节点获取内容——》存到目标节点——》从源节点删除内容
这里的迁移时同步的,在目标节点执行restore指令到源节点删除key之间,源节点的主线程会处于阻塞状态,直到key被成功删除。
如果迁移过程突然网络故障,整个槽的迁移只进行了一半,这时两个节点依旧处于中间过渡状态,待下次重新连上,会提示用户继续迁移。
在迁移过程中,如果每个key的内容都很小,migrate指令会执行的很快,就不会影响客户端的正常访问,如果key内容很大,因为是阻塞指令,会影响稳定性
在迁移过程中,客户端访问的流程会有很大的变化。
首先新旧两个节点对应的槽位都存在部分key数据,客户端先尝试访问旧节点。如果对应的数据还在旧节点里面,那么旧节点正常处理。如果对应的数据不再旧节点里面,那么有两种可能,要么该数据在新节点里,要么根本就不存在。旧节点不知道是哪种情况,所以它会向客户端返回一个-ASK targetNodeAddr的重定向指令。客户端收到这个重定向指令后,先去目标节点执行一个不带任何参数的ASKING指令,然后在目标节点重新执行原先的操作指令。
为什么需要执行一个不带参数的ASKING指令?
因为在迁移没有完成之前,按理说这个槽位不归新节点管理,如果这个时候向目标节点发送该槽位的指令,节点是不认的,它会向客户端返回一个-MOVED重定向指令告诉它去源节点去执行。如此就会形成重定向循环。ASKING指令的目标就是打开目标节点的选项,告诉它下一条指令不能不理,而要当自己的槽位处理。
以上过程看出,迁移时会影响服务效率的,通过的指令再正常情况下一个ttl就能完成,而在迁移情况下需要3个ttl才能搞定。
容错
Redis Cluster可以为每个主节点设置若干个从节点,当主节点发生故障时,集群自动将从节点提升为主节点,如果主节点没有从节点,那么它发生故障时,集群完全处于不可用状态。Redis提供一个参数cluster-require-full-coverage允许部分节点发生故障,其他节点还可以继续提供对外访问。
网络抖动
Redis Cluster提供一种选项cluster-node-timeout表示当某个节点持续timeout的时间失联时,才可以认定该节点出现故障,需要进行主从切换。
cluster-slave-validity-factor作为倍乘系数放大这个超时时间
可能下线与确定下线
Redis Cluster是去中心化的,一个节点认为某个节点失联并不代表所有的节点都认为他失联,所以集群经过一次协商。只有当大多数节点都认为某个节点失联,集群才认为该节点需要主从切换。
Redis集群采用Gossip协议来广播自己的状态以及改变对整个集群的认知。比如一个节点发现某个节点失联了,会将这条信息向整个集群广播,其他节点就可以收到这条失联信息,如果收到了某个节点失联的节点数量达到集群的大多数,就可以标记该失联节点确定下线,然后向整个集群广播,强迫其他节点也接收该节点已经下线的事实,立即对该节点进行主从切换。
槽位迁移感知
客户端保存了槽位和节点的映射关系表,需要及时更新,才可以正常将某条指令发到正确的节点上。
MOVED指令用来纠正槽位,如果将指令发送到了错误的节点上,该节点发现对应的指令槽位不归自己管理,就会将目标节点MOVED指令回复
ASKING临时纠正槽位。