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 篇,含桥接篇)

相关推荐
莫雪歌28 分钟前
Java AI 应用开发实践:基于 Spring Boot 实现 Chat、Memory、RAG 与 Tool Calling
java·aigc
知识分享小能手1 小时前
Flask入门学习教程,从入门到精通,数据库操作 — 知识点详解与案例代码(4)
数据库·学习·flask
我是一颗柠檬1 小时前
【MySQL全面教学】MySQL基础SQL语句Day3(2026年)
数据库·后端·sql·mysql·oracle
XS0301061 小时前
MyBatis动态SQL
数据库·sql·mybatis
MandalaO_O1 小时前
MyBatis 与 MySQL 执行流程
数据库·mysql·mybatis
SmartBrain1 小时前
AI全栈开发(SDD):慢病管理系统工程级设计
java·大数据·开发语言·人工智能·架构·aigc
梦想CAD控件1 小时前
网页端对DWG图纸进行预览与批注(CAD轻量化)
java·前端·javascript
老毛肚2 小时前
Spring boot 特性和自写Reids组件
java·spring boot·后端
极光代码工作室2 小时前
基于SpringBoot的课程管理系统
java·springboot·web开发·后端开发
JustNow_Man2 小时前
【opencode】安装使用daytona沙箱插件
android·java·javascript