28 データベース・シャーディングのJDBCによるサポート
この項では、データベース・シャーディング機能に対するOracle JDBCのサポートについて説明します。
28.1 JDBCユーザー用のデータベース・シャーディングの概要
現在、Webアプリケーションには大量のデータのスケーラビリティに関する新しい課題があります。この問題に共通して受け入れられているソリューションはシャーディングです。シャーディングは、独立したデータベース間でデータが水平にパーティション化されるデータ階層アーキテクチャです。このような構成内の各データベースをシャードと呼びます。すべてのシャードが集まったものが単一の論理データベースで、これをシャード・データベース(SDB)と呼びます。シャードはCPU、メモリー、記憶域デバイスなどの物理リソースを共有しないため、シャーディングは何も共有しないデータベース・アーキテクチャです。
シャーディングはグローバル・データ・サービス(GDS)を使用します。GDSは可用性、負荷、ネットワーク待機時間およびレプリケーション・ラグに基づいて、クライアント・リクエストを適切なデータベースにルーティングします。GDSプールは、レプリケートされたデータベースのセットであり、同じグローバル・サービスを提供します。GDSプールのデータベースは、異なるリージョンにある複数のデータ・センターに配置できます。シャードされたGDSプールにはシャードされたデータベースのすべてのシャードおよびそのレプリカが含まれ、データベース・クライアントには単一のシャードされたデータベースのように見えます。
Oracle Database 12cリリース2 (12.2.0.1)以降、Oracle JDBCではデータベース・シャーディングがサポートされています。JDBCドライバは指定されたシャーディング・キーおよびスーパー・シャーディング・キーを認識し、データが含まれている該当シャードに接続します。シャードに対する接続が確立されると、DML、SQL問合せなどのサポートされているデータベース操作は通常どおりに実行されます。次の項では、このガイドで使用されるシャーディングの用語について説明します。
関連項目:
シャーディング、シャードおよびシャードされたデータベース
シャーディングは、独立したデータベース間でデータが水平にパーティション化されるデータ階層アーキテクチャです。このような構成の各データベースはシャードと呼ばれます。すべてのシャードが集まったものが単一の論理データベースで、これをシャード・データベース(SDB)と呼びます。
シャーディング・キー、複合シャーディング・キーおよびスーパー・シャーディング・キー
シャーディング・キーは、範囲、リストまたは一貫性のあるハッシュによって単一レベルのシャーディングで使用されるパーティション化キーです。すべてのシャーディング・キーは、あわせて複合シャーディング・キーと呼ばれます。スーパー・シャーディング・キーは、範囲またはリストによって最上位レベルのシャーディングの複合シャーディングで使用されるパーティション化キーです。シャーディング・キーとスーパー・シャーディング・キーの両方は、各行が格納されるシャードを決定する1つ以上の列を含めることができます。シャーディング・キーは、VARCHAR2、CHAR、DATE、NUMBER、TIMESTAMP型などにすることができます。
JDBCユーザーの場合、データベースから接続を取得したときにシャーディング・キーおよびスーパー・シャーディング・キーを渡すことをお薦めします。ただし、シャーディング・キーは接続文字列でCONNECT_DATA
の別の属性として指定できます。シャーディング・キーを接続文字列で渡すと、1つのシャードのみへの接続に制限されます。したがって、この方法の使用はお薦めしません。次のコードでは、シャーディング・キーを接続文字列でCONNECT_DATA
の別の属性として指定する方法を示します。
(DESCRIPTION=(…)(CONNECT_DATA=(SERVICE_NAME=ORCL (SHARDING_KEY=…) (SUPER_SHARDING_KEY=...)))
ノート:
データベースで指定されているNLS書式に準拠したシャーディング・キーを指定する必要があります。
複数のシャード問合せ
複数のシャード問合せにより、複数のシャードに格納されたデータにアクセスする問合せとトランザクションをルーティングおよび処理できます。複数のシャード問合せはシャーディング・キーを指定しないで実行されます。複数のシャード操作は、データの単純な集計およびシャード間のレポート作成時に使用されます。
シャード・カタログ
シャード・カタログは、シャードされたデータベースの格納および複数のシャード問合せのサポートに使用される特殊なデータベースです。これは、シャードされたデータベースの集中管理にも役立ちます。
シャード・ディレクタ
シャード・ディレクタは、グローバル・サービス・マネージャ(GSM)の特定の実装であり、SDBに接続するクライアント用のリージョン・リスナーとして機能し、SDBの現在のトポロジ・マップを維持します。ディレクタは、接続リクエストで渡されたシャーディング・キーに基づいて、接続を適切なシャードにルーティングします。
シャード・トポロジ
シャード・トポロジは、特定のシャードに格納されたシャーディング・キーの範囲マッピングです。ユニバーサル接続プール(UCP)はシャード・トポロジをキャッシュできます。これにより、シャードへの接続の確立時にシャード・ディレクタをバイパスできるようになります。したがって、UCPを使用して作成するアプリケーションは、シャードへのファスト・パスが得られます。
チャンク
チャンクは表ファミリの各表の単一パーティションです。これは、シャード間のデータ移行の単位です。
チャンクの分割
チャンクの分割は、チャンクが大きくなりすぎた場合や、チャンクの一部のみを別のシャードに移行する必要がある場合に必要となるプロセスです。
チャンクの移行
チャンクの移行は、データまたはワークロードのスキューが発生したときに、シャード数を変更せずに、チャンクを1つのシャードから他のシャードへ移動するプロセスです。これは、ホット・スポットを回避するために、DBAで開始されます。
再シャーディング
再シャーディングは、データがシャード間に再分散されるプロセスで、シャード数の変化によってトリガーされます。チャンクは、シャード間でチャンクを均等に分散させるためにシャード間で移動します。ただし、チャンクの内容は変化しません。つまり、再シャーディング時に再ハッシュは行われません。
28.2 シャーディング・キーの作成について
シャード認識アプリケーションは、シャードされたデータベースへの接続の確立に必要なシャーディング・キーおよびスーパー・シャーディング・キーを識別して作成する必要があります。これを実行するには、シャード認識アプリケーションでOracleShardingKey
およびOracleShardingKeyBuilder
インタフェースを使用する必要があります。
OracleShardingKeyBuilder
は、データ型が異なる複合キーをサポートするために次のビルダー・メソッドを使用します。
subkey(Object subkey, java.sql.SQLTYPE subkeyDataType)
各サブキーのデータ型が異なる可能性がある複合シャーディング・キーを作成するには、ビルダーでsubkey
メソッドを複数回起動します。データ型は、oracle.jdbc.OracleType
列挙またはjava.sql.JDBCType
を使用して定義できます。
例28-1 シャーディング・キーの作成
次の例は、シャーディング・キーの作成方法を示します。
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Statement;
import oracle.jdbc.OracleShardingKey;
import oracle.jdbc.OracleType;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;
public class ShardExample
{
public static void main(String[] args) throws SQLException
{
String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(HOST=myhost)(PORT=3216)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=myservice)(REGION=east)))";
String user="testuser1";
String pwd = "password";
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setURL(url);
pds.setUser(user);
pds.setPassword(pwd);
pds.setConnectionFactoryClassName("oracle.jdbc.pool.OracleDataSource");
pds.setInitialPoolSize(5);
pds.setMinPoolSize(5);
pds.setMaxPoolSize(20);
// build the sharding key object
Date shardingKeyVal = new java.sql.Date(0L);
OracleShardingKey sdkey = pds.createShardingKeyBuilder()
.subkey(shardingKeyVal, OracleType.DATE)
.build();
Connection conn = pds.createConnectionBuilder()
.shardingKey(sdkey)
.build();
Statement stmt = conn.createStatement();
stmt.execute("... SQL statement here ...");
stmt.close();
conn.close();
}
}
次のコードでは、Stringデータ型とDateデータ型で構成される複合シャーディングの作成方法を示します。
...
Date shardingKeyVal = new java.sql.Date(0L);
...
OracleShardingKey shardingKey = datasource.createShardingKeyBuilder()
.subkey("abc@xyz.com", JDBCType.VARCHAR)
.subkey(shardingKeyVal, OracleType.DATE)
.build();
...
ノート:
-
有効でサポートされているデータ型の固定のセットがあります。サポートされていないデータ型をキーとして使用すると、例外が発生します。次のリストに、サポートされているデータ型を示します。
-
OracleType.VARCHAR2/JDBCType.VARCHAR
-
OracleType.CHAR/JDBCType.CHAR
-
OracleType.NVARCHAR/JDBCType.NVARCHAR
-
OracleType.NCHAR/JDBCType.NCHAR
-
OracleType.NUMBER/JDBCType.NUMERIC
-
OracleType.FLOAT/ JDBCType.FLOAT
-
OracleType.DATE/ JDBCType.DATE
-
OracleType.TIMESTAMP/JDBCType.TIMESTAMP
-
OracleType.TIMESTAMP_WITH_LOCAL_TIME_ZONE
-
OracleType.RAW
-
-
データベースで指定されているNLS書式に準拠したシャーディング・キーを指定する必要があります。
28.3 データベース・シャーディングのサポート用API
Oracle Database 12cリリース2 (12.2.0.1)では、データベース・シャーディングを実装するための一連のAPIが導入されました。次の各項では、これらのAPIについて詳細に説明します。
28.3.1 OracleShardingKeyインタフェース
このインタフェースは、現在のオブジェクトがOracleのシャードされたデータベースで使用されるOracleシャーディング・キーを表していることを示します。
構文
public interface OracleShardingKey extends Comparable <OracleShardingKey>
28.3.2 OracleShardingKeyBuilderインタフェース
OracleShardingKeyBuilder
では、サポートされている様々なデータ型のサブキーを持つ複合シャーディング・キーを作成するためのインタフェースを提供します。このインタフェースでは、新しいJDK 8ビルダー・パターンを使用してシャーディング・キーを作成します。
構文
public interface OracleShardingKeyBuilder
例28-2 シャーディング・キーの作成
OracleDataSource ods = new OracleDataSource();
...
//set datasource properties..
...
OracleShardingKey shardingKey = ods.createShardingKeyBuilder()
.subkey("Customer_Name_XYZ", JDBCType.VARCHAR)
.subkey(94002, JDBCType.NUMERIC)
.build();
28.3.3 OracleConnectionBuilderインタフェース
OracleConnectionBuilder
をユーザー名およびパスワード以外に追加パラメータともに使用して、接続オブジェクトを作成します。接続を作成するには、接続リクエストに含まれている必要があるパラメータごとにビルダー・メソッドをコールし、その後build()
メソッドをコールする必要があります。ビルダー・メソッドをコールする順序は重要ではありません。ただし、同じビルダー属性を複数回適用する場合、最新の値のみが接続の作成時に考慮されます。ビルダーのbuild()
メソッドをコールできるのは、ビルダー・オブジェクトで1回のみです。
構文
public interface OracleConnectionBuilder
例28-3 接続ビルダーの作成
...
OracleDataSource ods=new OracleDataSource();
...
OracleConnection conn = ods.createConnectionBuilder()
.shardingKey(shardingKey)
.superShardingKey(superShardingKey)
.build();
28.3.4 データベース・シャーディングのサポートのための他の新規クラスおよびメソッド
この項では、データベース・シャーディングのサポートの実装で導入されたその他の新規クラスおよびメソッドについて説明します。
OracleDataSourceクラスの新規メソッド
createConnectionBuilder
およびcreateShardingKeyBulider
メソッドが、データベース・シャーディングのサポート用にOracleDataSource
クラスに導入されました。
OracleConnectionBuilder createConnectionBuilder() throws SQLException;
OracleShardingKeyBuilder createShardingKeyBuilder()
OracleXADataSourceクラスの新規メソッド
createConnectionBuilder
メソッドが、データベース・シャーディングのサポート用にOracleXADataSource
クラスに導入されました。
OracleConnectionBuilder createConnectionBuilder() throws SQLException;
OracleConnectionクラスの新規メソッド
setShardingKeyIfValid
およびsetShardingKey
メソッドが、データベース・シャーディングのサポート用にOracleConnection
クラスに導入されました。
boolean setShardingKeyIfValid(OracleShardingKey shardingKey, OracleShardingKey superShardingKey, int timeout) throws SQLException;
void setShardingKey(OracleShardingKey shardingKey, OracleShardingKey superShardingKey) throws SQLException;
OracleXAConnectionクラスの新規メソッド
setShardingKeyIfValid
およびsetShardingKey
メソッドが、データベース・シャーディングのサポート用にOracleConnection
クラスに導入されました。
boolean setShardingKeyIfValid(OracleShardingKey shardingKey, OracleShardingKey superShardingKey, int timeout) throws SQLException;
void setShardingKey(OracleShardingKey shardingKey, OracleShardingKey superShardingKey) throws SQLException;
28.4 JDBCシャーディングの例
次のコードでは、JDBCシャーディングAPIの使用方法を示します。
例28-4 JDBCシャーディングの例
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(HOST=myhost)(PORT=1521)(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=myorcldbservicename)))");
ods.setUser("hr");
ods.setPassword("hr");
// Employee name is the sharding Key in this example.
// Build the Sharding Key using employee name as shown below.
OracleShardingKey employeeNameShardKey = ods.createShardingKeyBuilder()
.subkey("Mary", JDBCType.VARCHAR)// First Name
.subkey("Claire", JDBCType.VARCHAR)// Last Name
.build();
OracleShardingKey locationSuperShardKey = ods.createShardingKeyBuilder() // Building a super sharding key using location as the key
.subkey("US", JDBCType.VARCHAR)
.build();
OracleConnection connection = ods.createConnectionBuilder()
.shardingKey(employeeNameShardKey)
.superShardingKey(locationSuperShardKey)
.build();
28.5 シャーディング・データソースの概要
Oracle Databaseリリース21c以降では、JDBCデータ・ソースで、シャーディング・キーを提供する必要なく、シャードされたデータベースへのJava接続を確立できます。そのため、接続を確立するためにシャーディング・キーおよびスーパー・シャーディング・キーを識別して作成する必要はありません。
新しいシャーディング・データソースは、アプリケーション・コードに対する変更を伴わないため、シャードされたデータベースに透過的にスケール・アウトされます。シャーディング・キーをSQLまたはPL/SQLから導出できる場合、JDBCドライバは、アプリケーションがシャーディング・キーを送信しなくてもキーを識別できます。このデータソースを使用するには、次のように接続プロパティoracle.jdbc.useShardingDriverConnection
をtrue
に設定する必要があります。
Properties prop = new Properties();
prop.setProperty("oracle.jdbc.useShardingDriverConnection", "true");
この接続プロパティのデフォルト値はfalse
です。
28.5.1 シャーディング・データソースの利点
新しいシャーディング・データソースの利点は、次のとおりです。
- シャーディングAPIを使用してシャーディング・キーを渡す必要はありません。シャーディング・データソースはSQL文からシャーディング・キーを導出するためです。
- ユニバーサル接続プール(UCP)を構成する必要はありません。シャーディング・データソースがUCPの自動チューニング機能を使用するためです。
- 新しいシャーディング・キーごとに物理接続をチェックインまたはチェックアウトする必要はありません。シャーディング・データソースが自動的に実行するためです。
- クロスシャード文を単一のシャード文から分離して、それらの接続プールを個別に作成する必要はありません。シャーディング・データソースがこれらの接続プールを維持するためです。
- シャーディング・データソースにより、プリペアド文のキャッシュが可能になり、SQL文で使用されたキーに基づいてダイレクト・シャードに接続がルーティングされます。
- シャーディング・データソースにより、アプリケーションが簡素化され、コードを変更することなくアプリケーションのパフォーマンスが最適化されます。
28.5.2 例: シャーディング・データソースの使用方法
次の例は、シャーディング・データソースを使用する方法を示しています。
例28-5 シャーディング・データソースの使用
public class ShardingDriverSample {
public static void main(String[] args) throws SQLException {
ShardingDriverSample sample = new ShardingDriverSample();
sample.bindQuerySample();
}
private void bindQuerySample() throws SQLException {
OracleConnection conn = getGsmConnection();
executeQueryWithBindAndReadRows(conn, "SELECT * FROM MY_SHARD_TABLE where ID = ?", 10);
System.out.println("Direct shard execution percentage:" + conn.getPercentageQueryExecutionOnDirectShard());
}
private OracleConnection getGsmConnection() throws SQLException {
OracleDataSource ds = new OracleDataSource();
ds.setURL(gsmURL);
Properties prop = new Properties();
prop.setProperty("user", <userName>);
prop.setProperty("password", <password>);
// this property enables sharding datasource feature
prop.setProperty("oracle.jdbc.useShardingDriverConnection", "true");
ds.setConnectionProperties(prop);
return ds.getConnection();
}
private void executeQueryWithBindAndReadRows(Connection dbConnection, String sql, int noOfTime)
throws SQLException {
while (noOfTime-- > 0) {
PreparedStatement statement = dbConnection.prepareStatement(sql);
statement.setInt(1, 15);
ResultSet rs = statement.executeQuery();
...
}
}
}
28.5.3 シャーディング・データソースの制限
この項では、シャーディング・データソースの制限について説明します。
- シャーディング・データソースは、JDBC Thinドライバのみをサポートしています。JDBC OCIドライバまたはKPRBドライバはサポートしていません。
- シャーディング・データソースは、ダイレクト・パス・ロード、JDBC Dynamic Monitoring Service (DMS)メトリックなどの一部のOracle JDBC拡張APIをサポートしていません。
- シャーディング・データソースは、カタログ・データベースを介してのみPL/SQL実行をサポートしています。
AUTO COMMIT
がOFF
に設定されている場合、実行は常にカタログ・データベースで行われます。- データソース・プロパティ
singleShardTransactionSupport
がTRUE
に設定されている場合、AUTO COMMIT
がOFF
に設定されていると、シャーディング・データソースは単一のシャードに対するローカル・トランザクションをサポートします。次のコード・スニペットは、
singleShardTransactionSupport
プロパティを設定する方法を示しています。private OracleDataSource createShardingDataSource() throws SQLException { OracleDataSource ds = new OracleDataSource(); Properties prop = new Properties(); prop.setProperty("user", <userName>); prop.setProperty("password", <password>); // Set this connection property to enable sharding data source feature prop.setProperty("oracle.jdbc.useShardingDriverConnection", "true"); ds.setConnectionProperties(prop); ds.setURL(gsmURL); // Set this data source property to enable single shard transaction support ds.setSingleShardTransactionSupport(true); return ds; }