CacheSQL(四):CacheSQLClient——用一张路由表实现水平扩展

CacheSQL(四):CacheSQLClient------用一张路由表实现水平扩展


前三篇讲了 CacheSQL 内部的架构:工程化升级、主从复制、双引擎与 SQL 查询。但还有一个问题没解决------再多节点,对调用方来说还是一条 HTTP URL 吗?

不是。调用方需要知道哪个表在哪个节点上、Master 是谁、Slave 有谁、读操作打哪个、写操作打哪个。这些不应该让调用方自己管理------应该封装在一个 Client 里。

这就是 CacheSQLClient。


一、一张路由表,隐掉所有拓扑

配置:

properties 复制代码
# 组 insurance:负责 KCA2、KCA3 两张表
cachesql.group.insurance.master=http://192.168.1.10:8080
cachesql.group.insurance.slaves=http://192.168.1.11:8080,http://192.168.1.12:8080
cachesql.group.insurance.tables=KCA2,KCA3

# 组 finance:负责 KCA4 一张表
cachesql.group.finance.master=http://192.168.2.10:8080
cachesql.group.finance.slaves=http://192.168.2.11:8080
cachesql.group.finance.tables=KCA4

调用方只需要知道三件事:

java 复制代码
CacheSQLClient client = new CacheSQLClient("cachesql.properties");

// 查------自动打到 Master 或任意 Slave
List<Map<String, Object>> rows = client.get("KCA2", "AAC001", "12345");

// 写------自动打到 Master
boolean ok = client.insert("KCA2", "AAC001", "99999", data);

不需要知道 KCA2 在哪台机器上,不需要区分读操作打谁、写操作打谁。Client 内部按 Table → Group → URL 的路由链自动完成寻址。


二、路由逻辑:读分流,写集中

java 复制代码
private static class TableGroup {
    final String master;
    final String[] slaves;

    // 读:Master 或任意 Slave,各 50% 概率
    String pickReadUrl() {
        if (slaves.length == 0) return master;
        return random() ? master : slaves[(int)(Math.random() * slaves.length)];
    }

    // 写:始终 Master
    String getWriteUrl() {
        return master;
    }
}

简单但有效。读操作随机分摊到组内所有节点(Master + Slaves),Master 也不闲置。写操作始终打到 Master------因为只有 Master 有写入权限,Slave 的写操作最终也是转发给 Master。

这个设计借鉴了 MySQL 读写分离的经典模式:写走 Master,读分摊。但因为 CacheSQL 是内存库,没有"主从延时"的问题------一切都是同步写入后广播,读任意节点都是一致的数据。


三、按表分组:不同表走不同节点

不是所有表都在一组机器上。card_info 表数据量大、QPS 高,可能需要独立一组节点。dict 表数据量小、低频访问,可以和其他表共用一组。

TableGroup 的设计支持了这种灵活性:

java 复制代码
private final Map<String, TableGroup> tableToGroup = new LinkedHashMap<>();

private TableGroup findGroup(String tableName) {
    TableGroup group = tableToGroup.get(tableName);
    if (group == null)
        throw new IllegalArgumentException("No group configured for table: " + tableName);
    return group;
}

每个表通过配置文件绑定到一个组。调用方传表名,Client 自动路由到对应的组。这是传统分库分表中间件的简化版------不做数据拆分,只做路由隔离。


四、自带的 JSON 解析器:零外部依赖

CacheSQL 的服务器返回的是 JSON。正常做法是用 Jackson 或 Gson 反序列化。但 CacheSQLClient 只依赖 JDK 标准库------自己实现了一个 JSON 解析器。

这不是为了炫技。是为了"零依赖"------调用方不需要为了用 CacheSQL 引入任何额外的 JAR 包。一个 CacheSQLClient.java 扔进项目就能用。

实现方式:逐字符扫描。区分字符串内/外、跟踪花括号深度、按逗号切字段。对象嵌套用 matchBrace 递归匹配括号对确定边界------不是完整的 JSON 解析器,但覆盖了服务器返回的扁平对象数组格式。

java 复制代码
private int matchBrace(String s, int start) {
    int depth = 0;
    boolean inStr = false;
    for (int i = start; i < s.length(); i++) {
        char c = s.charAt(i);
        if (inStr) {
            if (c == '\\') i++;
            else if (c == '"') inStr = false;
        } else {
            if (c == '"') inStr = true;
            else if (c == '{') depth++;
            else if (c == '}') { depth--; if (depth == 0) return i; }
        }
    }
    return -1;
}

这是"够用主义者"的做法------不写完整的 JSON 规范实现,只处理 CacheSQL 服务器实际返回的格式。工程上正确。


五、Client 与服务器之间的分工

CacheSQLClient 把三件事集中在一个类里:

  1. 路由发现:从配置文件读取 Group 信息
  2. 负载均衡:读操作随机分摊到组内所有节点
  3. 协议适配:HTTP GET/POST + JSON 解析

三件事分开都能做------路由用 Nginx,负载用 HAProxy,协议用 Jackson。但合在一起的好处是:调用方的 pom.xml 不需要加任何依赖。一行 new CacheSQLClient("cachesql.properties") 全部搞定。

代价是什么?配置方式的灵活性------分组规则必须写在 properties 文件里,不能动态从注册中心发现。但在政务系统的部署环境下,节点拓扑是静态的------配置文件的方式反而更可控。


六、水平扩展的完整方案

回顾 CacheSQL 的水平扩展全貌:

复制代码
           CacheSQLClient
           (路由表 + 读负载均衡)
                 │
        ┌────────┼────────┐
        ▼        ▼        ▼
    ┌───────┐┌───────┐┌───────┐
    │Master ││Slave 1││Slave 2│  ← Group: insurance
    │.10    ││.11    ││.12    │
    └───┬───┘└───────┘└───────┘
        │ 广播
    ┌───┴───┐┌───────┐┌───────┐
    │Master ││Slave 1││Slave 2│  ← Group: finance
    │.20    ││.21    ││.22    │
    └───────┘└───────┘└───────┘
  • Client 层:表名 → 组名 → URL,调用方零感知
  • Group 层:一主多从,总共可以定义任意多个组
  • Server 层:Master 写入 + 广播,Slave 接收回放

水平扩展不是给你无限 QPS 的------它是让你在想加节点的时候,不用改代码。


下一篇:[桥接篇:从练手到交付------四篇博客之后,我回头做了 CacheSQL]


系列:CacheSQL 工程化交付实录(共 5 篇,含桥接篇)

相关推荐
Lyyaoo.1 小时前
缓存穿透/雪崩/击穿
数据库·缓存·oracle
许彰午1 小时前
CacheSQL(三):双 HTTP 引擎与 SQL 查询——接口抽象的价值
java·数据库·sql·缓存
lKWO OMET1 小时前
mysql之字符串函数
android·数据库·mysql
手握风云-2 小时前
Spring AI:让大模型住进 Spring 生态(三)
java·后端·spring
咸鱼2.03 小时前
【java入门到放弃】Dubbo
java·开发语言·dubbo
JAVA面经实录91710 小时前
Java企业级工程化·终极完整版背诵手册(无遗漏、全覆盖、面试+落地通用)
java·开发语言·面试
Flying pigs~~11 小时前
RAG智慧问答项目
数据库·人工智能·缓存·微调·知识库·rag
misL NITL11 小时前
mysql之如何获知版本
数据库·mysql
许彰午11 小时前
CacheSQL(二):主从复制——OpLog 环形缓冲区与故障自动恢复
java·数据库·缓存