8 シャード・データベースのアプリケーションの開発
シャードへの直接ルーティング
Oracleクライアントおよび接続プールは、高パフォーマンスのデータ依存ルーティングのために接続文字列に指定されたシャーディング・キーを認識できます。接続レイヤーのシャード・ルーティング・キャッシュは、データが常駐するシャードにデータベース・リクエストを直接ルーティングするために使用されます。
シャードへの直接(キーベース)ルーティングでは、必要なトランザクションに関連するデータが含まれている単一の関連するシャードに対して、シャーディング・キーを使用して接続が確立されます。
接続のチェック時にユーザー・セッション・レベルでデータベース接続リクエストをルーティングするために、シャーディング・キーが使用されます。コンポジット・シャーディング方法では、シャーディング・キーおよびスーパー・シャーディング・キーの両方が必要となります。直接(キーベース)ルーティングでは、シャーディング・キー(またはスーパー・シャーディング・キー)を接続の一部として渡す必要があります。この情報に基づいて、指定されたシャーディング・キーまたはスーパー・シャーディング・キーに関係するデータが含まれている関連するシャードに対して、接続が確立されます。
シャードとのセッションが確立されると、すべてのSQL問合せおよびDMLが該当するシャードのスコープ内でサポートされ、実行されます。このルーティングは高速であり、シャード内トランザクションを実行するすべてのOLTPワークロードで使用されます。最高のパフォーマンスおよび可用性を必要とするすべてのOLTPワークロードに直接ルーティングを使用することをお薦めします。
Oracle Shardingをサポートするために、Oracle接続プールおよびドライバに対して重要な機能強化が行われました。JDBC、UCP (Universal Connection Pool)、OCI (OCI Session Pool)およびODP.NET (Oracle Data Provider for .NET)は、接続作成中にシャーディング・キーを渡すためのAPIを提供しています。Apache Tomcat、IBM Websphere、Oracle WebLogic ServerおよびJBOSSでは、JDBC/UCPのサポートを活用してシャーディングを使用できます。PHP、Python、PerlおよびNode.jsではOCIのサポートを活用できます。
シャード・トポロジ・キャッシュは、シャードとシャーディング・キーの範囲のマッピングです。Oracle統合接続プールは、このシャード・トポロジ・キャッシュをそのメモリー内に保持します。特定のシャードへの最初の接続時(プールの初期化時またはプールが新しいシャードに接続するとき)に、シャーディング・キーの範囲のマッピングがシャードから収集されて、シャード・トポロジ・キャッシュが動的に作成されます。
シャード・トポロジをキャッシュすると、シャードへの高速なパスが作成され、シャードへの接続を作成するプロセスが迅速になります。シャーディング・キーを使用して接続リクエストが実行されると、接続プールはこの特定のシャーディング・キーが存在する対応するシャードを検索します(トポロジ・キャッシュから)。一致する接続がプールで利用できる場合、プールは内部接続選択アルゴリズムを適用することによって、シャードへの接続を返します。
キャッシュされたトポロジ・マップに存在する特定のシャーディング・キーへのデータベース接続リクエストは、そのシャードに直接送られます(つまり、シャード・ディレクタがバイパスされます)。また、接続プールは、SDBからRLB通知をサブスクライブし、実行時ロード・バランシング・アドバイザに基づいて最適な接続を分配します。接続が確立されると、クライアントはシャードに対するトランザクションを直接実行します。指定したシャーディング・キーのすべてのトランザクションが実行されたら、アプリケーションはその接続をプールに返し、別のキーの接続を取得する必要があります。
一致する接続がプールにない場合は、シャーディング・キーとともに接続リクエストをシャード・ディレクタに転送することによって、新しい接続が作成されます。
プールが初期化され、シャード・トポロジ・キャッシュがすべてのシャードに基づいて作成されると、シャード・ディレクタが停止しても直接ルーティングに影響しなくなります。
既存のアプリケーションのシャーディングに対する適合性
シャード・アーキテクチャの利点を享受するには、シャーディングを使用する予定がない既存のアプリケーションで、一定のレベルの再設計が必要となります。
シャーディング・キーを渡すのみで済む簡単な場合や、シャード・データベースで必要となるデータおよびワークロードの水平パーティション化を行うことができない場合があります。
電子商取引、モバイル、ソーシャル・メディアなど、多くの顧客対応Webアプリケーションはシャーディングに適切です。そのようなアプリケーションには、適切に定義されたデータ・モデルおよびデータ分散方法(ハッシュ、範囲、リストまたはコンポジット)があり、主にシャーディング・キーを使用してデータにアクセスします。シャーディング・キーの例として顧客ID、アカウント番号、country_idなどがあります。通常、アプリケーションでは、シャーディングが十分に機能するためにデータの部分的な非正規化も必要となります。
シャーディング・キーの単一値に関連付けられたデータにアクセスするトランザクションは、シャード・データベースの主なユースケースです。たとえば、顧客のレコード、サブスクライバのドキュメント、財務トランザクション、電子商取引トランザクションなどの検索および更新などです。同じ値のシャーディング・キーを持つ、シャード・スキーマ内のすべての行は同じシャード上にあることが保証されるため、そのようなトランザクションは常に単一のシャードで最高のパフォーマンスで実行され、最高レベルの一貫性となります。
マルチシャード操作はサポートされますが、パフォーマンスおよび一貫性のレベルは低くなります。そのようなトランザクションには単純な集計、レポートなどが含まれ、単一シャードのトランザクションが優位を占めるワークロードに比べて、シャード・アプリケーションで重要度の低い役割を果たします。
直接ルーティングをサポートするシャーディングAPI
Oracle接続プールおよびドライバはOracle Shardingをサポートしています。
JDBC、UCP、OCIおよびOracle Data Provider for .NET (ODP.NET)は、接続チェックの一部としてシャーディング・キーを認識します。Apache Tomcat、WebsphereおよびWebLogicはシャーディングのためのUCPサポートを活用し、PHP、Python、PerlおよびNode.jsはOCIサポートを活用します。
Oracle Sharding対応のOracle JDBC API
Oracle Java Database Connectivity (JDBC)には、Oracle Sharding構成内のデータベース・シャードに接続するために使用できるAPIがあります。
JDBCドライバは指定されたシャーディング・キーおよびスーパー・シャーディング・キーを認識し、データが含まれている該当シャードに接続します。シャードに対する接続が確立されると、DML、SQL問合せなどのサポートされているデータベース操作は通常どおりに実行されます。
シャード対応アプリケーションは、データベース・シャーディングAPIを使用してシャーディング・キーを指定することで特定のシャードに接続します。
OracleShardingKey
インタフェースは、現在のオブジェクトがOracleのシャード・データベースで使用されるOracleシャーディング・キーを表していることを示します。OracleShardingKeyBuilder
インタフェースは、サポートされている様々なデータ型のサブキーを持つ複合シャーディング・キーを作成します。このインタフェースでは、新しいJDK 8ビルダー・パターンを使用してシャーディング・キーを作成します。OracleConnectionBuilder
インタフェースは、ユーザー名とパスワード以外の追加パラメータを使用して、接続オブジェクトを構築します。OracleDataSource
クラスにより、createConnectionBuilder
メソッドとcreateShardingKeyBulider
メソッドはデータベース・シャードのサポートが可能になります。OracleXADataSource
クラスにより、createConnectionBuilder
メソッドはデータベース・シャードのサポートが可能になります。OracleConnection
クラスにより、setShardingKeyIfValid
メソッドとsetShardingKey
メソッドはデータベース・シャードのサポートが可能になります。OracleXAConnection
クラスにより、setShardingKeyIfValid
メソッドとsetShardingKey
メソッドはデータベース・シャードのサポートが可能になります。
詳細と例は、『Oracle Database JDBC開発者ガイド』を参照してください。
例8-1 JDBCを使用したシャード対応アプリケーション・コードの例
次のコードでは、JDBCシャーディングAPIの使用方法を示します
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();
Oracle Sharding対応のOracle Call Interface
Oracle Call Interface (OCI)には、Oracle Sharding構成内のデータベース・シャードに接続するために使用できるインタフェースがあります。
チャンクを対象に読取りまたは書込みを行う要求を作成するには、接続開始ステップでそのチャンクを格納している適切なデータベース(シャード)にアプリケーションをルーティングする必要があります。このルーティングを行うには、データ・キーを使用します。データ・キーにより、特定のチャンクへのルーティング(シャーディング・キーを指定)またはチャンクのグループへのルーティング(スーパー・シャーディング・キーを指定)が可能になります。
操作対象のチャンクを含む適切なシャードに接続するためには、アプリケーションでキーを指定してから、シャードされたOracle Databaseへの接続(スタンドアロン接続またはOCIセッション・プールから取得された接続)を取得する必要があります。OCIセッション・プールでは、プールから接続をチェックアウトする前にデータ・キーを指定する必要があります。
大まかに言うと、シャーディング・キーとシャード・グループ・キーを構成して、基礎となる接続でセッションを取得するには、次のステップを実行する必要があります。
- シャーディング・キー記述子を割り当てるため、
OCIDescriptorAlloc()
をコールし、シャーディング・キーを構成するためにOCI_DTYPE_SHARDING_KEY
として記述子型パラメータを指定します。 - シャード・グループ・キー記述子を割り当てるため、
OCIDescriptorAlloc()
をコールし、シャード・グループ・キーを構成するためにOCI_DTYPE_SHARDING_KEY
として記述子型パラメータを指定します。 - シャーディング・キーおよびシャード・グループ・キー情報が含まれる前のステップの初期化済認証ハンドルを使用して
OCISessionGet()
をコールし、シャーディング・キーで指定されたシャードおよびチャンクと、シャード・グループ・キーで指定されたチャンクのグループに対するデータベース接続を取得します。
OCIセッション・プールへの接続、スタンドアロン接続、およびカスタム・プール接続の作成の詳細は、『Oracle Call Interfaceプログラマーズ・ガイド』を参照してください。
Oracle Sharding対応のOracle Universal Connection Pool API
Oracle Universal Connection Pool (UCP)には、Oracle Sharding構成内のデータベース・シャードに接続するために使用できるAPIがあります。
シャード対応のアプリケーションは、createShardingKeyBuilder
およびcreateConnectionBuilder
という拡張シャーディングAPIを使用してシャーディング・キーを指定することによって、特定のシャードへの接続を取得します。
大まかに言うと、アプリケーションがシャード・データベースと連携するようにするには、次のステップに従う必要があります。
-
シャード・ディレクタおよびグローバル・サービスが反映されるようにURLを更新します。
-
次のプール・パラメータをプール・レベルおよびシャード・レベルで設定します。
-
setInitialPoolSize
では、UCPの開始時に作成する接続の初期数を設定します。 -
setMinPoolSize
では、実行時にプールで維持する接続の最小数を設定します。 -
setMaxPoolSize
では、接続プールに許容される接続の最大数を設定します -
setMaxConnectionsPerShard
では、シャードごとの最大接続数を設定します
-
-
createShardingKeyBuilder
を使用してシャーディング・キー・オブジェクトを作成します。 -
createConnectionBuilder
を使用して接続を確立します。 -
特定のシャードのスコープ内でトランザクションを実行します。
例8-2 UCPシャーディングAPIを使用した接続の確立
シャーディング・キーを作成し、UCPシャーディングAPIコールを使用して接続を確立する方法を示すコード片を次に示します。
...
PoolDataSource pds =
PoolDataSourceFactory.getPoolDataSource();
// Set Connection Pool properties
pds.setURL(DB_URL);
pds.setUser("hr");
pds.setPassword("****");
pds.setInitialPoolSize(10);
pds.setMinPoolSize(20);
pds.setMaxPoolSize(30);
// build the sharding key object
OracleShardingKey shardingKey =
pds.createShardingKeyBuilder()
.subkey("mary.smith@example.com", OracleType.VARCHAR2)
.build();
// Get an UCP connection for a shard
Connection conn =
pds.createConnectionBuilder()
.shardingKey(shardingKey)
.build();
...
例8-3 UCP接続プールを使用したシャード対応アプリケーション・コードの例
この例では、プール設定をプール・レベルおよびシャード・レベルで定義しています。
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import oracle.jdbc.OracleShardingKey;
import oracle.jdbc.OracleType;
import oracle.jdbc.pool.OracleDataSource;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;
public class MaxConnPerShard
{
public static void main(String[] args) throws SQLException
{
String url = "jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(HOST=shard-dir1)(PORT=3216)
(PROTOCOL=tcp))(CONNECT_DATA=(SERVICE_NAME=shsvc.shpool.oradbcloud)(REGION=east)))";
String user="testuser1", pwd = "testuser1";
int maxPerShard = 100, initPoolSize = 20;
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
pds.setConnectionFactoryClassName(OracleDataSource.class.getName());
pds.setURL(url);
pds.setUser(user);
pds.setPassword(pwd);
pds.setConnectionPoolName("testpool");
pds.setInitialPoolSize(initPoolSize);
// set max connection per shard
pds.setMaxConnectionsPerShard(maxPerShard);
System.out.println("Max-connections per shard is: "+pds.getMaxConnectionsPerShard());
// build the sharding key object
int shardingKeyVal = 123;
OracleShardingKey sdkey = pds.createShardingKeyBuilder()
.subkey(shardingKeyVal, OracleType.NUMBER)
.build();
// try to build maxPerShard connections with the sharding key
Connection[] conns = new Connection[maxPerShard];
for (int i=0; i<maxPerShard; i++)
{
conns[i] = pds.createConnectionBuilder()
.shardingKey(sdkey)
.build();
Statement stmt = conns[i].createStatement();
ResultSet rs = stmt.executeQuery("select sys_context('userenv', 'instance_name'),
sys_context('userenv', 'chunk_id') from dual");
while (rs.next()) {
System.out.println((i+1)+" - inst:"+rs.getString(1)+", chunk:"+rs.getString(2));
}
rs.close();
stmt.close();
}
System.out.println("Try to build "+(maxPerShard+1)+" connection ...");
try {
Connection conn = pds.createConnectionBuilder()
.shardingKey(sdkey)
.build();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select sys_context('userenv', 'instance_name'),
sys_context('userenv', 'chunk_id') from dual");
while (rs.next()) {
System.out.println((maxPerShard+1)+" - inst:"+rs.getString(1)+",
chunk:"+rs.getString(2));
}
rs.close();
stmt.close();
System.out.println("Problem!!! could not build connection as max-connections per
shard exceeded");
conn.close();
} catch (SQLException e) {
System.out.println("Max-connections per shard met, could not build connection
any more, expected exception: "+e.getMessage());
}
for (int i=0; i<conns.length; i++)
{
conns[i].close();
}
}
}
Oracle Sharding対応のOracle Data Provider for .NET API
Oracle Data Provider for .NET (ODP.NET)には、Oracle Sharding構成内のデータベース・シャードに接続するために使用できるAPIがあります。
ODP.NET APIを使用すると、シャード対応アプリケーションはOracleConnection
クラスのSetShardingKey(OracleShardingKey shardingKey, OracleShardingKey superShardingKey)
インスタンス・メソッドなどのAPIでシャーディング・キーおよびスーパー・シャーディング・キーを指定することで、特定のシャードへの接続を取得します。
大まかに言うと、.NETアプリケーションがシャード・データベースと連携するようにするには、次のステップを実行する必要があります。
-
ODP.NET管理対象外ドライバを使用します。
シャーディングは、ODP.NET接続プールを使用する場合もODP.NET接続プールを使用しない場合もサポートされます。各プールは、シャード・データベースの異なるシャードへの接続を保持できます。
-
OracleShardingKey
クラスを使用して、シャーディング・キー、およびスーパー・シャーディング・キーの別のインスタンスを設定します。 -
ODP.NETが指定したシャーディング・キーおよびスーパー・シャーディング・キーを使用する接続を返すことができるように、
OracleConnection.Open()
を呼び出す前に、OracleConnection.SetShardingKey()
メソッドを呼び出します。これらのキーは、
OracleConnection
がクローズ状態のときに設定する必要があります。そうしないと、例外がスローされます。
例8-4 ODP.NETを使用したシャード対応アプリケーション・コードの例
using System;
using Oracle.DataAccess.Client;
class Sharding
{
static void Main()
{
OracleConnection con = new OracleConnection
("user id=hr;password=hr;Data Source=orcl;");
//Setting a shard key
OracleShardingKey shardingKey = new OracleShardingKey(OracleDbType.Int32, 123);
//Setting a second shard key value for a composite key
shardingKey.SetShardingKey(OracleDbType.Varchar2, "gold");
//Creating and setting the super shard key
OracleShardingKey superShardingKey = new OracleShardingKey();
superShardingKey.SetShardingKey(OracleDbType.Int32, 1000);
//Setting super sharding key and sharding key on the connection
con.SetShardingKey(shardingKey, superShardingKey);
con.Open();
//perform SQL query
}
}