mysql分库策略
MySQL 分库策略是为了解决单库性能瓶颈(数据量过大、并发过高、I/O压力大)和实现水平扩展的核心手段。它通常与分表策略结合使用(合称分库分表或Sharding),但分库更侧重于将数据分散到不同的数据库实例上。
1. 垂直分库 (Vertical Sharding - By Business Module)
核心思想: 按照业务功能模块或领域将不同的表拆分到不同的数据库实例中。
实现方式:
将与用户相关的表(
user
,user_profile
,user_address
)放到 用户库。将与商品相关的表(
product
,product_category
,product_sku
)放到 商品库。将与订单相关的表(
order
,order_item
,payment
)放到 订单库。将与内容相关的表(
article
,comment
)放到 内容库。优点:
业务解耦清晰: 不同业务模块独立,便于维护和扩展。
降低单库压力: 将负载分散到不同数据库实例。
方便按业务扩展: 可以针对增长快的业务模块单独扩容其对应的数据库资源。
减少跨表Join: 同一业务域内的表通常还在同一个库内,库内Join效率较高。
缺点:
无法解决单表过大问题: 如果某个业务模块内的单张表数据量或访问量极大(如海量订单表),垂直分库本身无能为力,需要进一步结合水平分表/分库。
跨库事务复杂: 涉及多个业务库的事务需要分布式事务解决方案(如XA、TCC、Saga、Seata等),实现复杂且性能有损耗。
跨库查询困难: 需要跨多个库进行关联查询(如查用户信息和其订单)变得非常低效,通常需要在应用层做数据聚合或使用其他存储(如Elasticsearch)。
适用场景: 业务模块相对独立、耦合度低、模块间数据交互较少的大型系统。这是最常用也是优先考虑的拆分方式。
2. 水平分库 (Horizontal Sharding - By Data Row)
核心思想: 将同一张表的数据按照某种规则(分片键/Sharding Key)分散存储到多个结构相同的数据库实例中。每个分片库都包含该表的一部分数据。
关键要素:
分片键 (Sharding Key): 选择用于决定数据行分配到哪个分片的列。常见的有
user_id
,order_id
,shop_id
,region_id
等。选择至关重要,应满足业务高频查询场景。分片算法 (Sharding Algorithm): 根据分片键的值计算目标分片(库、表)的算法。
常用分片算法:
范围分片 (Range Sharding):
按分片键的连续范围划分。例如:
user_id
1-1000万在db1
, 1000万-2000万在db2
。优点: 易于管理,范围查询高效(如果查询条件包含分片键范围)。
缺点: 容易产生数据倾斜(新数据集中写入最新分片,造成热点);扩容时可能需要迁移大量数据。
哈希分片 (Hash Sharding):
对分片键值进行哈希计算(如MD5, CRC32, 一致性哈希),然后根据哈希值取模或其他方式映射到特定分片。例如:
hash(user_id) % 4
决定落在哪个库。优点: 数据分布相对均匀,减少热点问题。
缺点: 扩容困难(增加分片数量时,取模规则改变导致数据需要大规模重新分布/迁移);范围查询效率低(需要查询所有分片)
一致性哈希分片 (Consistent Hashing):
哈希分片的优化版。将分片节点和数据都映射到一个哈希环上。数据根据其哈希值顺时针找到最近的节点。增加或删除节点时,只影响环上相邻小部分数据,大大减少数据迁移量。
优点: 扩容缩容时数据迁移量小。
缺点: 实现相对复杂;仍然存在少量数据迁移。
列表分片 (List Sharding):
根据分片键的枚举值或特定列表映射到分片。例如:按
region_id
(bj
,sh
,gz
,sz
) 分配到不同的地域分库。优点: 规则明确,直接按业务属性划分。
缺点: 灵活性差,新增枚举值或改变映射关系需要修改配置;也可能存在数据不均匀。
复合分片 (Composite Sharding):
结合使用以上多种策略。例如:先按
user_id
范围分库,再在库内按user_id
哈希分表。优点:
解决海量数据存储和访问: 有效分散单库单表的数据量和访问压力。
高性能高并发: 读写负载被分散到多个节点。
高可用性: 一个分片故障不影响其他分片(需要配合高可用方案如主从)。
缺点:
架构复杂: 需要引入分库分表中间件或自研路由逻辑。
跨分片查询复杂: 涉及多个分片的查询(如不带分片键的条件查询、聚合查询、排序分页)非常麻烦且低效,通常需要查询所有分片然后在应用层合并结果。
跨分片事务复杂: 同样需要分布式事务。
扩容复杂度高: 尤其是哈希分片,扩容时数据迁移是痛点。一致性哈希缓解了此问题。
维护成本高: DDL变更(如加索引、改表结构)需要在所有分片上执行。
适用场景: 单表数据量巨大(亿级以上)、并发读写极高、垂直分库后仍无法满足性能需求的场景。如大型电商平台的订单表、用户行为日志表等。
3. 混合分库策略
核心思想: 在实践中,通常先进行垂直分库(按业务拆分),再对垂直分库后的大表进行水平分库(按数据行拆分)。
示例:
垂直分库:拆分成
用户库
、商品库
、订单库
。水平分库:由于
订单库
中的order
表数据量巨大,再对order
表按user_id
进行水平分库(分成order_db0
,order_db1
,order_db2
,order_db3
)。优点: 结合了两种策略的优势,是大型分布式系统最常见的数据库拆分方案。
缺点: 同时具有两种策略的复杂性。
实施分库的需要关注点
分库分表中间件 (Sharding Middleware):
应用透明性:让应用程序像访问单库单表一样访问分库分表后的数据。
核心功能:SQL解析、路由(根据分片键定位目标库表)、结果归并、读写分离支持、分布式事务支持(弱)、分布式主键生成等。
流行方案:
ShardingSphere-JDBC
(Java 客户端层代理, 轻量级, 性能好),ShardingSphere-Proxy
(独立中间件, 支持多语言),MyCat
(老牌中间件),Vitess
(Kubernetes 原生, 云友好)。分布式全局唯一ID生成:
分库后,数据库自增ID不再适用(不同库会产生相同ID)。
常用方案:
Snowflake
算法/UUID(较长, 无序)/Redis
自增/Leaf
(美团)/TinyID
(滴滴)/数据库号段模式。分布式事务:
跨多个库的写操作需要保证原子性。
常用方案:基于XA协议的强一致(性能差)/ 柔性事务(最终一致):
TCC
(Try-Confirm-Cancel),Saga
(补偿事务),本地消息表
,事务消息
(如RocketMQ)。跨分片查询:
应用层聚合:中间件查询所有相关分片,在内存中排序、分页、聚合。效率低,资源消耗大。
使用其他存储:将需要复杂查询的数据同步到适合检索的存储引擎(如
Elasticsearch
)进行查询。基因法:在分片键中融入查询维度的信息(如将
shop_id
融入order_id
),使按店铺查订单的请求能路由到特定分片,避免全扫描。数据迁移与扩容:
在线不停服扩容是巨大挑战。
常用工具:
pt-online-schema-change
(OSC),gh-ost
(GitHub), 中间件自带工具(如ShardingSphere的Scaling)。策略:双写过渡、数据同步、一致性哈希减少迁移量。