数据库架构
现代系统数据库架构通常包含主从复制、读写分离、分库分表或分布式数据库。
演进路径
单机 MySQL
│ 读压力大
▼
主从 + 读写分离
│ 写压力大 / 数据量超过单机
▼
分库分表(ShardingSphere / Vitess)
│ 运维复杂,跨分片查询难
▼
分布式数据库(TiDB / PolarDB-X)
主从复制(Master-Slave)
写请求
│
▼
┌──────────┐
│ Master │ ← 所有写操作
└────┬─────┘
│ Binlog 复制
│ 异步 / 半同步 / 同步
┌────┴──────────────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ Slave 1 │ │ Slave 2 │
└──────────┘ └──────────┘
↑ ↑
读请求 读请求
复制模式:
| 模式 | 说明 | 风险 |
|---|---|---|
| 异步复制 | 默认模式,Master 写完即返回 | 主库宕机可能丢数据 |
| 半同步复制 | 至少一个 Slave 收到 Binlog 才返回 | 延迟略高 |
| 全同步复制 | 所有 Slave 确认才返回 | 性能差 |
| MGR(Group Replication) | 多主,Paxos 协议 | 配置复杂 |
读写分离实现:
- 应用层:ShardingSphere-JDBC 拦截 SQL,自动路由读写
- 代理层:ProxySQL / MaxScale 作为中间代理
- K8s 内:分别创建写 Service 和读 Service 指向不同 Pod
分库分表
为什么需要
- 单表数据量超过 1000万行时索引效率下降
- 单机写 QPS 超过 ~5000 时成为瓶颈
- 存储空间超过单机上限
拆分策略
垂直分库:按业务拆分(用户库、订单库、商品库)
单体数据库
↓ 拆分
用户库(user_db) 订单库(order_db) 商品库(product_db)
水平分表:同一业务按规则分到多张表
orders 表 → orders_0, orders_1, ..., orders_15
路由规则:user_id % 16
分片路由
| 路由方式 | 说明 | 优缺点 |
|---|---|---|
| 取模(Hash) | user_id % N | 均匀,扩容需迁移数据 |
| 范围(Range) | 时间范围、ID 范围 | 扩容方便,可能热点 |
| 一致性 Hash | 环形 Hash,减少迁移 | 实现复杂 |
| 目录(Lookup) | 单独维护路由表 | 灵活,多一次查询 |
主流方案
| 方案 | 特点 |
|---|---|
| ShardingSphere | Java 生态,支持 JDBC 和 Proxy 两种接入方式 |
| Vitess | YouTube 开源,K8s 原生,MySQL 兼容 |
| TiDB | 分布式数据库,自动分片,无需改代码 |
| PolarDB-X | 阿里云,MySQL 兼容,分布式事务 |
Vitess 架构
Application
│
▼
VTGate(SQL 路由层)
│ 解析 SQL,路由到对应分片
▼
VTablet(每个 MySQL 实例的代理)
├── MySQL Shard 0
├── MySQL Shard 1
└── MySQL Shard 2
│
Topology(etcd / ZK,存储分片元数据)
TiDB 架构
┌──────────┐
│ TiDB │ MySQL 协议兼容,SQL 解析层
└────┬─────┘
│
┌─────────┴─────────┐
▼ ▼
┌────────┐ ┌────────┐
│ TiKV │ ←────► │ PD │
│ 分布式 │ │ 调度中心│
│ 存储 │ └────────┘
└────────┘
- TiDB:SQL 层,无状态,可水平扩展
- TiKV:分布式 KV 存储,Raft 多副本
- PD:集群调度,负责 Region 分配和负载均衡
TiDB 特点:
- MySQL 协议兼容,应用改动极小
- 分布式事务(Percolator 协议)
- HTAP:同时支持 OLTP 和 OLAP(TiFlash 列存引擎)
- 自动分片,无需手动分库分表
分布式事务
| 方案 | 一致性 | 性能 | 适用场景 |
|---|---|---|---|
| 2PC(两阶段提交) | 强一致 | 差 | 不推荐,锁时间长 |
| TCC(Try-Confirm-Cancel) | 强一致 | 中 | 核心金融场景 |
| Saga | 最终一致 | 好 | 长流程业务(跨多服务) |
| 本地消息表 | 最终一致 | 好 | 与 MQ 配合,简单可靠 |
| Seata | 多模式支持 | 中 | Java 生态 |
本地消息表(推荐):
业务 DB(同一事务):
INSERT INTO orders ...
INSERT INTO local_messages (event='order.created', status='PENDING')
定时任务:
扫描 PENDING 消息 → 发送 MQ → 更新状态为 SENT
消费方处理成功后确认
数据库选型参考
| 场景 | 推荐 |
|---|---|
| 单机 OLTP | MySQL / PostgreSQL |
| 读多写少,高并发读 | MySQL 主从 + 读写分离 |
| 数据量大,需分片 | ShardingSphere + MySQL / TiDB / OceanBase / Vitess |
| HTAP(同时分析) | TiDB、OceanBase |
| PG 栈、全球多活 | CockroachDB |
| 时序数据 | InfluxDB / TimescaleDB |
| 文档存储 | MongoDB |
| K-V 高速 | Redis |