データベース水平分割の必要性
大規模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アプリケーション
- 時系列データ分析システム