RedisCluster客户端路由智能缓存

通俗理解:客户端如何找到数据所在节点

具体流程分解:

1、客户端初始状态

java 复制代码
public class RedisClusterClient {
    // 刚开始,客户端不知道任何槽位对应关系
    private Map<Integer, String> slotToNodeCache = new HashMap<>();
    // 空的!像一张空白地图
}

2、第一次查询 - "问路过程"

java 复制代码
// 客户端想要执行:SET user:1001 "张三"
public void firstTimeRequest() {
    String key = "user:1001";
    int slot = CRC16(key) % 16384; // 计算槽位,比如得到 5000
    
    // 情况1:缓存中没有 → 随机选个节点发送请求
    if (!slotToNodeCache.containsKey(5000)) {
        // 随便选一个已知节点(比如节点A)
        sendCommandToNode("节点A", "SET", "user:1001", "张三");
    }
}

3、服务端响应 - "MOVED重定向"

java 复制代码
# 节点A检查槽位5000不属于自己,返回:
MOVED 5000 192.168.1.101:7001
# 意思是:"这个数据在5000号槽,应该去192.168.1.101:7001节点"

4. 客户端学习 - "更新地图"

java 复制代码
// 客户端处理MOVED响应
public void handleMovedResponse(String movedResponse) {
    // 解析:MOVED 5000 192.168.1.101:7001
    String[] parts = movedResponse.split(" ");
    int slot = Integer.parseInt(parts[1]);
    String correctNode = parts[2];
    
    // 重要:更新缓存!"记住5000槽在192.168.1.101:7001"
    slotToNodeCache.put(slot, correctNode);
    
    // 重新发送请求到正确节点
    resendToCorrectNode(correctNode, "SET", "user:1001", "张三");
}

5、后续请求 - "直接到达"

java 复制代码
// 第二次查询相同槽位的键
public void subsequentRequest() {
    String key = "user:1002"; // 相同用户ID,大概率在相同槽位
    int slot = CRC16(key) % 16384; // 还是5000左右
    
    // 现在缓存中有记录了!
    if (slotToNodeCache.containsKey(slot)) {
        String correctNode = slotToNodeCache.get(slot);
        // 直接去正确节点,不用问路了
        sendCommandToNode(correctNode, "GET", "user:1002");
    }
}

为什么需要这种设计?

java 复制代码
性能:避免每次请求都先问路
减负:减少服务端的路由查询压力
智能:客户端自己会学习,越来越聪明

问题

如果槽位和节点重新分布后,客户端的缓存怎么办?

详细的重定向处理流程

  1. MOVED重定向(永久迁移)

场景:槽位1000从节点A迁移到节点B已完成

public class SmartRedisClient {

private Map<Integer, String> slotCache = new HashMap<>();

复制代码
// 初始缓存:槽位1000在节点A
public void initCache() {
    slotCache.put(1000, "192.168.1.101:6379"); // 节点A
}

public void handleCommand(String key) {
    int slot = calculateSlot(key); // 假设是1000
    
    // 1. 客户端根据缓存发送到节点A
    String targetNode = slotCache.get(slot); // "192.168.1.101:6379"
    sendCommandToNode(targetNode, "SET", key, "value");
    
    // 2. 节点A返回MOVED重定向
    // 响应: "MOVED 1000 192.168.1.102:6379" (节点B)
}

public void processMovedResponse(String response) {
    // 解析MOVED响应: "MOVED <slot> <new-node>"
    String[] parts = response.split(" ");
    int movedSlot = Integer.parseInt(parts[1]);
    String newNode = parts[2];
    
    // 重要:永久更新缓存!
    slotCache.put(movedSlot, newNode);
    System.out.println("更新缓存: 槽位 " + movedSlot + " → " + newNode);
    
    // 重新发送请求到新节点
    resendToNewNode(newNode, movedSlot);
}

}

  1. ASK重定向(迁移中)

场景:槽位1000正在从节点A迁移到节点B

public class SmartRedisClient {

public void handleCommandDuringMigration(String key) {

int slot = calculateSlot(key); // 1000

复制代码
    // 1. 客户端根据缓存发送到节点A(源节点)
    String targetNode = slotCache.get(slot); // 仍然是节点A
    sendCommandToNode(targetNode, "SET", key, "value");
    
    // 2. 节点A检查键的迁移状态:
    if (isKeyMigrated(key, slot)) {
        // 键已迁移到节点B,返回ASK重定向
        return "ASK 1000 192.168.1.102:6379";
    } else {
        // 键还在节点A,正常处理
        return executeCommand(key);
    }
}

public void processAskResponse(String response) {
    // 解析ASK响应: "ASK <slot> <temp-node>"
    String[] parts = response.split(" ");
    int askSlot = Integer.parseInt(parts[1]);
    String tempNode = parts[2];
    
    // 重要:不更新永久缓存!
    System.out.println("临时重定向: 槽位 " + askSlot + " → " + tempNode + " (不更新缓存)");
    
    // 特殊流程:先发ASKING,再发命令
    sendAskingCommand(tempNode);    // 1. 发送ASKING命令
    resendToTempNode(tempNode);    // 2. 发送原命令
    
    // 缓存保持不变,后续请求仍然发往节点A
}

private void sendAskingCommand(String node) {
    // ASKING命令告诉目标节点:"我知道这是临时访问"
    sendCommandToNode(node, "ASKING");
}

}

相关推荐
roman_日积跬步-终至千里1 天前
【人工智能导论】02-搜索-高级搜索策略探索篇:从约束满足到博弈搜索
java·前端·人工智能
大学生资源网1 天前
java毕业设计之儿童福利院管理系统的设计与实现(源码+)
java·开发语言·spring boot·mysql·毕业设计·源码·课程设计
JasmineWr1 天前
JVM栈空间的使用和优化
java·开发语言
Hello.Reader1 天前
Flink SQL DELETE 语句批模式行级删除、连接器能力要求与实战避坑(含 Java 示例)
java·sql·flink
爱笑的眼睛111 天前
从 Seq2Seq 到 Transformer++:深度解构与自构建现代机器翻译核心组件
java·人工智能·python·ai
Spring AI学习1 天前
Spring AI深度解析(10/50):多模态应用开发实战
java·spring·ai
小鸡脚来咯1 天前
Redis与MySQL双写一致性(实战解决方案)
spring·oracle·mybatis
我是小妖怪,潇洒又自在1 天前
springcloud alibaba(九)Nacos Config服务配置
后端·spring·spring cloud
qq_12498707531 天前
重庆三峡学院图书资料管理系统设计与实现(源码+论文+部署+安装)
java·spring boot·后端·mysql·spring·毕业设计
大学生资源网1 天前
java毕业设计之“知语”花卉销售网站的设计与实现源码(源代码+文档)
java·mysql·毕业设计·源码·springboot