MySQL 的分库分表是应对海量数据和高并发访问的核心解决方案,主要通过将数据分散存储到多个数据库或数据表中来实现。主要方式可以分为以下几类:
一、 垂直拆分
-
垂直分库
- 概念: 按照业务功能模块将原本在单一数据库中的表拆分到不同的数据库中。
- 依据: 业务领域的划分。
- 例子:
- 原始单库:包含
用户表(user)、订单表(order)、商品表(product)、日志表(log)等。 - 垂直分库后:
- 用户库 (
user_db):user - 订单库 (
order_db):order,order_detail - 商品库 (
product_db):product,category,sku - 日志库 (
log_db):log
- 用户库 (
- 原始单库:包含
- 优点:
- 解耦业务,不同业务使用独立数据库,降低耦合度。
- 便于针对不同业务库进行优化(硬件、配置)。
- 分散数据库连接压力(不同业务应用连接不同的库)。
- 缺点:
- 无法解决单表数据量过大的问题(如订单表特别大)。
- 跨库事务处理复杂(通常需要分布式事务解决方案)。
- 无法执行跨库的关联查询(JOIN),需要在应用层处理。
-
垂直分表
- 概念: 在一个数据库内,将一个包含很多字段的大表,按照字段的访问频次或业务关联性拆分成多个小表。
- 依据: 字段的热点程度、冷热数据分离、大字段分离。
- 常见方式:
- 主表 + 扩展表: 将常用字段(核心信息)放在主表,将不常用字段(如长文本、JSON配置、附加信息)放在扩展表,通过主键关联。
- 例:
user_base(id, username, password, email) 和user_profile(id, real_name, avatar, bio, address)。
- 例:
- 冷热数据分离: 将频繁更新的“热”数据(如订单状态)和很少更新的“冷”数据(如订单创建信息)分离。
- 主表 + 扩展表: 将常用字段(核心信息)放在主表,将不常用字段(如长文本、JSON配置、附加信息)放在扩展表,通过主键关联。
- 优点:
- 减少单行数据大小,提高单次 I/O 效率,缓存更多热点数据。
- 提升高频查询字段的访问速度。
- 缺点:
- 需要管理表间关联关系。
- 查询完整数据需要 JOIN 操作(虽然在同一库内,但仍有一定开销)。
- 无法根本解决单表数据行数过多的问题。
二、 水平拆分 (Sharding)
这是解决单表数据量过大的核心手段。
-
水平分库
- 概念: 将同一个表的数据,按照某种规则(分片键/分片算法)分散存储到多个数据库中。每个数据库的表结构完全相同。
- 依据: 分片键(如
user_id,order_id,geo_location)和分片算法。 - 例子: 用户表
user有 10 亿数据。按user_id取模分库(假设分 4 个库):user_db_0:user_id % 4 = 0的数据user_db_1:user_id % 4 = 1的数据user_db_2:user_id % 4 = 2的数据user_db_3:user_id % 4 = 3的数据
- 优点:
- 有效分散单表海量数据存储压力。
- 分散单库读写压力(特别是写压力)。
- 提高系统整体吞吐量和可用性(一个库故障不影响其他库)。
- 缺点:
- 跨库查询极其复杂,需要合并结果(如
SUM,COUNT)。 - 跨库事务处理非常复杂(强一致性需分布式事务,通常最终一致性)。
- 分片键的选择和扩容(增加分片数)策略设计至关重要且复杂。
- 跨库查询极其复杂,需要合并结果(如
-
水平分表
- 概念: 在同一个数据库内,将同一个表的数据,按照某种规则(分片键/分片算法)分散存储到多个结构相同的表中。
- 依据: 分片键和分片算法。
- 例子: 订单表
order在order_db库中,按order_id范围分表:order_2023Q1:order_id在 20230101 - 20230331 之间的订单order_2023Q2:order_id在 20230401 - 20230630 之间的订单- … 以此类推
- 优点:
- 解决单库内单表数据量过大的问题。
- 相比水平分库,跨分片查询和事务处理相对简单(因为还在同一个库内)。
- 缺点:
- 无法分散数据库的 CPU、内存、连接数等资源压力(所有分表还在同一个物理库实例上)。
- 单库的物理资源(磁盘I/O、CPU)可能成为瓶颈。
- 扩容上限受单库物理资源限制。
水平拆分的关键:分片策略
选择合适的分片键和分片算法是水平拆分的核心:
- 分片键 (Sharding Key):
- 选择哪个字段作为数据路由的依据(如
user_id,order_id,shop_id,region_code)。 - 要求: 值分布均匀、业务查询常用(避免全表扫描)、稳定性高(避免频繁修改)。
- 选择哪个字段作为数据路由的依据(如
- 分片算法 (Sharding Algorithm):
- 哈希取模 (Hash Modulo):
- 原理:
shard = sharding_key % shard_num。 - 优点:数据分布相对均匀。
- 缺点:扩容(增加分片数)时,数据迁移量巨大(几乎所有数据都需要重新分布)。分片数最好为 2 的幂方便迁移。
- 原理:
- 范围分片 (Range):
- 原理: 按分片键值的范围划分(如时间范围、ID 范围)。
- 优点:按范围查询效率高(如查某个月订单),扩容方便(只需增加新范围的分片)。
- 缺点:容易产生数据倾斜(热点数据集中在某个范围),旧分片可能成为“冷数据”。
- 一致性哈希 (Consistent Hashing):
- 原理: 构建哈希环,节点和数据都映射到环上,数据顺时针找到的第一个节点即为其存储位置。
- 优点: 扩容/缩容时,仅需迁移环上相邻节点的部分数据,影响范围小。
- 缺点: 实现相对复杂。仍有轻微的数据倾斜可能,可通过虚拟节点缓解。
- 地理位置分片 (Geo Sharding):
- 原理: 根据用户或业务的地理位置信息(如国家、省、市代码)分片。
- 优点: 满足地域性查询和合规要求。
- 缺点: 地域间数据量可能不均。
- 查表法/动态分片 (Lookup Table / Dynamic):
- 原理: 使用独立的元数据表(或配置中心)存储分片键与分片位置的映射关系。
- 优点: 最灵活,分片规则可动态修改,分片键选择不受限(甚至可组合)。
- 缺点: 引入额外组件(元数据存储),增加一次查询开销,元数据存储本身可能成为瓶颈或单点。
- 哈希取模 (Hash Modulo):
三、 常用实现方式
- 应用层分片:
- 在应用程序代码中直接实现分库分表逻辑(路由规则、SQL 改写、结果合并)。
- 优点:灵活度高,无额外依赖。
- 缺点:侵入性强,开发维护成本高,容易出错,难以复用。
- 中间件分片:
- 使用独立的数据库中间件(Proxy 或 JDBC Driver 形式)来透明化分库分表操作。
- Proxy 模式: 应用连接中间件(如 MyCat, ProxySQL, DBLE),中间件伪装成 MySQL 服务器,负责 SQL 解析、路由、改写、结果合并等。应用无感知。
- Client 模式 (JDBC Driver): 应用引入特定 JDBC Driver(如 ShardingSphere-JDBC),Driver 在应用进程内完成 SQL 解析、路由、改写、结果合并等。
- 优点: 对应用透明(尤其是 Proxy),功能强大(支持读写分离、分布式事务等),社区活跃(尤其 ShardingSphere)。
- 缺点: 引入额外组件(Proxy 需部署运维),增加网络开销(Proxy),Client 模式对应用有轻微侵入(Driver)。
选择策略与注意事项
- 优先考虑垂直拆分: 先尝试通过垂直分库分表解决业务耦合和部分性能问题。
- 水平拆分是终极手段: 当单表数据量或单库性能成为瓶颈时再考虑。它带来巨大复杂性和成本。
- 谨慎选择分片键: 这是水平拆分成功的关键。考虑查询模式、数据分布、扩展性。
- 规划好分片策略和扩容方案: 提前考虑未来数据增长和如何平滑扩容(如一致性哈希)。
- 接受跨分片操作的限制: 尽量避免或精心设计需要跨多个分片的复杂查询(JOIN、GROUP BY)和事务。分布式事务性能开销大。
- 工具选择: 强烈推荐使用成熟的中间件(如 Apache ShardingSphere)来简化开发和管理。
- 运维复杂度激增: 监控、备份、恢复、数据迁移、SQL 调优在分库分表环境下变得异常复杂。
- 并非银弹: 分库分表带来性能和扩展性的同时,也牺牲了简易性、一致性(需要额外保障)和开发效率。只有在确实必要时才使用。
总结
| 方式 | 描述 | 优点 | 缺点 | 解决核心问题 |
|---|---|---|---|---|
| 垂直分库 | 按业务模块分到不同库 | 业务解耦,分散连接压力,独立优化 | 不解决单表大问题,跨库事务/查询复杂 | 业务耦合,连接数压力 |
| 垂直分表 | 大表按字段拆分成多个小表(同库) | 减少IO,提升热点访问效率 | 需JOIN,不解决单表行数过多问题 | 单行数据过大,IO效率低 |
| 水平分库 | 同表数据按规则分到多个不同库 | 解决海量数据存储/读写压力,高可用性 | 跨库查询/事务极其复杂,分片键/扩容策略关键 | 单表数据量过大,写压力大 |
| 水平分表 | 同表数据按规则分到多个同库不同表 | 解决单库内单表数据量过大问题 | 无法分散单库资源压力(CPU/内存/IO) | 单库内单表数据量过大 |
核心要点: 垂直拆分侧重业务和解耦,水平拆分(尤其是水平分库)是应对海量数据和高并发的终极手段,但会带来显著的架构复杂度和开发运维挑战。务必在充分评估必要性和成本后再实施水平拆分,并优先考虑使用成熟的中间件(如 ShardingSphere)来降低复杂性。
1842

被折叠的 条评论
为什么被折叠?



