楼层: 首页/ 软件技术/ 中间件全景/ 数据库中间件:连接池、读写分离、分库分表
03

数据库中间件:连接池、读写分离、分库分表

Database Middleware · Connection Pool / RWS / Sharding

数据库中间件就是"在应用和数据库之间加一层",搞定三件事:连接池(别每次都重新建连接)、读写分离(写主库读从库)、分库分表(单库单表扛不住了就拆开)。没有它,你的应用每次查数据都要重新握手建连接,慢死;读多写少时所有请求都打主库,主库累死;单表几千万行,查询慢如蜗牛。

2.1 什么是数据库中间件

论为什么需要这一层

在应用和数据库之间加一层,搞定连接池/读写分离/分库分表/缓存。想象一下:你的应用有 100 个并发请求,每个请求都新建一个 TCP 连接连 MySQL——TCP 握手 + 认证 + 建连接,一个连接要几毫秒,100 个并发就几百毫秒浪费在"连接"上。有了连接池,连接提前建好放池子里,用的时候拿、用完还回去,省掉反复建连的开销。

读写分离更直白:主库负责写(INSERT/UPDATE/DELETE),从库负责读(SELECT)。主库把数据同步给从库,应用读的时候走从库,主库就不那么累了。数据库中间件帮你自动把"写"路由到主库、"读"路由到从库,应用层无感知。

2.2 连接池原理:为什么不能裸连

每次创建/销毁一个数据库连接要经历:TCP 三次握手 → MySQL 认证 → 执行 SQL → 关闭连接。这一套下来少说 1-3ms,高并发下全浪费在连接上。连接池就是预先建好一批连接放在池子里,用的时候拿,用完还回去,不关闭。

连接池核心参数
参数含义调优建议
maxActive池里最多多少个连接按 CPU 核数 × 2 起步,别太大(MySQL 每个连接占内存)
maxIdle池里最少保持多少个空闲连接和 maxActive 差不多,避免频繁建连
minIdle启动时初始化多少个连接5-10 个,启动时别建太多
maxWait池子满了,等多久拿不到连接就报错(毫秒)3000-5000ms,别太长,快速失败

HikariCP(Spring Boot 默认)连接池配置 application.yml

spring: datasource: url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=Asia/Shanghai username: root password: "your_password" # HikariCP 配置(Spring Boot 2+ 默认连接池) hikari: maximum-pool-size: 20 # 最多 20 个连接 minimum-idle: 5 # 最少保持 5 个空闲 connection-timeout: 3000 # 等 3 秒拿不到连接就报错 idle-timeout: 600000 # 空闲 10 分钟回收 max-lifetime: 1800000 # 连接最多活 30 分钟(MySQL 默认 wait_timeout 8h)
HikariCP vs Druid 连接池对比
对比点HikariCPDruid(阿里)
性能极快(字节码级优化,fastlist)够用,略慢
监控基本无自带监控面板,SQL 执行统计
SQL 防火墙无有,可拦截危险 SQL
Spring Boot 默认是(2.x 起)否,需手动引入
适合追求极致性能需要监控和 SQL 审计

2.3 读写分离:主库写、从库读

数据库扛不住了,最经典的水平扩展方案就是主从复制 + 读写分离。主库负责写,数据通过 binlog 同步到从库;应用读的时候走从库,写的时候走主库。数据库中间件或框架帮你自动路由。

应用
自动路由:写→主,读→从
主库 Master
写操作 + 同步 binlog
⇒
从库 Slave1
读操作
⇒
从库 Slave2
读操作

ShardingSphere-JDBC 读写分离配置(Spring Boot)

spring: shardingsphere: datasource: names: master,slave0,slave1 master: type: com.zaxxer.hikari.HikariDataSource jdbc-url: jdbc:mysql://master-host:3306/demo username: root password: "***" slave0: jdbc-url: jdbc:mysql://slave0-host:3306/demo username: root password: "***" rules: readwrite-splitting: data-sources: write_ds: static: write-data-source-name: master read-data-source-names: slave0,slave1
主从延迟的坑

主库写完,数据要过个几十毫秒到几秒才同步到从库。如果你写完立刻读,读从库可能读到旧数据。解决方案:① 写完后的一小段时间强制走主库;② 用 HintManager 强制走主库;③ 业务上接受短暂不一致。面试常考。

2.4 分库分表:单库单表扛不住了

单表几千万行,查询开始慢了;单库几十张表,写入到瓶颈了。这时候要分库分表:把数据按某个规则(用户 ID、订单 ID)拆散到多个库或多个表里。垂直拆分按业务拆(用户库/订单库/商品库),水平拆分按行拆(同一张表的数据散到 N 个表)。

分库分表中间件对比
中间件特点适合
ShardingSphereApache 顶级项目,JDBC 轻量级(嵌应用里)+ Proxy 独立部署,社区活跃新项目首选,Java 生态
MyCat基于 Cobar,早年火,现在维护放缓老项目维护
VitessYouTube 开源,云原生,K8s 友好超大规模、K8s 环境

2.5 pgpool-II:PostgreSQL 的连接池 + 读写分离

如果你用的是 PostgreSQL 而不是 MySQL,pgpool-II 就是它的中间件:连接池、读写分离、复制、限制连接数,一个工具全搞定。

# pgpool.conf 核心配置 listen_addresses = '*' port = 9999 # 后端 PostgreSQL 节点 backend_hostname0 = 'master-host' backend_port0 = 5432 backend_weight0 = 1 backend_hostname1 = 'slave-host' backend_port1 = 5432 backend_weight1 = 1 # 连接池模式 pool_mode = 'session' # session/transaction/statement num_init_children = 32 # 最多 32 个连接 # 读写分离 load_balance_mode = on # SELECT 自动走从库
2.6 数据库中间件面试重点

Q1:连接池为什么能提高性能?

查看答案

避免反复建连/断连(TCP握手+认证每连接几毫秒),复用已有连接。参数 maxActive 控制上限,太大浪费数据库内存,太小排队。

Q2:读写分离后主从延迟怎么办?

查看答案

① 写完后强制走主库(HintManager);② 业务上接受短暂不一致(最终一致);③ 半同步复制减少延迟。面试常考。

Q3:分库分表的分片算法有哪些?

查看答案

① 取模(user_id % N),简单但扩容要迁移数据;② 范围分片(按时间/ID段),扩容方便但可能热点;③ 一致性哈希,扩容迁移少;④ 查表(配置路由表),灵活但有单点。

记
第二章小结

① 连接池是标配:HikariCP 性能党,Druid 监控党。参数 maxActive/maxIdle/maxWait 调对就行。

② 读写分离 = 主写从读,主从延迟要靠"写完走主库"兜底。

③ 分库分表是单表扛不住后的终极方案,ShardingSphere 是新项目首选。