Spring BootとShardingSphereによるMySQL分庫分表の実装

データベース水平分割の必要性

大規模Webアプリケーションでは、データ量増加に伴うデータベース性能問題が顕在化します。単一データベースでは処理限界に達した場合、分庫分表(シャーディング)技術が有効な解決策となります。

分庫分表の基本概念

分庫分表はデータベースを水平分割する手法で、単一データベースを複数の論理単位(データベース/テーブル)に分割します。これにより:

  • クエリ負荷の分散
  • トランザクション処理能力の向上
  • システム拡張性の確保

ShardingSphereの特徴

Apache ShardingSphereは分散データベースソリューションを提供するオープンソースミドルウェアで、以下の機能をサポート:

  • 透過的なデータシャーディング
  • 分散トランザクション管理
  • データマスクング

実装手順

依存関係の追加

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

設定ファイルの構成

spring:
  shardingsphere:
    datasource:
      names: primary_db, replica_db
      primary_db:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://node1:3306/main_db
        username: admin
        password: securepass
      replica_db:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://node2:3306/backup_db
        username: admin
        password: securepass
    sharding:
      tables:
        customer:
          actualDataNodes: primary_db.customer_${0..3}, replica_db.customer_${0..3}
          tableStrategy:
            inline:
              shardingColumn: customer_code
              algorithmExpression: customer_${customer_code % 4}

サービス層実装例

@Service
public class CustomerService {

  @Autowired
  private CustomerRepository repository;

  public void registerCustomer(Customer customer) {
    repository.save(customer);
  }

  public Customer findCustomerByCode(Long code) {
    return repository.findById(code).orElse(null);
  }
}

シャーディング戦略の種類

日付範囲分割

public class DateRangeSharding implements PreciseShardingAlgorithm<LocalDate> {

  @Override
  public String doSharding(Collection<String> targets, 
                          PreciseShardingValue<LocalDate> value) {
    int year = value.getValue().getYear();
    return "transaction_" + year;
  }
}

複合キー分割

public class CompositeSharding implements ComplexKeysShardingAlgorithm<Long> {

  @Override
  public Collection<String> doSharding(Collection<String> targets, 
                                      ComplexKeysShardingValue<Long> value) {
    Set<String> result = new HashSet<>();
    Long orgId = value.getColumnNameAndValuesMap().get("org_id").iterator().next();
    Long userId = value.getColumnNameAndValuesMap().get("user_id").iterator().next();
    
    int shardIndex = (orgId.hashCode() + userId.hashCode()) % 4;
    result.add("data_" + shardIndex);
    
    return result;
  }
}

ヒントベースルーティング

ShardingHint hint = new ShardingHint();
hint.addDatabaseShardingValue("customer", 2);
hint.addTableShardingValue("customer", 2);
ShardingContextHolder.setShardingHint(hint);

Customer customer = customerService.findCustomerByCode(1002L);

ShardingContextHolder.clearShardingHint();

メリットと適用場面

  • 高トラフィックECサイトでの注文処理
  • マルチテナントSaaSアプリケーション
  • 時系列データ分析システム

タグ: SpringBoot ShardingSphere MySQL データベースシャーディング 水平スケーリング

6月23日 18:43 投稿