5.9. データベースシャーディング

5.9.1. Overview

本ガイドラインでは、AWSを使用したデータベースシャーディングについて説明する。

データ永続層のスケール性の確保データベースシャーディング で説明したシャーディング方式を実現するにあたり、AWS上でシャーディングを実現する場合はシャードにはRDSを、シャードキー管理のための記憶装置にはKVS(Key-Value Store)であるDynamoDBを使用する。また、DynamoDBに格納するシャードキー情報は読み込み頻度が高く、値の更新の機会が少ないため、キャッシュ方式によりアクセスの負荷を低減する。DynamoDBへのアクセスにはSpring Data DynamoDBを使用する。シャードキー情報のキャッシュ化には キャッシュの抽象化(Cache Abstraction) を使用する。

本ガイドラインでは、以下に示すイメージの赤枠破線部分について説明する。

../_images/DatabaseShardingOverview.png
項番 説明
(1)
Controllerが@ShardWithAccount@Transactional付のServiceメソッドを呼び出す。
(2)
Sharding AOPがDynamoDB Repositoryを呼び出しシャードキーを特定する。
(3)
Sharding AOPは、(2)で特定したシャードキーをRouting Data Sourceへ伝播する。
(4)
Transaction AOPは、Transaction Managerを呼び出す。
(5)
Transaction Managerは、Routing Data SourceからConnectionを取得する。
(6)
Transaction Managerは、(5)で取得したConnectionでトランザクションを開始しConnection HolderへConnectionを格納する。
(7)
Serviceは、Shard RepositoryのDBアクセスメソッドを呼び出す。
(8)
Shard Repositoryは、Mybatis Springを経由してDBへクエリを発行する。
(9)
Mybatis Springは、(6)で格納したConnectionをConnection Holderから取得しDBへアクセスする。

5.9.1.1. DynamoDB

DynamoDBについては、 公式サイト を参照されたい。

DynamoDBのガイドについては、 Amazon DynamoDB ドキュメント を参照されたい。

Warning

DynamoDBにトランザクション機能はないため、RDB等との整合性をトランザクション機能により担保することができない点に注意されたい。 また、デフォルトでは結果整合性モデルである点に注意されたい。詳細は 読み込み整合性 を参照されたい。

5.9.2. How to use

AWSを使用する場合、データベースシャーディング で説明したシャードキーの取得の内容は、本ガイドラインで説明する以下の内容となる。

DynamoDBへアクセスするシャードキーリポジトリの設定シャードキーリポジトリの実装について説明する。

Spring Data module for DynamoDBの詳細については、 Spring Data DynamoDB を参照されたい。


5.9.2.1. シャードキーリポジトリの設定

以下に、pom.xmlで依存ライブラリの設定例を示す。

  • xxx-parent/pom.xml
<dependencyManagement>
  <dependencies>
    ・・・
    <!-- == Begin DynamoDB == -->
    <!-- (1) -->
    <dependency>
      <groupId>com.github.derjust</groupId>
      <artifactId>spring-data-dynamodb</artifactId>
      <version>${org.springframework.data.dynamodb-dependencies.version}</version>
    </dependency>
    <!-- == End DynamoDB == -->
  </dependencies>
</dependencyManagement>
<properties>
  ・・・
  <!-- (2) -->
  <org.springframework.data.dynamodb-dependencies.version>4.5.0</org.springframework.data.dynamodb-dependencies.version>
  ・・・
</properties>
項番 説明
(1)

spring-data-dynamodbをバージョン指定で設定する。

子pomでバージョン指定が不要になる。

(2)
spring-data-dynamodbのバージョンを設定する。
  • xxx-domain/pom.xml
・・・
<!-- (1) -->
<dependency>
  <groupId>com.github.derjust</groupId>
  <artifactId>spring-data-dynamodb</artifactId>
</dependency>
・・・
項番 説明
(1)
spring-data-dynamodbを設定する。

以下に、DynamoDBのリージョンとシャードキーリポジトリインタフェースの設定例を示す。

  • xxx-web/src/java/resources/application-local.ymlにDynamoDBのリージョンを設定
cloud:
  aws:
    ・・・
    # (1)
    dynamodb:
      region: ap-northeast-1
項番 説明
(1)
DynamoDBのリージョンを設定する。

  • xxx-domain/src/main/resources/META-INF/spring/xxx-domain.xmlにシャードキーリポジトリインタフェースの設定
<!-- (1) -->
 <bean id="amazonDynamoDB"
   class="com.example.xxx.domain.common.dynamodb.DynamoDBClientFactory" factory-method="create">
   <!-- (2) -->
   <constructor-arg index ="0" value="${cloud.aws.dynamodb.region}" />
 </bean>
<!-- (3) -->
<dynamodb:repositories base-package="com.example.xxx.domain.common.shard.repository"
  amazon-dynamodb-ref="amazonDynamoDB" />
項番 説明
(1)
DynamoDBへアクセスするためのAmazonDynamoDBを定義する。
DynamoDBClientFactoryを使用してインスタンスを生成する。
(2)
DynamoDBリージョンをコンストラクタ引数で設定する。
(3)
シャードキーリポジトリのパッケージをスキャン対象に設定する。

  • DynamoDBClientFactory.java
public class DynamoDBClientFactory {
     public static AmazonDynamoDB create(String region) {
        // (1)
        return AmazonDynamoDBClientBuilder.standard().withRegion(region).build();
    }
}
項番 説明
(1)
AmazonDynamoDBClientBuilderを使用してインスタンスを生成する。

5.9.2.2. シャードキーリポジトリの実装

以下に、DynamoDBのテーブルShardAccountに格納されたデータのイメージを示す。

user_id data_source_key
0000000001
xxx1
0000000002
xxx2
0000000003
xxx3
・・・
・・・

Note

DynamoDBは、AWSアカウントとリージョンの組み合わせの単位でテーブル名がユニークとなっている必要がある。そのため、たとえば開発環境とテスト環境で同一のAWSアカウントとリージョンを使用して、データを排他的に管理したい場合は同名のテーブルを使用することができない。

一方で、@DynamoDBTableに設定するテーブル名を、変数化やプロファイル対応させてプログラマティックに動的に変更することは、DynamoDBのSDKやSpring Data DynamoDBの仕様上難しい。

そのため、同一アプリケーションを複数の排他的な環境で実行したい場合には、AWSアカウントもしくはリージョンを別にすることを推奨する。


DynamoDBへアクセスする為には、テーブルデータに対応したエンティティクラスとシャードキーリポジトリクラスを作成する。 以下に、DynamoDBのエンティティクラスShardingAccountとシャードキーリポジトリクラスAccountShardKeyRepositoryの実装例を示す。

Spring DataのRepositoryの詳細については、Spring Data JPA を参照されたい。

  • エンティティクラスShardingAccount
package com.example.xxx.domain.common.shard.model;

import java.io.Serializable;

import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
// (1)
@DynamoDBTable(tableName = "ShardAccount")
public class ShardingAccount implements Serializable {

  private static final long serialVersionUID = 1L;
  // (2)
  @DynamoDBHashKey(attributeName = "user_id")
  private String userId;
  // (3)
  @DynamoDBAttribute(attributeName = "data_source_key")
  private String dataSourceKey;
  // setter and getter
}
項番 説明
(1)
DynamoDBエンティティとして使用するためのアノテーションDynamoDBTableを付与しテーブル名を設定する。
(2)

ユーザID(ハッシュキー)の項目名を定義する。

アノテーションDynamoDBHashKey

(3)
データソースキーの項目名を定義する。

  • リポジトリクラスAccountShardKeyRepository
package com.example.xxx.domain.common.shard.repository;

import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;

import com.example.xxx.domain.common.shard.model.ShardingAccount;
// (1)
@EnableScan
// (2)
public interface AccountShardKeyRepository extends CrudRepository<ShardingAccount, String> {
  // (3)
  @Override
  @Cacheable(key = "'shardid/' + #a0")
  ShardingAccount findOne(String id);
}
項番 説明
(1)
DynamoDBリポジトリとして使用するためのアノテーションEnableScanを付与する。
(2)
CrudRepositoryのサブインタフェースとして実装する。
(3)

キャッシュの為、メソッドをオーバーライドしている。キャッシュの詳細は、キャッシュの抽象化(Cache Abstraction) を、@Cacheableアノテーションの属性keyで設定している#a0については、キャッシュするデータの選択を参照されたい。

キャッシュが不要な場合は、本メソッドのオーバーライドは不要である。


5.9.2.3. シャードキーリポジトリの使用

シャードキーリポジトリはシャードキーリポジトリの実装で説明したように、CrudRepositoryのサブインタフェースとして実装しCrudRepositoryをそのまま使用するため追加実装は不要である。