Redis Cluster集群是如何通过哈希槽实现分片的?

来源:JS脚本作者:IT柏拉图头衔:草根站长
导读:本期聚焦于IT柏拉图创作的《Redis Cluster集群是如何通过哈希槽实现分片的?》,敬请观看详情。Redis Cluster采用哈希槽机制替代传统一致性哈希,将键空间划分为16384个固定槽位。每个节点负责一部分槽,客户端写入键时通过CRC16算法计算哈希值并对16384取模得到槽编号,再根据槽与节点的映射关系路由到对应节点。当键不在当前节点时,集群返回MOVED重定向指令,客户端更新本地槽映射;在槽迁移过程中则返回ASK重定向。节点间通过Gossip协议在集群总线上交换状态,实现故障检测与主从自动切换。扩容时使用redis-cli --cluster reshard命令在线迁移槽位,迁移过程通过MIGRATE命令逐键转移数据。本文深入解析哈希槽计算、路由容错、节点通信及迁移流程,并给出Windows环境下的配置路径示例。

Redis Cluster是Redis官方提供的分布式解决方案,它通过分片的方式将数据分散存储到多个节点上,从而实现水平扩展和高可用。与传统的客户端分片或代理分片相比,Redis Cluster将分片逻辑集成在服务端和协议层,既避免了单点故障,又降低了客户端复杂度。理解其分片原理,需要从哈希槽、路由机制、节点通信和在线迁移四个层面入手。

Redis Cluster集群是如何通过哈希槽实现分片的?

一、哈希槽与CRC16算法

Redis Cluster没有使用一致性哈希,而是将整个键空间划分为16384个哈希槽(slot)。每个节点负责若干个槽,槽的数量可以动态调整。节点加入集群时,管理员通过命令将部分槽分配给该节点。这种设计使得节点与槽的解耦更加灵活,例如扩容时只需迁移部分槽的数据,无需重新映射所有键。相比一致性哈希环,哈希槽的粒度更细,迁移成本更低,且不存在环形结构中常见的负载倾斜问题。

键到槽的映射通过CRC16算法完成。公式为slot = CRC16(key) % 16384。CRC16是一种循环冗余校验算法,对键的二进制表示计算16位校验和,然后对16384取模。Redis选用的CRC16变体具有计算速度快、分布均匀的特点。对于包含多个键的操作(如MGET、事务),Redis支持哈希标签(hash tag)机制:如果键名中包含大括号{},则仅对大括号内的子字符串进行哈希计算。例如,user:{1001}:profile和user:{1001}:orders会映射到同一个槽,从而保证多键操作可以作用于同一节点。哈希标签的使用需要谨慎,过度集中可能导致单个槽数据量过大,影响集群平衡。

下面这段Python代码演示了如何简化实现槽位计算,实际项目中Redis客户端会内置更高效的CRC16实现。

import binascii

def crc16(data):
    # 简化的CRC16-CCITT实现,实际Redis使用CRC16-CCITT变体
    crc = 0
    for byte in data:
        crc ^= byte << 8
        for _ in range(8):
            if crc & 0x8000:
                crc = (crc << 1) ^ 0x1021
            else:
                crc <<= 1
            crc &= 0xffff
    return crc

def slot(key):
    return crc16(key.encode('utf-8')) % 16384

print(slot("user:1001"))

二、客户端路由与MOVED/ASK重定向

客户端在发送命令前需要知道键对应的槽由哪个节点负责。Redis Cluster提供两种客户端模式:普通客户端和智能客户端。普通客户端不缓存槽映射,每次请求都根据服务器返回的重定向信息重新定位;智能客户端(如JedisCluster、redis-py-cluster)会缓存槽与节点的映射表,并在收到重定向时更新缓存,从而减少网络往返。智能客户端通常采用懒加载策略,只在首次连接或收到重定向时获取槽映射,之后直接根据本地缓存定位节点。

当客户端向错误的节点发送命令时,该节点会返回MOVED错误,格式为“MOVED slot ip:port”。客户端收到后需要解析出新地址,连接到新节点重新执行命令,并更新本地槽映射。MOVED错误表示槽的负责节点已经发生变化,客户端缓存失效。另一种错误是ASK,发生在槽迁移过程中。迁移期间,部分键可能仍留在源节点,目标节点在收到命令时如果键尚未迁移,会返回ASK错误并附带目标节点地址,客户端需要先发送ASKING命令,再重新执行原命令。ASK错误不会更新客户端槽映射,因为槽的归属尚未正式切换。

下面是一个简化版的客户端重定向处理伪代码,展示了MOVED和ASK的判别逻辑。

def execute_command(conn, cmd, *args):
    try:
        return conn.execute_command(cmd, *args)
    except RedisClusterException as e:
        if e.type == 'MOVED':
            slot = e.slot
            new_addr = e.addr
            conn = get_connection(new_addr)
            update_slot_cache(slot, new_addr)
            return execute_command(conn, cmd, *args)
        elif e.type == 'ASK':
            new_addr = e.addr
            conn = get_connection(new_addr)
            conn.execute_command('ASKING')
            return execute_command(conn, cmd, *args)

理解这两种重定向的区别非常重要:MOVED代表槽归属的永久变化,客户端应更新缓存;ASK则是迁移过程中的临时状态,客户端只需在本次请求中加上ASKING前缀,不应改变槽映射。将二者混淆会导致缓存错误,造成大量无效重定向,甚至引发集群访问异常。

三、节点通信、故障转移与数据迁移

Redis Cluster节点间通过Gossip协议交换状态信息。每个节点默认使用两个端口:普通客户端端口(如6379)和集群总线端口(普通端口加10000,如16379)。总线端口用于节点间二进制协议通信,传递节点状态、槽分配表、故障信息等。Gossip协议采用随机选点传播的方式,保证最终一致性,避免中心化元数据存储。节点会在固定周期内向随机选出的其他节点发送PING消息,并携带已知节点列表和槽信息,收到PONG后更新本地视图。这种去中心化设计使得集群无单点瓶颈,即使部分节点暂时不可达,集群整体仍可服务。

故障检测方面,节点会定期向其他节点发送PING,如果在规定时间内未收到PONG,则标记为PFAIL(可能故障),当足够多的节点报告同一节点不可达时,状态升级为FAIL,触发主从切换。每个主节点可以配置一个或多个从节点,主节点故障后,从节点通过选举机制提升为新主节点,接管其槽位,保证集群可用性。选举过程基于Raft算法的变体,从节点在发现主节点FAIL后发起投票,获得多数派支持的从节点完成切换。整个过程自动完成,无需人工干预。

数据迁移是扩容和缩容的核心操作。使用redis-cli --cluster reshard命令可以指定迁移的槽数量、目标节点和源节点。迁移过程是逐槽进行的:对于每个槽,先将目标节点设置为该槽的临时负责节点,然后在源节点上使用MIGRATE命令将槽内的键原子地迁移到目标节点,迁移完成后更新槽映射。整个过程在线进行,不影响集群对外服务,只有正在迁移的槽可能有短暂的ASK重定向。下面是一组常用的redis-cli操作命令。

redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
redis-cli --cluster reshard 127.0.0.1:7000
# 按照提示输入迁移槽数量、目标节点ID、源节点ID
redis-cli --cluster check 127.0.0.1:7000

在Windows环境中部署Redis Cluster时,配置文件通常放在C:\Redis\redis.conf,数据持久化目录可以设置为C:\Redis\data\,日志文件路径为C:\Redis\log\redis.log。启动每个节点时使用redis-server.exe C:\Redis\redis.conf,集群创建命令需要指定对应的绝对路径。注意Windows上需确保端口和集群总线端口未被防火墙拦截,否则节点间无法完成Gossip通信,集群状态会一直处于fail状态。

总的来说,Redis Cluster的分片原理建立在哈希槽、CRC16计算、客户端重定向、Gossip通信和在线迁移这几大支柱之上。掌握这些机制后,运维人员可以更从容地进行集群规划、扩容缩容和故障排查,开发人员也能写出更健壮的高性能分布式缓存代码。

Redis Cluster哈希槽数据分片修改时间:2026-08-27 17:35:48

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。