ShardingJDBC

ShardingJDBC分库分表实战:原理、配置与最佳实践

一、分库分表背景与挑战

随着业务规模的指数级增长,单数据库实例在存储容量、并发处理能力和运维复杂度等方面逐渐显现瓶颈。传统单体数据库架构面临三大核心挑战:

  1. 性能瓶颈:单表数据量突破千万级时,查询性能呈断崖式下降
  2. 可用性风险:单一故障点导致全站服务不可用
  3. 运维复杂度:数据迁移、索引维护等操作窗口期越来越短

ShardingJDBC作为Apache ShardingSphere的核心组件,通过客户端直连的轻量级方案,提供透明化的数据库水平扩展能力。

二、ShardingJDBC核心架构

2.1 架构分层

graph TD
    A[应用层] --> B[ShardingJDBC]
    B --> C[逻辑表]
    C --> D[物理数据源1]
    C --> E[物理数据源2]
    D --> F[实际表_0]
    D --> G[实际表_1]
    E --> H[实际表_0]
    E --> I[实际表_1]

2.2 核心概念

  • 逻辑表:应用程序视角的统一表名(如t_order)
  • 真实表:物理数据库中的实际表(如ds0.t_order_0)
  • 数据节点:由数据源与真实表组成的定位单元(ds0.t_order_0)
  • 分片键:决定数据路由的关键字段(如order_id)
  • 分片算法:包含精确分片、范围分片等策略

三、Spring Boot集成实战

3.1 Maven依赖配置

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
    <version>5.3.2</version>
</dependency>

3.2 分库分表策略配置

# https://shardingsphere.apache.org/index_zh.html
mode:
  # 运行模式类型。可选配置:内存模式 Memory、单机模式 Standalone、集群模式 Cluster - 目前为单机模式
  type: Standalone

dataSources:
  ds_0:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://192.168.10.130:13306/sharding_db_00?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 15
    minPoolSize: 5

  ds_1:
    dataSourceClassName: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://192.168.10.130:13306/sharding_db_01?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 15
    minPoolSize: 5

rules:
  - !SHARDING
    # 声明这是一个分片(分库分表)规则配置

    # 库的路由
    defaultDatabaseStrategy:
      # 定义默认的数据库分片策略
      standard:
        # 使用标准分片策略,该策略适用于单分片键的场景
        shardingColumn: user_id
        # 指定分片键为 user_id,即根据 user_id 的值来决定数据存储在哪个数据库中
        shardingAlgorithmName: database_inline
        # 指定使用的分片算法名称为 database_inline

    # 表的路由
    tables:
      # 配置具体表的分片规则
      user_order:
        # 配置 user_order 表的分片规则
        actualDataNodes: ds_->{0..1}.user_order_->{0..3}
        # 定义实际的数据节点,这里表示数据会存储在 ds_0 和 ds_1 两个数据库中,
        # 每个数据库中又有 user_order_0 到 user_order_3 共 4 个表
        tableStrategy:
          # 定义该表的分片策略
          standard:
            # 使用标准分片策略,同样适用于单分片键的场景
            shardingColumn: user_id
            # 指定分片键为 user_id,即根据 user_id 的值来决定数据存储在哪个表中
            shardingAlgorithmName: user_order_inline
            # 指定使用的分片算法名称为 user_order_inline

    # 路由算法
    shardingAlgorithms:
      # 定义具体的分片算法
      # 库-路由算法 2是两个库,库的数量。库的数量用哈希模2来计算。
      database_inline:
        # 定义名为 database_inline 的分片算法
        type: INLINE
        # 指定算法类型为 INLINE,INLINE 类型的算法可以使用表达式来计算分片结果
        props:
          algorithm-expression: ds_->{Math.abs(user_id.hashCode()) % 2}
          # 定义算法表达式,通过计算 user_id 的哈希值的绝对值并对 2 取模,
          # 得到的结果决定数据存储在 ds_0 还是 ds_1 数据库中

      # 表-路由算法 4是一个库里,表的数量。4 - 1 为了获得 011 这样的二进制值。不推荐 user_order_->{Math.abs(user_id.hashCode()) % 2} 作为表的路由
      user_order_inline:
        # 定义名为 user_order_inline 的分片算法
        type: INLINE
        # 指定算法类型为 INLINE
        props:
          algorithm-expression: user_order_$->{(user_id.hashCode() ^ (user_id.hashCode()) >>> 16) & (4 - 1)}
          # 定义算法表达式,通过对 user_id 的哈希值进行一系列位运算(异或和右移),
          # 并与 3(4 - 1)进行按位与运算,得到的结果决定数据存储在 user_order_0 到 user_order_3 中的哪个表中

props:
  # 是否在日志中打印 SQL。
  # 打印 SQL 可以帮助开发者快速定位系统问题。日志内容包含:逻辑 SQL,真实 SQL 和 SQL 解析结果。
  # 如果开启配置,日志将使用 Topic ShardingSphere-SQL,日志级别是 INFO。 false
  sql-show: true
  # 是否在日志中打印简单风格的 SQL。false
  sql-simple: true
  # 用于设置任务处理线程池的大小。每个 ShardingSphereDataSource 使用一个独立的线程池,同一个 JVM 的不同数据源不共享线程池。
  executor-size: 20
  # 查询请求在每个数据库实例中所能使用的最大连接数。1
  max-connections-size-per-query: 1
  # 在程序启动和更新时,是否检查分片元数据的结构一致性。
  check-table-metadata-enabled: false
  # 在程序启动和更新时,是否检查重复表。false
  check-duplicate-table-enabled: false

四、最佳实践与注意事项

4.1 分片键选择原则

  1. 选择高基数列(如用户ID、订单号)
  2. 避免选择频繁更新的字段
  3. 优先选择业务查询中的必现条件

4.2 常见问题解决方案

分布式ID生成:

// 雪花算法配置
spring.shardingsphere.rules.sharding.key-generators:
  snowflake:
    type: SNOWFLAKE
    props:
      worker-id: 123

跨库关联查询:

  • 全局表:小规模维度表全库冗余
  • 绑定表:确保关联表分片策略一致
    spring.shardingsphere.rules.sharding.binding-tables:
    - t_order,t_order_item

4.3 性能优化建议

  1. 合理设置分片数量(建议单表不超过5000万行)
  2. 避免全路由查询(如不带分片键的查询)
  3. 使用Hint强制路由处理特殊场景
    try (HintManager hintManager = HintManager.getInstance()) {
    hintManager.addDatabaseShardingValue("t_order", 1);
    hintManager.addTableShardingValue("t_order", 2);
    // 执行查询
    }

五、监控与扩展

  1. 集成Prometheus监控指标

    spring.shardingsphere.metrics:
    enabled: true
    name: prometheus
    host: 127.0.0.1
    port: 9090
  2. 使用ShardingSphere-UI进行可视化管控

  3. 弹性扩展方案:

    • 双写迁移:新旧分片策略并行写入
    • 历史数据归档:冷热数据分离存储

六、总结

ShardingJDBC通过以下核心优势成为分库分表首选方案:

  1. 无侵入性:无需修改业务代码即可实现分片功能
  2. 灵活扩展:支持动态数据源、在线规则修改
  3. 生态完善:提供分布式事务、数据加密等企业级功能

当面临以下场景时建议采用分库分表方案:

  • 单表数据量预计超过5000万行
  • 数据库QPS超过5000
  • 需要多地多活部署架构

附录:分片算法性能对比表

算法类型 适用场景 扩容复杂度 查询性能
取模分片 数据均匀分布
范围分片 时间序列数据
哈希分片 随机分布需求
自定义复合分片 复杂业务规则
博客内容均系原创,未经允许严禁转载!
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇