MySQL分库分表的核心目的是解决单库单表在数据量、并发访问量增长时遇到的性能瓶颈和存储上限问题,通过数据拆分实现水平扩展。
一、核心拆分原理
分库分表主要分为垂直拆分 和水平拆分两大类。
| 拆分类型 | 拆分维度 | 描述 | 优点 | 缺点 |
|---|---|---|---|---|
| 垂直分库 | 按业务模块 | 将不同业务领域的表拆分到不同的数据库中。 | 降低单库压力,业务解耦,便于独立扩展。 | 跨库事务复杂,无法解决单表数据量过大的问题。 |
| 垂直分表 | 按表字段 | 将一张宽表的字段按访问频次或业务属性拆分到多张表中(如热点字段与冷字段分离)。 | 减少单次查询的I/O,提升热点数据访问效率。 | 查询可能需JOIN,增加应用复杂度。 |
| 水平分库 | 按数据行,分布到不同库 | 将同一张表的数据按规则分布到多个数据库中。 | 大幅降低单库数据量和访问压力,是应对高并发的核心手段。 | 跨库查询、分布式事务、全局主键生成复杂。 |
| 水平分表 | 按数据行,在同一库内 | 将同一张表的数据按规则拆分到同一数据库的多个子表中。 | 解决单表数据量过大问题,操作相对简单。 | 仍受限于单台数据库服务器的性能(CPU、I/O、连接数)。 |
二、常用数据分片策略
水平拆分(分库分表)的关键在于如何将数据均匀分布到不同的库或表中,常用策略如下:
| 策略 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| 范围分片 | 按某个字段的范围(如时间、ID区间)划分。例如,按月份分表。 | 数据连续,易于范围查询和扩容。 | 容易产生数据热点(如最新月份数据访问集中)。 |
| 哈希分片 | 对分片键(如user_id)进行哈希运算,再取模决定目标位置。 |
数据分布均匀,避免热点。 | 扩容时(如从2库扩到3库)需要大量数据迁移。 |
| 一致性哈希 | 改进的哈希算法,将数据和存储节点映射到哈希环上。 | 扩容时仅需迁移部分数据,影响小。 | 实现相对复杂。 |
| 地理位置/业务属性分片 | 按地区、租户ID等业务属性划分。 | 符合业务逻辑,便于数据隔离和管理。 | 分布可能不均衡,依赖业务规则。 |
三、实现方式
- 应用层(客户端)实现
在应用程序代码中封装数据访问层,直接根据分片规则计算数据源和表名,进行路由和结果聚合。例如,在Laravel框架中,可以通过自定义数据库连接和查询构建器来实现。
php
// 示例:基于 user_id 的简单哈希分表查询逻辑
$userId = 12345;
$shardKey = $userId % 4; // 假设分为4个表
$tableName = 'user_' . $shardKey;
// 执行查询
$user = DB::table($tableName)->where('user_id', $userId)->first();
实现要点:需在业务代码中管理所有数据源连接,并处理跨分片查询(如UNION)。
- 中间件(代理层)实现
使用独立的中间件服务(如MyCAT、ShardingSphere-Proxy)代理所有数据库请求。应用像连接单库一样连接中间件,由中间件完成SQL解析、路由、执行和结果归并。
yaml
# 以ShardingSphere配置片段为例(YAML格式)
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds${0..1}.t_order_${0..1} # 数据节点:2个库,每个库2张表
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: table_inline
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: database_inline
shardingAlgorithms:
database_inline:
type: INLINE
props:
algorithm-expression: ds${user_id % 2}
table_inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 2}
中间件对应用透明,功能强大,但引入了新的运维点和网络跳转。
四、面临的挑战与应对
- 分布式ID生成:需保证全局唯一、趋势递增。常用方案有雪花算法(Snowflake)、号段模式、Redis自增等。
- 跨分片查询与排序 :中间件通常支持将查询分发到多个分片,然后在内存中进行结果合并(
MERGE、ORDER BY、GROUP BY)。复杂查询可能效率低下。 - 分布式事务:保证跨库操作的一致性。可采用XA协议、基于消息的最终一致性(如Seata的AT模式)、TCC等方案。
- 数据迁移与扩容:动态扩容(如增加分片)时,需平滑迁移数据。可使用双写、数据校验等工具进行在线迁移。
五、核心原则与建议
- 能不分则不分:分库分表显著增加系统复杂度和维护成本,应在单表数据量达到千万级、并发压力巨大时再考虑。
- 优先优化单表:考虑通过优化索引、字段类型、归档历史数据、读写分离等手段提升性能。
- 选择合适的分片键:分片键应能保证数据均匀分布,且是高频查询的条件,避免跨分片查询。
- 提前规划容量:设计分片策略时需预留一定的扩展空间,避免频繁扩容。