约 5 分钟看到第一条 [HIT] · 单条 SQL 命中 < 1ms

把缓存代理跑起来
Quick Start

本指南面向第一次接触本项目的用户。跟着 5 步走完,你将在终端看到 SELECT 命中缓存、UPDATE 触发表级失效,并感受单条 SQL 从 ~12ms 降到 <1ms 的差异。

前置条件:Linux / macOS · Rust 1.75+ · 已经能连上一个 MySQL 5.7+ 或 PostgreSQL 12+ 后端(本机或远端均可)。 客户端工具任选:mysql CLI、psql、GORM、JDBC、Python 驱动 ……

装 Rust 工具链

本项目用 Rust 写,依赖 tokiosqlparser 等。如果你已经装过 Rust,跳到下一步。

# 一行装好 rustup(包含 cargo / rustc)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"

# 验证
cargo --version
# cargo 1.7x.x

克隆仓库 & 改 config.yaml

克隆后第一件事是把 backend 段指到你能连上的真实数据库。凭据不进配置 — 客户端连进来时再带

# 克隆(请替换为实际 Git 仓库地址)
git clone <your-repo-url> database-cache-proxy
cd database-cache-proxy

# 编辑 config.yaml,重点是 backend.host/port/protocol
$EDITOR config.yaml

最小可运行示例:

proxy:
  listen: "0.0.0.0:3307"

backend:
  host: "127.0.0.1"
  port: 3306                  # 或 5432 for PG
  protocol: "auto"            # 启动时拨测后端识别协议;也可写 "mysql" / "postgresql"
  pool:
    enabled: true
    max_per_key: 16
    idle_ttl_secs: 300
    reset_query: "DISCARD ALL"  # MySQL 自动映射为 COM_RESET_CONNECTION

cache:
  enabled: true
  ttl_secs: 300
  max_entries: 10000

log:
  level: "info"
  stdout_level: "warn"
  path: "log/database-cache-proxy.log"
  file_async: true
backend.protocol: "auto" 时代理会启动期间 TCP 拨测后端:MySQL 服务器主动下发 Initial Handshake(特征 […,0x00,0x0a]),PG 则用一次 SSLRequest 探测,回复字节 S/N/E 都是 PG。客户端侧说什么协议必须跟后端一致,代理不在中间做协议翻译。

编译 & 启动代理

第一次编译大约 1–2 分钟(debug),release 多几十秒。生产环境一定要 release。

# 开发模式(编译快、二进制大、运行慢)
cargo run -- --config config.yaml

# 生产模式(编译慢、二进制小、运行快)
cargo build --release
./target/release/database-cache-proxy --config config.yaml

# 或者用 Makefile
make run

看到下面这两行就说明启动成功:

[INFO] proxy listening on 0.0.0.0:3307 · mysql + postgresql
[INFO] backend pool · max_per_key=16 · idle_ttl=300s · reset="DISCARD ALL"

客户端连接

无论你后端是哪个数据库,客户端按自己的协议连 127.0.0.1:3307 即可。

MySQL — cleartext plugin 必须开(代理需要明文密码去后端做真鉴权):

# mysql CLI
mysql --enable-cleartext-plugin -h 127.0.0.1 -P 3307 -u root -p

# Go GORM:cleartext + 走 COM_QUERY(勿发 COM_STMT_PREPARE)
"root:pw@tcp(127.0.0.1:3307)/mydb?allowCleartextPasswords=true&interpolateParams=true"
# gorm.Open(..., &gorm.Config{ PrepareStmt: false })

# JDBC url
"jdbc:mysql://127.0.0.1:3307/mydb?allowPublicKeyRetrieval=true&useSSL=false"
# 加属性 cleartextPassword=true

# Python pymysql
pymysql.connect(host="127.0.0.1", port=3307, user="root", password="pw", db="mydb",
                auth_plugin_map={"mysql_clear_password": ClearPasswordHandler})
GORM / go-sql-driver 若报错 this user requires clear text authentication ... add 'allowCleartextPasswords=1' to your DSN,即未开启明文插件;在 DSN 中加上 allowCleartextPasswords=true 即可(与 =1 等价)。若报 Error 1047 ... Unsupported MySQL command 0x16,请再加 interpolateParams=truePrepareStmt: false。完整说明见 MySQL 路径文档

PostgreSQL — 不需要任何额外开关,标准 cleartext 密码:

# psql
psql -h 127.0.0.1 -p 3307 -U postgres -d mydb

# Go pgx dsn
"postgres://postgres:pw@127.0.0.1:3307/mydb?sslmode=disable"

# JDBC url
"jdbc:postgresql://127.0.0.1:3307/mydb"
密码会在 客户端 → 代理 这一跳以明文传输,请只在受信网络里用(loopback / 同 Pod / 私网)。代理 → 后端那一跳依然走后端选定的鉴权(SCRAM / native_password / …),不存任何凭据。

验证缓存命中与失效

在 SQL CLI 里跑 SELECT → SELECT → UPDATE → SELECT,对照另一个终端的代理日志看:

# MySQL 例子(PG 同理,把语法换成 PG 的)
mysql> SELECT * FROM users WHERE id = 1;   -- MISS · 11ms
mysql> SELECT * FROM users WHERE id = 1;   -- HIT  · 0.8ms
mysql> UPDATE users SET name = 'Ada' WHERE id = 1;
mysql> SELECT * FROM users WHERE id = 1;   -- MISS · 11ms (缓存被失效)

代理日志(tail -f log/database-cache-proxy.log)应该看到:

cache MISS query="SELECT * FROM users WHERE id = 1" tables=[users]
cache STORE query_hash=ab12.. bytes=312
cache HIT  query="SELECT * FROM users WHERE id = 1" replay_us=820
cache INV  table=users evicted=1
cache MISS query="SELECT * FROM users WHERE id = 1" tables=[users]
看到这 4 行就成了。缓存生效、回放正确、表级失效精确 — 接下来就可以把业务连过来跑真实流量。
下一步

跑通之后做什么?

调缓存策略

根据业务读写比例调 cache.ttl_secscache.max_entries。读多写少的查询热点在这里收益最大。

调连接池

backend.pool.max_per_key 决定同凭据的最大空闲连接;idle_ttl_secs 决定空闲多久被剔除。短连接业务把 max 调高收益最大。

多副本:开广播失效

多个副本前置同一后端时,开 broadcast.enabled = true,把所有副本指向同一个 broadcast-host + 同一个 group,DML 引发的失效会跨副本同步。完整说明见 集群广播文档

压测 & 调日志

跑真实业务流量后开 level: debug 看每条 SQL 的命中比例。日志文件路径在 log.path,异步落盘不阻塞热路径。

跑通了?翻开完整文档

架构原理、MySQL 路径打通历程、PG 路径性能调优、所有可调参数 ……