一、Redis 哈希槽的基础概念

1.1 什么是哈希槽?

哈希槽(Hash Slot)是 Redis 集群实现数据分片的核心机制,它将整个数据集划分为多个逻辑分区。Redis 集群采用固定数量的哈希槽(16384个),每个键值对通过计算CRC16校验值后,再对16384取模来确定其所属的哈希槽。

工作流程示例:

  1. 客户端写入键"user:1001"时,集群先计算CRC16("user:1001")=1234
  2. 计算槽位:1234 % 16384 = 1234
  3. 查找槽位1234对应的节点(假设由节点A负责)
  4. 将数据写入节点A

核心优势详解:

  1. 数据与节点解耦

    • 传统一致性哈希需要重新计算大量键的映射关系
    • 哈希槽只需调整槽位分配,例如节点扩容时,只需将部分槽位从现有节点转移到新节点
    • 实际案例:当从3节点扩展到6节点时,每个原始节点分出50%的槽位给新节点
  2. 数据迁移优化

    • 迁移单位是槽位而非单个键
    • 支持批量迁移,一个槽位可能包含数万个键值对
    • 迁移过程中客户端仍可访问数据(通过重定向机制)
  3. 负载均衡实现

    • 通过CLUSTER ADDSLOTS命令可以手动分配槽位
    • 自动均衡工具redis-trib可确保各节点槽位数差异不超过10%
    • 监控指标:每个节点的内存使用、QPS与槽位分布成正比

1.2 为什么是16384个哈希槽?

深度技术考量:

  1. 集群规模适配

    • 数学推算:在1000节点集群中,平均每个节点管理16个槽位
    • 实际测试:Facebook的Redis集群验证了16384槽位在300节点规模下的稳定性
    • 对比方案:早期版本曾考虑65536槽位,但会导致心跳包过大(16KB vs 4KB)
  2. 网络通信优化

    • 节点间心跳包携带的槽位映射信息采用bitmap压缩存储
    • 16384个槽位需要2048字节(16384/8)
    • 如果采用65536槽位,需要8KB存储空间,增加网络负载
  3. 数据迁移控制

    • 生产环境测试显示:
      • 单个槽位迁移1GB数据约需2-5分钟(取决于网络带宽)
      • 迁移10个槽位可并行执行,总时间不会线性增长
    • 性能测试数据:
      • 槽位过少(如4096):单槽位数据量过大,迁移时可能达10GB+
      • 槽位过多(如65536):槽位管理元数据占用内存超过100MB

历史决策背景:

  • 原始作者antirez在GitHub issue #2576中解释:
    • 综合权衡了内存占用(每个节点需要存储槽位映射)
    • 考虑了未来10年的集群规模增长预期
    • 测试了不同槽位数对集群启动时间的影响(16384槽位约0.5秒完成分配)

二、Redis 哈希槽的工作原理

2.1 Key 到哈希槽的映射过程

Redis 采用 CRC16 算法将 Key 精确映射到对应的哈希槽,这是实现数据分片的核心机制。具体映射过程如下:

  1. 计算 Key 的 CRC16 值:

    • 对 Key 的原始字符串(不包含大 Key 的特殊标记)执行 CRC16 校验计算
    • 得到一个 16 位的无符号整数,取值范围为 0-65535
    • 注意:计算时只使用 Key 本身,不包含任何前缀或命名空间
  2. 对哈希槽总数取模:

    • 将上一步得到的 CRC16 值对 Redis 集群固定的 16384 个槽位取模
    • 计算公式:slot = CRC16(Key) % 16384
    • 最终得到 0-16383 之间的哈希槽编号
  3. 特殊处理:

    • 对于包含"{}"的复合 Key,如"user:{100}:profile",只计算花括号内的部分(即"100")
    • 这是 Redis 提供的哈希标签功能,确保相关数据落在同一个槽位

示例:手动计算 Key 的哈希槽

假设 Key 为"user:100",我们可以通过以下方式验证其哈希槽:

# 使用Redis内置命令直接查询
127.0.0.1:6379> CLUSTER KEYSLOT user:100
(integer) 7420  # 该Key被分配到7420号哈希槽
# 也可以通过Ruby脚本模拟计算过程
require 'zlib'
Zlib.crc16("user:100") % 16384  # => 7420

2.2 哈希槽到节点的映射

Redis 集群通过分布式槽位分配表(Slot Assignment Table)维护哈希槽与节点的映射关系,该机制具有以下特点:

  1. 槽位分配表结构:

    • 每个节点都存储完整的槽位分配表
    • 记录每个哈希槽范围(0-16383)对应的主节点信息
    • 包含节点的IP、端口和唯一ID等元数据
  2. 请求重定向机制:

    • 当客户端请求到达非目标节点时,节点会检查本地槽位分配表
    • 若当前节点不负责该Key的哈希槽,返回MOVED错误
    • MOVED响应格式:MOVED <slot> <node-ip>:<node-port>
    • 智能客户端会缓存槽位映射信息,减少重定向次数
  3. 集群状态同步:

    • 节点间通过 Gossip 协议定期交换集群状态信息
    • 包含槽位分配变更、节点故障等关键信息
    • 同步频率可通过cluster-node-timeout参数配置(默认15秒)

查看集群槽位分配情况

通过CLUSTER SLOTS命令可以获取完整的槽位分配视图:

127.0.0.1:6379> CLUSTER SLOTS
1) 1) (integer) 0       # 起始槽位
   2) (integer) 5460    # 结束槽位
   3) 1) "192.168.1.100" # 主节点IP
      2) (integer) 6379  # 主节点端口
      3) "a1b2c3d4e5f6..." # 节点ID
   4) 1) "192.168.1.110" # 从节点IP
      2) (integer) 6380  # 从节点端口
      3) "d4e5f6a1b2c3..."
2) 1) (integer) 5461
   2) (integer) 10922
   3) 1) "192.168.1.101"
      2) (integer) 6379
      3) "b2c3d4e5f6a1..."
   4) 1) "192.168.1.111"
      2) (integer) 6380
      3) "e5f6a1b2c3d4..."
3) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "192.168.1.102"
      2) (integer) 6379
      3) "c3d4e5f6a1b2..."
   4) 1) "192.168.1.112"
      2) (integer) 6380
      3) "f6a1b2c3d4e5..."

上述输出表示:

  • 节点192.168.1.100:6379为主节点,负责0-5460号槽,其从节点为192.168.1.110:6380
  • 节点192.168.1.101:6379为主节点,负责5461-10922号槽,其从节点为192.168.1.111:6380
  • 节点192.168.1.102:6379为主节点,负责10923-16383号槽,其从节点为192.168.1.112:6380

三、Redis 哈希槽的分配策略详解

3.1 初始分配:集群创建时的槽位分配

在创建 Redis 集群(如通过redis-cli --cluster create命令)时,系统会采用均匀分配的原则将16384个哈希槽(slot)分配到所有主节点上。具体分配逻辑如下:

  1. 计算基础分配量:将16384个槽平均分配给所有主节点
  2. 处理余数分配:若有剩余槽位,则按照节点顺序依次分配
  3. 保证连续性:为每个节点分配连续的槽位范围

典型分配方案

主节点数量每个节点槽位数槽位范围示例
354610-5460, 5461-10922, 10923-16383
440960-4095, 4096-8191, 8192-12287, 12288-16383
53276+32770-3275, 3276-6551, 6552-9827, 9828-13103, 13104-16383

详细示例:创建3主3从集群并查看槽位分配

# 创建3主3从集群(IP分别为100、101、102,从节点省略)
redis-cli --cluster create \
  192.168.1.100:6379 \
  192.168.1.101:6379 \
  192.168.1.102:6379 \
  --cluster-replicas 1
# 查看主节点槽位分配详情
for port in 6379 6380 6381; do
  echo "Node 192.168.1.100:$port slots:"
  redis-cli -h 192.168.1.100 -p $port CLUSTER NODES | grep "myself"
  redis-cli -h 192.168.1.100 -p $port CLUSTER INFO | grep "cluster_slots_assigned"
done

3.2 手动分配:自定义槽位映射

在实际生产环境中,可能需要根据节点性能差异进行自定义槽位分配。常见场景包括:

  1. 性能优化:为配置更高的节点分配更多槽位
  2. 业务隔离:将特定业务范围的键分配到指定节点
  3. 负载均衡:调整热点数据的分布

手动分配操作步骤

  1. 准备阶段

    • 确认目标槽位当前状态:CLUSTER SLOTS
    • 如需重新分配,先释放已有槽位
  2. 槽位分配

    # 释放节点101的现有槽位(若有)
    redis-cli -h 192.168.1.101 -p 6379 CLUSTER DELSLOTS 5461 10922
    # 为节点101分配连续的槽位范围8192-12287(共4096个槽)
    redis-cli -h 192.168.1.101 -p 6379 CLUSTER ADDSLOTS {8192..12287}

  3. 更新集群拓扑

    # 通知其他节点槽位变更
    for port in 6379 6380 6381; do
      redis-cli -h 192.168.1.100 -p $port CLUSTER SETSLOT 8192-12287 NODE 
    done
    # 验证槽位分配
    redis-cli -h 192.168.1.101 -p 6379 CLUSTER SLOTS

注意事项

  • 手动分配期间应暂停客户端请求
  • 确保槽位覆盖完整(0-16383无遗漏)
  • 分配完成后执行CLUSTER SAVECONFIG

3.3 动态调整:集群扩容/缩容时的槽位迁移

3.3.1 扩容场景:新增节点并迁移槽位

扩容操作流程(以3主集群扩容到4主为例):

  1. 准备新节点

    # 启动新Redis实例
    redis-server /path/to/redis.conf --port 6379
    # 加入集群
    redis-cli --cluster add-node 192.168.1.103:6379 192.168.1.100:6379

  2. 槽位迁移规划

    • 计算每个原有节点应迁出的槽位数:16384/4=4096
    • 建议从每个节点迁移约1365个槽位(4096/3)
  3. 执行迁移

    # 交互式迁移(推荐)
    redis-cli --cluster reshard 192.168.1.100:6379
    # 或非交互式迁移
    redis-cli --cluster reshard 192.168.1.100:6379 \
      --cluster-from all \
      --cluster-to  \
      --cluster-slots 4096 \
      --cluster-yes

  4. 验证迁移

    # 检查新节点槽位
    redis-cli -h 192.168.1.103 -p 6379 CLUSTER SLOTS
    # 检查集群状态
    redis-cli --cluster check 192.168.1.100:6379

3.3.2 缩容场景:下线节点并迁移槽位

缩容操作流程(从4主集群缩容到3主):

  1. 槽位迁移准备

    # 查看待下线节点槽位
    redis-cli -h 192.168.1.103 -p 6379 CLUSTER SLOTS

  2. 分批迁移槽位

    # 迁移1000个槽位到节点100
    redis-cli --cluster reshard 192.168.1.100:6379 \
      --cluster-from  \
      --cluster-to  \
      --cluster-slots 1000 \
      --cluster-yes
    # 迁移剩余槽位到其他节点
    redis-cli --cluster reshard 192.168.1.101:6379 \
      --cluster-from  \
      --cluster-to  \
      --cluster-slots 3096 \
      --cluster-yes

  3. 下线节点

    # 确认槽位已清空
    redis-cli -h 192.168.1.103 -p 6379 CLUSTER INFO | grep "cluster_slots_assigned"
    # 移除节点
    redis-cli --cluster del-node 192.168.1.100:6379 
    # 最终集群检查
    redis-cli --cluster check 192.168.1.100:6379

关键注意事项

  1. 迁移过程中会影响相应槽位的服务可用性
  2. 建议在业务低峰期执行迁移
  3. 对于大集群,考虑使用--cluster-timeout参数增加超时时间
  4. 可使用CLUSTER SETSLOT <slot> MIGRATING <node-id>CLUSTER SETSLOT <slot> IMPORTING <node-id>命令进行精细控制

四、Redis 哈希槽的特殊场景处理

4.1 大 Key 的哈希槽分配

对于大 Key(如体积超过 100MB 的 String、包含大量元素的 Hash/List),Redis 会采用特殊的处理机制:

  • 数据拆分:将大 Key 拆分为多个 "槽位片段",每个片段的大小通常在 1MB 左右
  • 哈希一致性:所有片段的哈希槽计算仍基于原始 Key 的 CRC16 值(模 16384)
  • 存储示例:比如一个 150MB 的 String 类型 Key "big:data" 会被拆分为约 150 个片段,但所有片段都存储在编号为 1234 的哈希槽中
  • 访问保证:这种设计确保客户端访问大 Key 时只需连接一个节点即可获取完整数据

4.2 多 Key 操作的哈希槽一致性

当执行多 Key 原子操作时,Redis 集群有严格的哈希槽一致性要求:

错误场景:

  • 典型错误:CROSSSLOT Keys in request don't hash to the same slot
  • 触发条件:如 MGET key1 key2,其中 key1 在槽 500,key2 在槽 600

解决方案:

  1. Key 命名规范:

    • 使用花括号{}指定哈希计算范围
    • 示例:对于用户 100 的相关数据:
      • "user:{100}:profile"
      • "user:{100}:orders"
      • "user:{100}:logs"
    • 计算原理:仅对 "{100}" 部分计算 CRC16,保证关联数据同槽
  2. 哈希标签(Hash Tag)高级用法:

    • 强制同槽场景:如跨类型数据关联
      • 订单系统示例: "order:{12345}" (Hash 类型) "order:{12345}_items" (List 类型) "order:{12345}_status" (String 类型)
    • 注意事项:过度使用可能导致数据倾斜

4.3 哈希槽故障转移

Redis 集群的故障转移机制包含以下详细过程:

故障检测阶段:

  • 节点间通过 Gossip 协议交换状态信息
  • 超过 500ms 无响应时标记为疑似下线(PFAIL)
  • 多数节点确认后升级为已下线(FAIL)

转移准备阶段:

  • 从节点发起选举:采用基于 Raft 的选举算法
  • 资格验证:从节点需具备完整复制偏移量
  • 选举成功条件:获得大多数主节点投票

数据迁移阶段:

  • 状态标记:
    • 原主节点槽位标记为 MIGRATING
    • 新主节点槽位标记为 IMPORTING
  • 客户端重定向:
    • ASK 重定向:临时路由变更
    • MOVED 重定向:永久路由更新
  • 数据同步:
    • 新主节点会完成全量同步
    • 确保没有数据丢失

恢复稳定阶段:

  • 集群状态更新:通过 Gossip 协议传播新配置
  • 客户端更新:智能客户端会缓存新路由表
  • 监控告警:触发哨兵的故障通知机制

五、Redis 哈希槽的常见问题与排查

5.1 问题 1:客户端收到MOVED或ASK错误

原因详解:

  • MOVED错误:表示客户端请求的Key对应的哈希槽已经永久性地重新分配给了集群中的其他节点。这种情况通常发生在:

    • 集群扩容后完成了槽位重新分配
    • 手动执行了CLUSTER SETSLOT命令更改了槽位归属
    • 故障转移后主从角色发生变化
  • ASK错误:表示客户端请求的Key对应的哈希槽正在迁移过程中。这种情况常见于:

    • 集群正在进行扩容/缩容操作
    • 手动执行槽位迁移但尚未完成
    • 节点故障恢复过程中

解决方案详细说明:

对于MOVED错误处理:
  1. 解析错误信息:MOVED错误格式为MOVED <slot> <ip>:<port>
  2. 更新本地槽位映射表:客户端应维护一个slot-node映射表(如{slot:node}字典)
  3. 重定向请求:将后续该槽位的所有请求直接发送到新节点
  4. 实现示例优化
class RedisClusterClient:
    def __init__(self, startup_nodes):
        self.slot_cache = {}  # 槽位缓存表
        self.nodes = startup_nodes
        self.refresh_slot_cache()
    def refresh_slot_cache(self):
        """从任意节点获取最新的集群槽位分配"""
        r = self._get_random_connection()
        cluster_slots = r.execute_command("CLUSTER SLOTS")
        for slot_info in cluster_slots:
            start_slot, end_slot = slot_info[0:2]
            master_node = slot_info[2]
            for slot in range(start_slot, end_slot+1):
                self.slot_cache[slot] = (master_node[0], master_node[1])
    def get(self, key):
        slot = self._calculate_slot(key)
        node = self.slot_cache.get(slot)
        if not node:
            raise Exception("Slot not found")
        r = redis.Redis(host=node[0], port=node[1])
        try:
            return r.get(key)
        except redis.exceptions.ResponseError as e:
            if "MOVED" in str(e):
                self.refresh_slot_cache()  # 刷新槽位映射
                return self.get(key)  # 重试
            raise

对于ASK错误处理:
  1. 临时重定向:仅对当前请求重定向到目标节点
  2. 不更新槽位表:因为迁移是临时状态
  3. 添加ASKING命令:在重定向请求前需要先发送ASKING命令
  4. Java客户端处理示例
try {
    return jedis.get(key);
} catch (JedisRedirectionException jre) {
    if (jre instanceof JedisAskDataException) {
        // 处理ASK重定向
        JedisAskDataException askEx = (JedisAskDataException)jre;
        try (Jedis redirectedJedis = new Jedis(askEx.getTargetNode().getHost(),
                                             askEx.getTargetNode().getPort())) {
            redirectedJedis.asking();  // 关键步骤
            return redirectedJedis.get(key);
        }
    }
    // 处理MOVED异常...
}

5.2 问题 2:哈希槽分配不均导致节点负载失衡

深入原因分析:

  1. 初始规划不足

    • 集群初期节点数过少(如3节点),每个节点负责约5461个槽位
    • 后期扩容时未重新平衡槽位分布
  2. 手动分配问题

    • 使用CLUSTER ADDSLOTS命令时分配不均
    • 扩容后使用CLUSTER SETSLOT迁移槽位时集中在少数节点
  3. 数据倾斜

    • 某些槽位包含热点Key(如秒杀商品)
    • 大Key集中在特定槽位

完整解决方案:

1. 诊断工具使用
# 查看详细槽位分布(包括主从)
redis-cli --cluster check 192.168.1.100:6379 --cluster-search-multiple-owners
# 查看节点内存使用情况
redis-cli -h 192.168.1.100 -p 6379 info memory | grep used_memory_human
# 找出热点Key(需要monitor权限)
redis-cli -h 192.168.1.100 -p 6379 --hotkeys

2. 再平衡操作
# 完整再平衡流程(带参数说明)
redis-cli --cluster rebalance 192.168.1.100:6379 \
    --cluster-weight node1=1.2 node2=0.8 \  # 调整权重
    --cluster-use-empty-masters \           # 包含空节点
    --cluster-simulate                      # 先模拟再执行

3. 预防措施
  • 定期检查:每周执行CLUSTER SLOTS检查分布
  • 自动均衡:使用redis-trib.rb工具设置自动均衡
  • 容量规划:提前规划节点数和槽位分布

5.3 问题 3:槽位迁移失败或卡住

详细排查步骤:

1.检查迁移状态

# 查看所有进行中的迁移
redis-cli -h 192.168.1.100 -p 6379 CLUSTER MIGRATINGSLOTS
# 查看特定槽位状态
redis-cli -h 192.168.1.100 -p 6379 CLUSTER NODES | grep -A 1 "migrating"

2.网络诊断

# 检查节点间连通性
redis-cli -h 192.168.1.100 -p 6379 CLUSTER INFO | grep -E "cluster_state|cluster_slots"
# 测试节点间延迟
redis-cli -h 源节点 -p 6379 --latency -i 1

大Key处理方案

分步骤处理大Key:

1.识别大Key

# 渐进式扫描(避免阻塞)
redis-cli -h 192.168.1.100 -p 6379 --bigkeys --memkeys -i 0.5

2.拆分方案

  • String类型:使用GETRANGE/SETRANGE分片
# 将5GB的user:log拆分为5个1GB的片段
for i in {0..4}; do
    redis-cli -h 192.168.1.100 -p 6379 GETRANGE "user:log" $((i*1073741824)) $(((i+1)*1073741824-1)) > "user:log.part$i"
    redis-cli -h 192.168.1.100 -p 6379 SET "user:log.part$i" "$(cat user:log.part$i)"
done

  • Hash类型:使用HSCAN分片
# 将大Hash拆分为多个子Hash
cursor=0
count=0
while true; do
    result=$(redis-cli -h 192.168.1.100 -p 6379 HSCAN "big:hash" $cursor COUNT 1000)
    cursor=$(echo "$result" | head -n1)
    # 处理返回的字段值对...
    if [[ "$cursor" == "0" ]]; then break; fi
done

3.迁移恢复

# 安全中断迁移流程
redis-cli -h 192.168.1.100 -p 6379 CLUSTER SETSLOT 1234 STABLE
# 重新规划迁移批次(每次迁移少量槽位)
redis-cli --cluster reshard 192.168.1.100:6379 \
    --cluster-from node-id1 \
    --cluster-to node-id2 \
    --cluster-slots 100 \  # 每次只迁移100个槽位
    --cluster-yes

预防措施:

1.迁移前检查

# 预估迁移数据量
redis-cli -h 192.168.1.100 -p 6379 CLUSTER COUNTKEYSINSLOT 1234

2.限流迁移

# 设置迁移速度限制(单位:MB/s)
redis-cli -h 192.168.1.100 -p 6379 CONFIG SET cluster-migration-barrier 2

3.监控指标

# 监控迁移进度
watch -n 1 "redis-cli -h 192.168.1.100 -p 6379 CLUSTER INFO | grep -E 'importing|migrating'"

六、Redis 哈希槽的监控与优化

6.1 哈希槽状态监控指标

为确保 Redis 集群稳定运行,需重点监控以下哈希槽相关指标,可通过redis-cli、Prometheus+Grafana 等工具实现:

哈希槽监控指标表

指标名称说明正常范围异常阈值处理建议
cluster_slots_assigned已分配的哈希槽总数16384<16384检查是否有节点下线或网络分区
cluster_slots_ok状态正常的哈希槽数量16384<16384检查故障槽所在节点的健康状况
cluster_slots_pfail处于疑似故障状态的哈希槽数量0>0检查节点间网络延迟和心跳包传输
cluster_slots_fail处于故障状态的哈希槽数量0>0立即执行故障转移或手动修复
单节点槽位数据量单个节点负责的所有槽位的数据总大小均匀分布某节点数据量是均值2倍+执行槽位再平衡操作
槽位迁移耗时单个哈希槽迁移的总时间<10s(中小数据量)>60s检查是否存在大Key或网络带宽瓶颈

监控工具配置示例

通过redis-cli监控
# 查看集群哈希槽分配状态
redis-cli -c -h 192.168.1.100 CLUSTER SLOTS
# 查看故障槽位信息
redis-cli -c -h 192.168.1.100 CLUSTER INFO | grep fail

通过Prometheus监控

在 Redis Exporter 配置中添加以下指标采集规则,即可在 Grafana 中可视化哈希槽状态:

# redis_exporter配置文件
redis:
  addr: "redis://192.168.1.100:6379"
  cluster: true # 开启集群模式监控
  metrics:
    include:
      - "cluster_slots_assigned"
      - "cluster_slots_ok"
      - "cluster_slots_pfail"
      - "cluster_slots_fail"
      - "cluster_slots_migrating"
      - "cluster_slots_importing"

Grafana仪表盘配置建议
  1. 创建集群槽位状态面板:用饼图显示正常/故障槽位比例
  2. 添加槽位迁移进度监控:显示正在迁移的槽位数量和耗时
  3. 设置告警规则:当故障槽位>0时触发PagerDuty告警

6.2 哈希槽优化策略

6.2.1 基于业务拆分哈希槽

典型业务场景划分
  1. 高频访问业务(如用户会话、秒杀库存):

    • 分配槽位范围:0-4095(25%槽位)
    • 节点配置:8核16GB SSD节点
    • 连接池配置:最大连接数500+
  2. 中频访问业务(如商品详情、购物车):

    • 分配槽位范围:4096-10239(37.5%槽位)
    • 节点配置:4核8GB SSD节点
    • 连接池配置:最大连接数300
  3. 低频访问业务(如历史订单、日志):

    • 分配槽位范围:10240-16383(37.5%槽位)
    • 节点配置:4核8GB HDD节点
    • 连接池配置:最大连接数100
实现步骤
# 将槽位0-4095分配给节点A
redis-cli --cluster reshard 192.168.1.100:6379 \
    --cluster-from all \
    --cluster-to  \
    --cluster-slots 4096 \
    --cluster-yes

6.2.2 避免哈希槽"热点"

热点Key优化方案对比
方案实现方式优点缺点适用场景
Key随机化添加随机后缀简单易实现需要修改业务代码临时性热点
槽位迁移迁移部分槽到新节点无需改代码需要额外节点资源持续性热点
本地缓存应用层缓存热点数据减轻Redis压力存在数据一致性问题读多写少场景
Key随机化实现示例
import random
def set_hot_key(key, value):
    slot_suffix = random.randint(0,9)
    distributed_key = f"{key}:{slot_suffix}"
    redis_client.set(distributed_key, value)
# 使用时
set_hot_key("seckill:goods:100", "in_stock")

槽位迁移操作流程
  1. 识别热点槽位:通过CLUSTER HOTSPOT命令或监控工具
  2. 新增节点并加入集群
  3. 迁移部分槽位:
    redis-cli --cluster reshard  \
        --cluster-from  \
        --cluster-to  \
        --cluster-slots 100 \
        --cluster-yes

6.2.3 预分配哈希槽应对扩容

预分配方案设计
  1. 3主3从集群

    • 实际分配:12288个槽(0-12287)
    • 预留槽位:4096个(12288-16383)
    • 每个主节点初始分配4096个槽
  2. 扩容到5主节点时

    • 新节点1:分配2048个预留槽(12288-14335)
    • 新节点2:分配2048个预留槽(14336-16383)
    • 无需数据迁移,立即可用
扩容操作示例
# 添加新节点
redis-cli --cluster add-node 192.168.1.200:6379 192.168.1.100:6379
# 分配预留槽位
redis-cli --cluster reshard 192.168.1.200:6379 \
    --cluster-from null \
    --cluster-to  \
    --cluster-slots 2048 \
    --cluster-yes \
    --cluster-use-empty-masters

预分配注意事项
  1. 预留比例建议:20-30%总槽位数
  2. 监控预留槽位使用情况,避免预留过多影响当前性能
  3. 文档记录槽位分配方案,避免后期管理混乱

七、Redis 哈希槽常用命令速查表

命令功能描述示例参数说明使用场景
CLUSTER KEYSLOT <key>查看指定 Key 对应的哈希槽编号CLUSTER KEYSLOT user:100<key>:需要查询的键名在需要确认某个键应该存储在哪个节点时使用,常用于调试和问题排查
CLUSTER SLOTS查看所有哈希槽的分配情况(节点、IP、端口)CLUSTER SLOTS无参数集群维护时查看当前槽位分布,或扩容/缩容前后对比槽位分配
CLUSTER ADDSLOTS <slot>为当前节点分配指定哈希槽CLUSTER ADDSLOTS 8192 8193<slot>:槽位编号(0-16383),可多个初始化集群时分配槽位,或扩容后为新节点分配槽位
CLUSTER DELSLOTS <slot>从当前节点删除指定哈希槽CLUSTER DELSLOTS 8192 8193<slot>:槽位编号(0-16383),可多个缩容前清空节点槽位,或重新分配槽位时使用
CLUSTER SETSLOT <slot> NODE <node-id>将指定槽位分配给目标节点CLUSTER SETSLOT 8192 NODE a1b2c3d4<slot>:槽位编号<br><node-id>:目标节点ID集群扩容时迁移槽位到新节点,或手动调整槽位分布
CLUSTER MIGRATINGSLOTS查看当前节点正在迁移的槽位CLUSTER MIGRATINGSLOTS无参数在槽位迁移过程中监控迁移状态
redis-cli --cluster reshard集群槽位重分配(扩容/缩容)redis-cli --cluster reshard 192.168.1.100:6379集群任一节点地址集群扩容后自动平衡槽位,或缩容前迁移槽位
redis-cli --cluster check检查集群槽位分配与节点健康状态redis-cli --cluster check 192.168.1.100:6379集群任一节点地址日常维护检查集群状态,或变更后验证配置

注意事项:

  1. 槽位操作需要确保集群处于健康状态
  2. 执行ADDSLOTS/DELSLOTS前需确保槽位未被其他节点持有
  3. 重分配槽位时建议在业务低峰期进行
  4. SETSLOT命令需要配合MIGRATING/IMPORTING状态使用

典型应用场景示例:

  1. 扩容操作流程:

    • 添加新节点到集群
    • 使用reshard命令自动迁移部分槽位
    • 通过CLUSTER SLOTS验证新分布
  2. 键定位问题排查:

    • 用KEYSLOT确认键所属槽位
    • 用SLOTS查找槽位所在节点
    • 连接到对应节点验证数据是否存在
posted on 2025-10-02 13:29  lxjshuju  阅读(21)  评论(0)    收藏  举报