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

相关推荐
言乐61 小时前
Python视频相对亮度检测
数据库·python·计算机视觉·小程序·音视频
并不喜欢吃鱼2 小时前
从零开始 C++----- 十五.一文吃透 C++ 异常:try-catch、栈展开、自定义异常、异常安全 noexcept 底层全剖析
java·开发语言·jvm
snow@li2 小时前
中台:中台即复用 / 理解企业架构中的能力抽象与分层共享 / 中台体系全景梳理 / 共性能力抽象、沉淀并复用
数据库
智码看视界2 小时前
Day19 Spring Boot启动优化:启动时间从8秒降到2秒
java·spring boot·后端·启动优化
SelectDB技术团队2 小时前
AB 实验指标计算场景:Apache Doris / SelectDB 的技术能力、选型对比与实践
大数据·数据库·数据分析·apache·用户运营·apache doris·selectdb
snow@li2 小时前
数据库:B+ 树 / 数据库索引的底层支柱
数据库
北京阿法龙科技有限公司2 小时前
AR智能眼镜安防应用核心指标:识别距离筑牢防线
java·开发语言·ar
殘殤血2 小时前
Tomcat的事件监听机制:观察者模式 _
java·观察者模式·tomcat
汤姆yu2 小时前
面向具身智能的物理视频模拟器:蚂蚁灵波LingBot-Video开源模型全解析
java·大数据·人工智能·gpt·开源·大模型·音视频
cxr8282 小时前
缓存策略探测实验方案架构设计
缓存