分表分库

1.分库(Database Sharding)

  • 定义:将数据拆分到多个数据库,每个数据库存储一部分数据
  • 目的:解决单一数据库的存储和性能瓶颈,提供系统的并发能力
  • 示例:

    • 原始数据库:db_users
    • 分库后: db_users_1, db_users_2, db_users_3

2.分表(Table Sharding)

  • 定义:在一个数据库内,将一张大表拆分为多张小表。
  • 目的:减少单表的数据量,挺高查询和写入性能

    • 原始数据库:users
    • 分表后:users_0,users_1,users_2

3.分库分表(Database Sharding, Table Sharding)

  • 定义:结合分表和分库,将数据分布到多个库和表
  • 目的:同时解决数据库和表的性能瓶颈问题。
  • 示例:

    • 原始数据单库单表
    • 分表后:db_users_1.users_0,db_users_2.users_1
分库分表的优点
  1. 性能提升

    • 减少单个数据库或者表的数据量,提升查询,插入,更新的性能
  2. 提升并发能力

    • 将请求分散到不同的库和表中,降低单点的压力,提高整体系统吞吐量
  3. 提高扩展性

    • 数据量增长时可以通过增加库或者表来实现水平扩展,而不是垂直扩展硬件资源
  4. 提升数据存储容量

    • 单个数据库的存储上线(例如2TB)限制可以通过多库分散突破
分库分表的缺点
  1. 复杂性增加

    • 数据路由、分片逻辑和事务处理的复杂度上升。
  2. 跨库查询困难

    • 查询涉及多个库时,需要合并结果集,增加延迟和计算量
  3. 分布式事务

    • 传统数据库的事务特性(ACID)在分布式场景下很难实现,需要引入分布式事务管理工具
  4. 数据迁移复杂

    • 分库分表后如果需要调整分片规则或扩展分片,数据迁移成本高
  5. 运维成本增加

    • 需要管理更多的数据库实例和表,运维复杂度提升
分库分表的常见策略
  1. 范围分片

    • 规则:根据某个字段的值的范围分片
    • 示例:用户ID 1-10000放在db_1, 10001-20000放在db_2
    • 优点:简单直观,方便维护。
    • 缺点:容易出现数据倾斜,导致分片压力过大
  2. 按哈希分片

    • 规则:对分片键(如用户 ID、订单号)进行哈希计算后取模
    • 示例:user_id % 4 分为 4 个分片。
    • 优点:数据分布较均匀,避免热点问题。
    • 缺点:扩容时需要重新计算哈希,导致数据迁移成本高
  3. 按时间分片

    • 规则:根据时间字段(如创建时间)将数据分片
    • 示例:2024 年数据放在 db_2024,2025 年数据放在 db_2025
    • 优点:适合时间序列数据,历史数据方便归档
    • 缺点:可能导致部分分片(最新数据)压力较大
  4. 按地理位置分片
分库分表的实现方式
  1. 数据库中间件
  • 说明:通过数据库中间件(如 ShardingSphere、MyCAT)实现分库分表。
  • 特点:

    • 对应用透明,不需要修改业务代码。
    • 支持跨库查询、分布式事务等功能。
  • 缺点:增加系统复杂性,可能引入性能瓶颈。
  1. 应用层控制
  2. 说明:在应用程序中自行实现分库分表逻辑。
  3. 特点:

    • 灵活性高,可根据业务需求定制。
    • 无额外中间件依赖。
  4. 缺点:开发工作量大,运维复杂。
  5. 云原生数据库
  6. 说明:使用云厂商提供的分布式数据库(如 TiDB、Amazon Aurora)。
  7. 特点:

    • 内置分库分表能力
    • 易于维护
  8. 缺点:成本较高,对云服务依赖强。
分库分表导致主键冲突
  1. 自增主键导致冲突:

    • 在多个数据库或表中使用自增主键时,由于各分片独立维护自己的自增计数器,同样的主键值可能在多个分片中生成,从而导致冲突
  2. 分布式 ID 生成规则设计不当:

    • 自行设计的 ID 生成策略(如时间戳拼接、随机数等)未能确保分片间的唯一性,导致冲突
  3. 不使用分片键生成 ID:

    • 数据分片时主键生成逻辑未与分片键关联,导致不同分片中出现相同的主键。
  4. 主键范围未分区

    • 分片时没有为主键分配独立的范围,导致不同分片中的主键值相同
如何解决主键冲突
  1. 使用全局唯一ID:通过分布式 ID 生成器来确保每个分片生成的主键全局唯一
  2. 常见方案:

    • 雪花算法:

      • 基于时间戳 + 数据中心ID + 机器ID + 自增序列
      • 生成的 ID 是全局唯一且趋势递增的 64 位整数
    • UUID(通用唯一标识符)

      • 生成 128 位的唯一字符串
      • 缺点是长度较长,查询效率低
    • 数据库中间件(如 ShardingSphere):

      • 提供全局主键生成服务
  3. 适用场景:

    • 分布式系统中需要全局唯一主键的场景。
  4. 为主键分配分片标识
  • 常见方案:

    • 分片 ID + 自增序列:

      • 主键格式为 [shard_id][local_id],例如:
      • 分片 A:1_00001, 1_00002...
      • 分片 B:2_00001, 2_00002...
    • 范围分配:

      • 不同分片分配不同的主键范围:

        • 分片 A 的主键范围是 1~1亿。
        • 分片 B 的主键范围是 1亿+1~2亿。
  • 优点:

    • 简单易实现,无需复杂逻辑。
  • 缺点:

    • 主键设计不够灵活,范围用尽需要重新分配。
  1. 基于分片键生成主键
  2. 方法:

    • 主键的生成规则与分片键绑定,确保分片键和主键的对应关系。
  3. 举例:

    • 如果分片键为 user_id,主键可以为 hash(user_id) + 时间戳。
  4. 逻辑主键与物理主键分离
  5. 方法:

    • 在数据库表中使用逻辑主键(如订单号、业务 ID),物理主键使用内部自增 ID。
  6. 优点:

    • 业务层逻辑主键具有全局唯一性,物理主键的冲突只在表内部处理。
使用Sharding JDBC实现分库分表

使用 ShardingSphere-JDBC 实现分库分表是一种高效且灵活的方式。ShardingSphere 是一个开源的分布式数据库中间件,其中 ShardingSphere-JDBC 通过代理数据库操作,在应用层实现透明的分库分表功能。以下是实现的详细步骤和关键点。


爱跑步的猕猴桃
1 声望0 粉丝