本指南面向第一次接触本项目的用户。跟着 5 步走完,你将在终端看到 SELECT 命中缓存、UPDATE 触发表级失效,并感受单条 SQL 从 ~12ms 降到 <1ms 的差异。
mysql CLI、psql、GORM、JDBC、Python 驱动 ……
本项目用 Rust 写,依赖 tokio、sqlparser 等。如果你已经装过 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
克隆后第一件事是把 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})
this user requires clear text authentication ... add 'allowCleartextPasswords=1' to your DSN,即未开启明文插件;在 DSN 中加上 allowCleartextPasswords=true 即可(与 =1 等价)。若报 Error 1047 ... Unsupported MySQL command 0x16,请再加 interpolateParams=true 且 PrepareStmt: 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"
在 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]
根据业务读写比例调 cache.ttl_secs 与 cache.max_entries。读多写少的查询热点在这里收益最大。
backend.pool.max_per_key 决定同凭据的最大空闲连接;idle_ttl_secs 决定空闲多久被剔除。短连接业务把 max 调高收益最大。
多个副本前置同一后端时,开 broadcast.enabled = true,把所有副本指向同一个 broadcast-host + 同一个 group,DML 引发的失效会跨副本同步。完整说明见 集群广播文档。
跑真实业务流量后开 level: debug 看每条 SQL 的命中比例。日志文件路径在 log.path,异步落盘不阻塞热路径。