DBのデータ量が増えてきた場合の対策の1つとしてユーザIDなどをキーにデータベースを分割するシャーディングと呼ばれる手法があります。これをJDBCのレイヤで実現してしまうsharding-jdbcというライブラリを見つけました。
github.com
sharding-jdbcは中国のdangdang(当当)というEC大手企業が開発したOSSで、SQLをパースし、SQLに含まれるシャードキーを抽出して接続先のデータベースや、参照するテーブルを切り替えてくれるというものです。
使ってみる
まずはpom.xmlに以下の依存関係を追加します。
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>1.4.1</version>
</dependency>
今回は簡単な例ということで、COMPANY_ID
というカラムをシャードキーに接続するデータベースを切り替えてみます。以下のような感じでデータソースを準備します。
Map<String, DataSource> dataSources = new HashMap<>();
dataSources.put("ds_0", createDataSource(...));
dataSources.put("ds_1", createDataSource(...));
DataSourceRule dataSourceRule = new DataSourceRule(dataSources);
TableRule companyTableRule = TableRule.builder("COMPANY")
.dataSourceRule(dataSourceRule)
.build();
ShardingRule shardingRule = ShardingRule.builder()
.dataSourceRule(dataSourceRule)
.tableRules(Arrays.asList(companyTableRule, deptTableRule))
.databaseShardingStrategy(new DatabaseShardingStrategy("COMPANY_ID", new CompanyIdShardingAlgorithm()))
.build();
DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
CompanyIdShardingAlgorithm
が接続先データベースを決定するクラスになります。シャードキーに使用するカラムは=
、BETWEEN
、IN
での検索しか行うことができません。ShardingAlgorithmではこれらの検索方法に対応したメソッドを実装する必要があるのですが、今回は=
での検索しか行わないのでdoEqualSharding()
メソッドのみ実装しています。
public class CompanyIdShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<String> {
@Override
public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<String> shardingValue) {
switch(shardingValue.getValue()){
case "bizreach":
return "ds_0";
default:
return "ds_1";
}
}
@Override
public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<String> shardingValue) {
throw new UnsupportedOperationException();
}
@Override
public Collection<String> doBetweenSharding(Collection<String> availableTargetNames, ShardingValue<String> shardingValue) {
throw new UnsupportedOperationException();
}
}
あとは作成したデータソースからgetConnection()
メソッドを取得してSQLを実行すればシャードキーに応じたDBに対してSQLが発行されます。
その他の機能
sharding-jdbcにはこの他にも以下のような機能があります。
- シャードキーで、接続するデータベースではなく参照するテーブルを切り替える機能(SQLがリライトされて実行されます)
- 一意なIDを発行する機能(シャードをまたぐ自動採番のカラムに値を入れるのに使用します)
- クエリが複数のシャードにまたがる場合に
ORDER BY
やGROUP BY
を処理する機能(マージ処理と呼ぶようです)
一方で前述の通りシャードキーに対する検索条件に制限がある、異なるシャードをUNION
できないなどの制約もあります。正常にルーティングが行われないSQLの場合でも特にエラーにはならず、SQL中で最初に検出されたシャードキーを使ってルーティングされているように見えましたが、できればエラーになってくれると嬉しいですね。
まとめ
sharding-jdbcはJDBCのレイヤでシャーディングを解決してくれるため、既存の様々なORMやデータベースアクセスライブラリをそのまま利用できるという大きなメリットがあります。利用可能なSQLに制限はあるものの、そもそもシャードキーに対してリッチな検索を行う必要はないでしょうし、複雑なレポーティングが必要といったケースでなければさほど困ることもなさそうです。
現時点でシャーディングが不要だとしても、将来的にデータの増加に伴ってDBのシャーディングを検討する可能性があるようであれば、最初からこれを入れておくという手も考えられるのではないでしょうか。