如何使用分库分表Sharding-JDBC

发布时间:2021-10-21 17:18:21 作者:iii
来源:亿速云 阅读:313
# 如何使用分库分表Sharding-JDBC

## 目录
- [一、分库分表核心概念](#一分库分表核心概念)
  - [1.1 什么是分库分表](#11-什么是分库分表)
  - [1.2 垂直拆分与水平拆分](#12-垂直拆分与水平拆分)
  - [1.3 分库分表适用场景](#13-分库分表适用场景)
- [二、Sharding-JDBC架构解析](#二sharding-jdbc架构解析)
  - [2.1 核心组件与工作原理](#21-核心组件与工作原理)
  - [2.2 与MyCat对比](#22-与mycat对比)
  - [2.3 版本演进与新特性](#23-版本演进与新特性)
- [三、基础环境搭建](#三基础环境搭建)
  - [3.1 依赖配置](#31-依赖配置)
  - [3.2 数据源配置](#32-数据源配置)
  - [3.3 分片规则配置](#33-分片规则配置)
- [四、分片策略详解](#四分片策略详解)
  - [4.1 标准分片策略](#41-标准分片策略)
  - [4.2 复合分片策略](#42-复合分片策略)
  - [4.3 Hint分片策略](#43-hint分片策略)
  - [4.4 不分片策略](#44-不分片策略)
- [五、分布式事务实现](#五分布式事务实现)
  - [5.1 XA事务](#51-xa事务)
  - [5.2 Seata柔性事务](#52-seata柔性事务)
  - [5.3 BASE事务](#53-base事务)
- [六、实战案例](#六实战案例)
  - [6.1 电商订单分库分表](#61-电商订单分库分表)
  - [6.2 多租户SAAS系统](#62-多租户saas系统)
  - [6.3 物联网时序数据](#63-物联网时序数据)
- [七、性能优化](#七性能优化)
  - [7.1 路由优化](#71-路由优化)
  - [7.2 合并执行优化](#72-合并执行优化)
  - [7.3 连接池配置](#73-连接池配置)
- [八、运维监控](#八运维监控)
  - [8.1 指标监控集成](#81-指标监控集成)
  - [8.2 链路追踪](#82-链路追踪)
  - [8.3 慢查询分析](#83-慢查询分析)
- [九、常见问题解决方案](#九常见问题解决方案)
  - [9.1 分布式ID生成](#91-分布式id生成)
  - [9.2 跨库JOIN处理](#92-跨库join处理)
  - [9.3 分布式序列问题](#93-分布式序列问题)
- [十、未来发展趋势](#十未来发展趋势)
  - [10.1 云原生支持](#101-云原生支持)
  - [10.2 多模异构支持](#102-多模异构支持)
  - [10.3 智能化方向](#103-智能化方向)

## 一、分库分表核心概念

### 1.1 什么是分库分表

分库分表是数据库水平扩展的核心技术手段,主要解决单机数据库在数据量增长时出现的性能瓶颈问题。当单表数据量超过500万行或数据库实例QPS超过3000时,就应该考虑分库分表方案。

**技术本质**:通过数据分片(Sharding)将数据集分散到不同的物理节点,使每个节点只处理部分数据,从而提升整体系统的处理能力。

### 1.2 垂直拆分与水平拆分

#### 垂直拆分(Vertical Partitioning)
```sql
-- 原始用户表
CREATE TABLE user (
  id BIGINT,
  username VARCHAR(50),
  password VARCHAR(100),
  profile_json TEXT,
  login_log TEXT
);

-- 拆分后
CREATE TABLE user_basic (
  id BIGINT,
  username VARCHAR(50),
  password VARCHAR(100)
);

CREATE TABLE user_profile (
  user_id BIGINT,
  profile_json TEXT
);

水平拆分(Horizontal Partitioning)

// 按用户ID范围分片
shardingRuleConfig.getTableRuleConfigs().add(
    TableRuleConfiguration.builder("t_order")
        .actualDataNodes("ds${0..1}.t_order_${0..15}")
        .databaseShardingStrategy(
            new StandardShardingStrategyConfiguration("user_id", "dbShardingAlgorithm"))
        .tableShardingStrategy(
            new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm"))
        .build());

1.3 分库分表适用场景

场景类型 典型特征 解决方案
高并发读写 QPS > 5000 分库分散压力
大数据量存储 单表 > 500万行 分表存储
地理分布式访问 跨地域访问延迟高 按地域分库
多租户系统 租户数据隔离需求 按租户ID分库

二、Sharding-JDBC架构解析

2.1 核心组件与工作原理

graph TD
    A[应用代码] --> B[Sharding-JDBC Driver]
    B --> C[SQL解析引擎]
    C --> D[路由引擎]
    D --> E[改写引擎]
    E --> F[执行引擎]
    F --> G[结果归并]
    G --> H[返回结果]

关键组件说明: 1. SQL解析:基于Apache Calcite实现SQL语法树解析 2. 路由引擎:支持精确路由、范围路由、广播路由等多种模式 3. 执行引擎:自动建立多线程执行管道 4. 归并引擎:支持流式归并、内存归并等多种方式

2.2 与MyCat对比

特性 Sharding-JDBC MyCat
架构模式 客户端直连 代理层
性能损耗 % 15%-20%
功能完整性 分片+分布式事务 分片+集群管理
运维复杂度 低(无中间件) 高(需维护代理)
版本迭代 活跃(Apache维护) 社区维护

2.3 版本演进与新特性

5.x版本重大改进: 1. 可插拔架构:支持SPI扩展 2. 分布式事务:XA/SAGA/SEATA全支持 3. 数据加密:列级别透明加密 4. 影子库压测:全链路压测支持

三、基础环境搭建

3.1 依赖配置

Maven核心依赖:

<dependency>
    <groupId>org.apache.shardingsphere</groupId>
    <artifactId>shardingsphere-jdbc-core</artifactId>
    <version>5.3.2</version>
</dependency>
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>4.0.3</version>
</dependency>

Spring Boot自动配置:

spring.shardingsphere.datasource.names=ds0,ds1
spring.shardingsphere.datasource.ds0.type=com.zaxxer.hikari.HikariDataSource
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://localhost:3306/ds0
spring.shardingsphere.datasource.ds0.username=root
spring.shardingsphere.datasource.ds0.password=123456

3.2 数据源配置

YAML格式配置示例:

spring:
  shardingsphere:
    datasource:
      names: ds0,ds1
      ds0:
        type: com.zaxxer.hikari.HikariDataSource
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/ds0
        username: root
        password: 123456
        connection-timeout: 30000
        idle-timeout: 600000
        max-lifetime: 1800000
        maximum-pool-size: 20

3.3 分片规则配置

Java API配置方式:

// 分片算法配置
Properties dbShardingProps = new Properties();
dbShardingProps.setProperty("algorithm-expression", "ds${user_id % 2}");
ShardingSphereAlgorithmConfiguration dbShardingAlgorithm = 
    new ShardingSphereAlgorithmConfiguration("INLINE", dbShardingProps);

// 表规则配置
ShardingTableRuleConfiguration orderTableRule = new ShardingTableRuleConfiguration(
    "t_order", "ds${0..1}.t_order_${0..15}");
orderTableRule.setDatabaseShardingStrategy(
    new StandardShardingStrategyConfiguration("user_id", "dbShardingAlgorithm"));
orderTableRule.setTableShardingStrategy(
    new StandardShardingStrategyConfiguration("order_id", "tableShardingAlgorithm"));

四、分片策略详解

4.1 标准分片策略

精确分片算法实现:

public class OrderDatabaseShardingAlgorithm implements PreciseShardingAlgorithm<Long> {
    @Override
    public String doSharding(Collection<String> availableTargetNames, 
                           PreciseShardingValue<Long> shardingValue) {
        for (String each : availableTargetNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new IllegalArgumentException();
    }
}

范围分片算法示例:

public class OrderRangeShardingAlgorithm implements RangeShardingAlgorithm<Long> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames,
                                       RangeShardingValue<Long> shardingValue) {
        Set<String> result = new LinkedHashSet<>();
        Long lower = shardingValue.getValueRange().lowerEndpoint();
        Long upper = shardingValue.getValueRange().upperEndpoint();
        for (long i = lower; i <= upper; i++) {
            for (String each : availableTargetNames) {
                if (each.endsWith(i % 2 + "")) {
                    result.add(each);
                }
            }
        }
        return result;
    }
}

4.2 复合分片策略

多字段分片配置:

spring:
  shardingsphere:
    sharding:
      tables:
        t_order:
          actual-data-nodes: ds$->{0..1}.t_order_$->{0..15}
          database-strategy:
            complex:
              sharding-columns: user_id,order_date
              algorithm-class-name: com.example.ComplexShardingAlgorithm

复合算法实现:

public class ComplexShardingAlgorithm implements ComplexKeysShardingAlgorithm<Comparable<?>> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames,
                                       ComplexKeysShardingValue<Comparable<?>> shardingValue) {
        Map<String, Collection<Comparable<?>>> columnValues = shardingValue.getColumnNameAndShardingValuesMap();
        Collection<Comparable<?>> userIds = columnValues.get("user_id");
        Collection<Comparable<?>> orderDates = columnValues.get("order_date");
        
        Set<String> result = new HashSet<>();
        // 实现自定义复合分片逻辑
        for (Comparable<?> userId : userIds) {
            for (Comparable<?> orderDate : orderDates) {
                int dbSuffix = (userId.hashCode() & Integer.MAX_VALUE) % 2;
                int tableSuffix = orderDate.hashCode() % 16;
                result.add(String.format("ds%d.t_order_%d", dbSuffix, tableSuffix));
            }
        }
        return result;
    }
}

4.3 Hint分片策略

强制路由配置:

// 设置分片值
HintManager.getInstance().setDatabaseShardingValue(1);

try {
    // 执行SQL(将强制路由到ds1)
    orderRepository.selectAll();
} finally {
    HintManager.clear();
}

Hint算法实现:

public class OrderHintShardingAlgorithm implements HintShardingAlgorithm<Integer> {
    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames,
                                       HintShardingValue<Integer> shardingValue) {
        Collection<String> result = new ArrayList<>();
        for (String each : availableTargetNames) {
            for (Integer value : shardingValue.getValues()) {
                if (each.endsWith(value.toString())) {
                    result.add(each);
                }
            }
        }
        return result;
    }
}

4.4 不分片策略

广播表配置:

spring:
  shardingsphere:
    sharding:
      broadcast-tables: t_config

绑定表配置:

spring:
  shardingsphere:
    sharding:
      binding-tables:
        - t_order,t_order_item

五、分布式事务实现

5.1 XA事务

配置XA事务管理器:

spring:
  shardingsphere:
    props:
      xa-transaction-manager-type: Atomikos

事务使用示例:

@ShardingSphereTransactionType(TransactionType.XA)
@Transactional
public void placeOrder(Order order) {
    // 业务逻辑
}

5.2 Seata柔性事务

Seata集成配置:

spring:
  shardingsphere:
    props:
      seata:
        tx-service-group: my_test_tx_group

AT模式示例:

@ShardingSphereTransactionType(TransactionType.BASE)
@Transactional
public void updateOrder(Order order) {
    // 第一阶段:执行业务SQL并生成undo log
    orderMapper.update(order);
    // 第二阶段:由Seata自动提交/回滚
}

5.3 BASE事务

Saga模式配置:

@ShardingSphereTransactionType(TransactionType.SAGA)
@SagaStart(timeoutSeconds = 300)
public void createOrder(Order order) {
    // 正向操作
    orderService.create(order);
    inventoryService.reduce(order.getItemId(), order.getCount());
    
    // 补偿操作定义
    @Compensate
    public void compensateCreate(Order order) {
        orderService.delete(order.getId());
        inventoryService.increase(order.getItemId(), order.getCount());
    }
}

六、实战案例

6.1 电商订单分库分表

场景特点: - 订单量日均10万+ - 需要按用户维度查询 - 历史订单需要归档

分片方案

spring:
  shardingsphere:
    sharding:
      tables:
        t_order:
          actual-data-nodes: ds$->{0..3}.t_order_$->{0..15}
          database-strategy:
            inline:
              sharding-column: user_id
              algorithm-expression: ds$->{user_id % 4}
          table-strategy:
            standard:
              sharding-column: order_time
              precise-algorithm-class-name: com.example.OrderTimePreciseShardingAlgorithm
              range-algorithm-class-name: com.example.OrderTimeRangeShardingAlgorithm

6.2 多租户SAAS系统

场景特点: - 租户数量超过1000+ - 需要严格数据隔离 - 支持自定义租户分片策略

解决方案

public class TenantShardingAlgorithm implements PreciseShardingAlgorithm<String> {
    @Override
    public String doSharding(Collection<String> availableTargetNames,
                           PreciseShardingValue<String> shardingValue) {
        // 根据租户ID哈希分片
        int hash = Math.abs(shardingValue.getValue().hashCode());
        int index = hash % availableTargetNames.size();
        return new ArrayList<>(availableTargetNames).get(index);
    }
}

6.3 物联网时序数据

特殊需求: - 时间序列数据 - 需要定期自动创建新表 - 支持冷热数据分离

动态分片方案

public class TimeSeriesShardingAlgorithm implements PreciseShardingAlgorithm<Date> {
    private static final DateTimeFormatter TABLE_FORMAT = 
        DateTimeFormatter.ofPattern("yyyy_MM");

    @Override
    public String doSharding(Collection<String> availableTargetNames,
                           PreciseShardingValue<Date> shardingValue) {
        LocalDate date = shardingValue.getValue().toInstant()
            .atZone(ZoneId.systemDefault()).toLocalDate();
        String tableSuffix = date.format(TABLE_FORMAT);
        return availableTargetNames.stream()
            .filter(each -> each.endsWith(tableSuffix))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("No table for date " + date));
    }
}

七、性能优化

7.1 路由优化

最佳实践: 1. 避免全库全表扫描:

-- 错误写法(导致广播路由)
SELECT * FROM t_order WHERE status = 1;

-- 正确写法(带上分片键)
SELECT * FROM t_order WHERE user_id = 123 AND status = 1;
  1. 索引优化建议:
-- 分片键必须包含在索引中
ALTER TABLE t_order ADD INDEX idx_user_status (user_id, status);

7.2 合并执行优化

配置参数调优:

spring:
  shardingsphere:
    props:
      max.connections.size.per.query: 5  # 每个查询最大连接数
      executor.size: 20                  # 执行线程池大小
      kernel.executor.size: 20           # 内核线程池大小

7.3 连接池配置

HikariCP优化建议: “`yaml spring: shardingsphere: datasource: ds0: hikari: maximum-pool-size:

推荐阅读:
  1. SpringBoot 2.0 整合sharding-jdbc中间件,实现数据分库分表
  2. 分库分表中间件sharding-jdbc的使用

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

spring java mysql

上一篇:linux的起源和认识是什么

下一篇:Linux如何安装 MySQL5.7跟权限管理

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》