本文主要介绍Rediscoluster集群数据分片机制的原理,通过实例代码进行了非常详细的介绍,对大家的学习或工作有一定的参考价值。有需要的朋友可以参考一下。
Redis Cluster数据分片机制
Redis 集群简介
Redis集群是Redis的分布式解决方案,在3.0版本正式推出,有效解决了Redis的分布式需求。
Redis集群一般由多个节点组成,节点数量至少要达到六个才能保证一个完整的高可用的集群,其中三个为主节点,三个为从节点。三个主节点将分配插槽来处理来自客户端的命令请求,而当主节点出现故障时,从节点可以用来代替主节点。
如上图所示,该集群包含六个Redis节点,三个主节点和三个从节点,即M1、M2、M3、S1、S2和S3。除了主、从Redis节点之间的数据复制,所有Redis节点都使用Gossip协议进行通信,交换维护节点的元数据信息。
一般来说,主Redis节点处理客户端的读写操作,而从节点只处理读操作。
数据分片策略
分布式数据存储方案最重要的一点就是数据分片,也就是所谓的分片。
为了使集群横向扩展,首先要解决的问题是如何将整个数据集按照一定的规则分布到多个节点上。常用的数据分片方法包括范围分片、哈希分片、一致哈希算法和虚拟哈希槽等。
范围分割假设数据集是有序的,把相邻顺序的数据放在一起可以很好的支持遍历操作。范围切片的缺点是面对顺序写入时会有热点。比如写日志类型的时候,日志的顺序一般和时间有关,时间是单调递增的,所以写的热点总是在最后一个切片。
对于关系数据库,因为经常需要进行表扫描或者索引扫描,所以基本上使用范围分片策略。
Redis集群通过虚拟哈希槽进行分区,所有键根据哈希函数映射到0 ~ 16383的整数槽。计算公式为slot=CRC16(key) 16383。每个节点负责维护一些槽和槽映射的键值数据。
Redis虚拟插槽分区的特征:
将数据和节点之间的关系解耦,简化了节点扩展和收缩的难度。节点本身维护槽的映射关系,不需要客户端或代理服务来维护槽分区元数据。支持节点、槽、键之间的映射查询,用于数据路由、在线集群扩展等场景。
Redis集群提供了灵活的节点扩展和收缩方案。在不影响集群外部服务的情况下,可以向群集中添加节点进行扩展,或者减少一些离线节点的容量。可以说,插槽是Redis集群管理数据的基本单位,集群扩展是插槽和数据在节点之间的移动。
我们先来看看Redis集群伸缩的原理。然后了解如何在Redis节点数据迁移或从故障中恢复时确保集群的可用性。
扩容集群
为了让读者更好地理解节点在线时的扩容操作,我们通过Redis集群的命令模拟了整个过程。
当一个新的Redis节点运行并加入现有集群时,我们需要为它迁移片段和数据。首先,为新节点指定插槽的迁移计划,并确保迁移后每个节点负责相似数量的插槽,以保证这些节点的数据一致性。
1)首先启动一个Redis节点,并将其标记为M4。
2)使用cluster meet命令使新的Redis节点加入集群。起初,所有新节点都处于主节点状态,由于没有插槽负责,它们不能接受任何读写操作。稍后,我们将迁移插槽并为它们填充数据。
3)向M4节点发送集群设置槽{slot}导入{source nodeid}命令,以便目标节点准备导入槽的数据。
4)向源节点,即M1、M2和M3节点发送集群设置槽{slot}迁移{target nodeid}命令,以便源节点准备移出槽的数据。
5)源节点执行命令Cluster GetKeysinslot {slot} { count },获取属于slot { slot }的count个密钥,然后执行步骤6的操作迁移密钥数据。
6)执行迁移{ targetnodeip }“0 { time out }密钥{key.}命令,并通过管道机制将获取的密钥批量迁移到目标节点。Redis 3 . 0 . 6或更高版本中提供了批量迁移版本的migrate命令。
7)重复步骤5和6,直到槽中的所有关键数据都迁移到目标节点。
8)向集群中的所有主节点发送集群设置槽{slot} node {target nodeid}命令,通知该槽被分配给目标节点。为了保证槽节点映射变化的及时传播,需要遍历迁移后的槽节点,发送给所有主节点进行更新。
收缩集群
收缩一个节点就是让Redis节点离线。整个过程需要以下操作流程。
1)首先需要确认离线节点是否有负责槽。如果是这样,就需要将slot迁移到其他节点上,以保证节点离线后整个集群的slot节点映射的完整性。
2)当离线节点不再负责槽或者是从节点时,可以通知集群中的其他节点忘记离线节点。当所有节点都忘记换节点时,可以正常关闭。
当一个节点脱机时,它需要将自己的插槽迁移到其他节点。原理和前面节点扩展的槽迁移过程一样。
槽迁移后,需要通知集群中的所有节点忘记离线节点,也就是说,其他节点不会与离线节点交换八卦消息。
Redis cluster使用cluster forget {downNodeId}命令表示指定节点被添加到禁止列表中,禁止列表中的节点不再发送八卦消息。
客户端路由
在集群模式下,Redis节点接收到任何与key相关的命令时,先计算出key对应的slot,然后根据slot找出对应的节点,如果节点是自己,则处理key命令;否则,回复已移动的重定向错误,并通知客户端请求正确的节点。这个过程称为移动重定向。
需要注意的是,Redis在计算slots时,并不只是计算键值。当键值包含花括号时,它只计算括号中的内容。例如,当键为user:{10000}:books时,计算哈希值时只计算10000。
移动的错误示例显示以下信息:键X所属的哈希槽3999,以及负责处理该槽的节点的IP和端口号127.0.0.1:6381。根据这个IP和端口号,客户端需要向其节点重新发送GET命令请求。
codeclass=hljs/code
因为请求重定向会增加IO开销,所以这不是使用Redis集群的高效方式,而是使用智能集群客户端。智能客户端在内部维护slot和Redis节点之间的映射关系,使得key to node可以在本地找到,从而保证最大的IO效率,MOVED redirection负责协助客户端更新映射关系。
Redis集群支持插槽和数据的在线迁移,以完成水平扩展。当插槽对应的数据从源节点迁移到目标节点时,客户端需要进行智能迁移,以保证关键命令的正常执行。例如,当槽数据从源节点迁移到目标节点时,源节点中可能有一些数据,而目标节点中可能有另一些数据。
因此,基于上述情况,客户端命令执行过程如下:
客户端根据本地槽缓存向源节点发送命令,如果有键对应,则直接执行并将结果返回给客户端。
如果节点返回移动错误,更新本地插槽和Redis节点之间的映射关系,然后重新发起请求。
如果数据正在迁移,节点将回复ASK重定向异常。格式如下:(error)ask { slot } { target iport }:{ target port }
从客户端重定向异常中提取目标节点信息,向目标节点发送打开客户端连接标识的请求命令,然后执行key命令。
虽然ASK和MOVED都是客户端的重定向控件,但它们本质上是不同的。ASK重定向表示集群正在迁移slot数据,客户端无法知道何时完成迁移,所以只能是临时重定向,客户端不会更新slot到Redis节点的映射缓存。但是,与移动的重定向键对应的slot已经被显式分配给新节点,因此需要更新slot到Redis节点的映射缓存。
故障转移
当Redis集群中少数节点出现故障时,自动故障转移保证了集群能够正常向外界提供服务。
当一个Redis节点客观离线时,Redis集群会选择它的一个从节点来替换它,从而保证集群的高可用性。这个内容不是本文的核心内容。有兴趣的同学可以自学。
但是,有一点需要注意。默认情况下,当群集的16384个插槽中的任何一个未分配给节点时,整个群集都不可用。执行任意键命令以返回未提供服务的集群散列槽命令。当持有插槽的主节点脱机时,从故障发现到自动转移期间,整个集群都不可用,这对于大多数服务来说是无法忍受的。因此,建议将参数cluster-require-full-coverage配置为no,这只会影响主节点失效时插槽相关命令的执行,不会影响其他主节点的可用性。
这就是本文的全部内容。希望对大家的学习有帮助,支持我们。