次の方法で共有


シャード マップ マネージャーでデータベースをスケールアウトする

適用対象:Azure SQL データベース

Azure SQL Database でデータベースを簡単にスケールアウトするには、シャード マップ マネージャーを使用します。 シャード マップ マネージャーは、シャード セット内のすべてのシャード (データベース) についてのグローバル マッピング情報を保持する特殊なデータベースです。 メタデータにより、アプリケーションは シャーディング キーの値に基づいて適切なデータベースに接続できます。 さらに、セット内のすべてのシャードには、ローカル シャード データを追跡するマップが含まれます ( シャードレットと呼ばれます)。

シャード マップ管理の図。

これらのマップの構造を理解することは、シャード マップ管理に不可欠です。 これは、シャード マップを管理するためのスケーラブルなクラウド データベースの構築にある ShardMapManager クラス (Java.NET) を使用して行われます。

シャード マップとシャードのマッピング

シャードごとに、作成するシャード マップの種類を選択する必要があります。 何を選択するかはデータベースのアーキテクチャによって異なります。

  1. データベースごとに 1 つのテナント
  2. データベースごとに複数のテナント (2 種類):
    1. リスト マッピング
    2. 範囲マッピング

シングルテナント モデルの場合は、リスト マッピング シャード マップを作成します。 シングルテナント モデルでは、テナントごとに 1 つのデータベースが割り当てられます。 これは、シャード マップ管理が簡単なので、SaaS 開発者にとって効率的なモデルです。

リスト マッピングの図。

マルチテナント モデルでは、個々のデータベースに複数のテナントが割り当てられます (そして、テナントのグループを複数のデータベースに分散させることができます)。 各テナントで必要なデータが少ない場合は、このモデルを使用します。 このモデルでは、範囲マッピングを使用してデータベースにテナントの範囲を割り当てます。

範囲マッピングの図。

または、リスト マッピングを使用して複数のテナントを個々のデータベースに割り当てることにより、マルチテナント データベース モデルを実装できます。 たとえば、ID が 1 と 5 のテナントに関する情報を DB1 に格納し、DB2 にテナント 7 と 10 のデータを格納する、といったことができます。

1 つの DB 上の複数のテナントの図。

シャーディング キーでサポートされる型

Elastic Scale では、シャーディング キーとして次の型がサポートされています。

。網 ジャワ
整数 (integer) 整数 (integer)
長い 長い
guid UUID(ユニバーサルユニーク識別子)
byte[] byte[]
DATETIME タイムスタンプ(時刻印)
TimeSpan 期間
datetimeoffset (デイトタイムオフセット) offsetdatetime

リスト シャード マップと範囲シャード マップ

シャード マップは、個々のシャーディング キー値のリストまたはシャーディング キー値の範囲を使用して作成できます。

リスト シャード マップ

シャードには、シャードレットが含まれます。シャードレットとシャードの間のマッピングは、シャード マップによって管理されます。 リスト シャード マップは、シャードレットを識別する個々のキー値と、シャードとして動作するデータベースとの間の関連付けのことです。 リスト マッピングは明示的であり、異なるキー値を同じデータベースにマップすることができます。 たとえば、キー値 1 がデータベース A にマップし、キー値 3 と 6 の両方がデータベース B にマップされます。

シャードの場所
1 データベース A
3 データベース B
4 データベース C
6 データベース B
... ...

範囲シャード マップ

範囲シャード マップでは、キーの範囲がペア [Low Value, High Value) によって記述されます。Low Value は範囲内の最小キー、High Value は範囲を超える最初の値です。

たとえば、 [0, 100) には、0 以上 100 未満のすべての整数が含まれます。 複数の範囲が同じデータベースを指すことができます。次の例では、不整合な範囲 ([100,200) と [400,600] の両方がデータベース C を指しています)。

シャードの場所
[1,50) データベース A
[50,100) データベース B
[100,200) データベース C
[400,600) データベース C
... ...

上記の各表は、 ShardMap オブジェクトの概念的な例です。 各行は、個々の PointMapping (リスト シャード マップの場合) または RangeMapping (範囲シャード マップの場合) オブジェクトの簡略化された例です。

シャード マップ マネージャー

クライアント ライブラリでは、シャード マップ マネージャーはシャード マップのコレクションです。 ShardMapManager インスタンスによって管理されるデータは、次の 3 つの場所に保持されます。

  1. グローバル シャード マップ (GSM) : すべてのシャード マップとマッピングのリポジトリとして機能するデータベースを指定します。 この情報を管理するために、特殊なテーブルとストアド プロシージャが自動的に作成されます。 通常、これは小さなデータベースで簡単にアクセスでき、アプリケーションの他の目的には使用されません。 テーブルは、 __ShardManagementという名前の特別なスキーマ内にあります。
  2. ローカル シャード マップ (LSM) : シャードとして指定されたすべてのデータベースは、シャードに固有のシャード マップ情報を格納と管理するためのいくつかの小さなテーブルと特殊なストアド プロシージャを含むように変更されます。 この情報は GSM 内の情報を冗長化したもので、これにより、アプリケーションは、GSM に負荷をかけることなくキャッシュされたシャード マップ情報を検証できます。アプリケーションは、LSM を使用して、キャッシュされたマッピングがまだ有効であるかどうかを判定できます。 各シャードの LSM に対応するテーブルもスキーマ __ShardManagementに含まれます。
  3. アプリケーション キャッシュ: ShardMapManager オブジェクトにアクセスする各アプリケーション インスタンスは、そのマッピングのローカル メモリ内キャッシュを保持します。 ここには、最近取得されたルーティング情報が格納されます。

ShardMapManager を構築する

ShardMapManager オブジェクトは、ファクトリ (Java.NET) パターンを使用して構築されます。 ShardMapManagerFactory.GetSqlShardMapManager (Java.NET) メソッドは、ConnectionStringの形式で資格情報 (GSM を保持するサーバー名とデータベース名を含む) を取得し、ShardMapManagerのインスタンスを返します。

ShardMapManagerは、アプリケーションの初期化コード内で、アプリ ドメインごとに 1 回だけインスタンス化する必要があります。 同じアプリ ドメインに ShardMapManager の追加インスタンスを作成すると、アプリケーションのメモリと CPU 使用率が増加します。 ShardMapManagerには、任意の数のシャード マップを含めることができます。 多くのアプリケーションでは 1 つのシャード マップで十分な場合がありますが、異なるスキーマまたは一意の目的で異なるデータベース セットが使用される場合があります。このような場合は、複数のシャード マップを使用することをお勧めします。

このコードでは、アプリケーションは、ShardMapManager (TryGetSqlShardMapManager.NET メソッド) を使用して既存のを開こうとします。 グローバル ShardMapManager (GSM) を表すオブジェクトがまだデータベース内に存在しない場合、クライアント ライブラリは、 CreateSqlShardMapManager (Java.NET) メソッドを使用してオブジェクトを作成します。

// Try to get a reference to the Shard Map Manager in the shardMapManager database.
// If it doesn't already exist, then create it.
ShardMapManager shardMapManager = null;
boolean shardMapManagerExists = ShardMapManagerFactory.tryGetSqlShardMapManager(shardMapManagerConnectionString,ShardMapManagerLoadPolicy.Lazy, refShardMapManager);
shardMapManager = refShardMapManager.argValue;

if (shardMapManagerExists) {
    ConsoleUtils.writeInfo("Shard Map %s already exists", shardMapManager);
}
else {
    // The Shard Map Manager does not exist, so create it
    shardMapManager = ShardMapManagerFactory.createSqlShardMapManager(shardMapManagerConnectionString);
    ConsoleUtils.writeInfo("Created Shard Map %s", shardMapManager);
}
// Try to get a reference to the Shard Map Manager via the Shard Map Manager database.  
// If it doesn't already exist, then create it.
ShardMapManager shardMapManager;
bool shardMapManagerExists = ShardMapManagerFactory.TryGetSqlShardMapManager(
                                        connectionString,
                                        ShardMapManagerLoadPolicy.Lazy,
                                        out shardMapManager);

if (shardMapManagerExists)
{
    Console.WriteLine("Shard Map Manager already exists");
}
else
{
    // Create the Shard Map Manager.
    ShardMapManagerFactory.CreateSqlShardMapManager(connectionString);
    Console.WriteLine("Created SqlShardMapManager");

    shardMapManager = ShardMapManagerFactory.GetSqlShardMapManager(
            connectionString,
            ShardMapManagerLoadPolicy.Lazy);

// The connectionString contains server name, database name, and admin credentials for privileges on both the GSM and the shards themselves.
}

.NET バージョンの場合は、PowerShell を使用して新しいシャード マップ マネージャーを作成できます。

RangeShardMap または ListShardMap の取得

シャード マップ マネージャーの作成後、TryGetRangeShardMap (Java.NET)、TryGetListShardMap (Java.NET)、または GetShardMap (Java.NET) メソッドを使用して、RangeShardMap (Java.NET) または ListShardMap (Java.NET) を取得できます。

// Creates a new Range Shard Map with the specified name, or gets the Range Shard Map if it already exists.
static <T> RangeShardMap<T> createOrGetRangeShardMap(ShardMapManager shardMapManager,
            String shardMapName,
            ShardKeyType keyType) {
    // Try to get a reference to the Shard Map.
    ReferenceObjectHelper<RangeShardMap<T>> refRangeShardMap = new ReferenceObjectHelper<>(null);
    boolean isGetSuccess = shardMapManager.tryGetRangeShardMap(shardMapName, keyType, refRangeShardMap);
    RangeShardMap<T> shardMap = refRangeShardMap.argValue;

    if (isGetSuccess && shardMap != null) {
        ConsoleUtils.writeInfo("Shard Map %1$s already exists", shardMap.getName());
    }
    else {
        // The Shard Map does not exist, so create it
        try {
            shardMap = shardMapManager.createRangeShardMap(shardMapName, keyType);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        ConsoleUtils.writeInfo("Created Shard Map %1$s", shardMap.getName());
    }

    return shardMap;
}
// Creates a new Range Shard Map with the specified name, or gets the Range Shard Map if it already exists.
public static RangeShardMap<T> CreateOrGetRangeShardMap<T>(ShardMapManager shardMapManager, string shardMapName)
{
    // Try to get a reference to the Shard Map.
    RangeShardMap<T> shardMap;
    bool shardMapExists = shardMapManager.TryGetRangeShardMap(shardMapName, out shardMap);

    if (shardMapExists)
    {
        ConsoleUtils.WriteInfo("Shard Map {0} already exists", shardMap.Name);
    }
    else
    {
        // The Shard Map does not exist, so create it
        shardMap = shardMapManager.CreateRangeShardMap<T>(shardMapName);
        ConsoleUtils.WriteInfo("Created Shard Map {0}", shardMap.Name);
    }

    return shardMap;
}

シャード マップ管理資格情報

シャード マップを管理、操作するアプリケーションは、シャード マップを使用して接続をルーティングするアプリケーションとは異なります。

シャード マップを管理するには (シャード、シャード マップ、シャード マッピングなどを追加または変更する)、ShardMapManagerを使用して、をインスタンス化する必要があります。 この資格情報により、新しいシャードに LSM テーブルが作成されるときだけでなく、シャード マップ情報が入力または変更されたときに GSM と LSM の両方のテーブルに対する書き込みが許可される必要があります。

Elastic Database クライアント ライブラリへのアクセスに使用する資格情報」を参照してください。

影響を受けるのはメタデータのみ

ShardMapManager データの設定または変更に使用されるメソッドは、シャード自体に格納されているユーザー データを変更しません。 たとえば、 CreateShardDeleteShardUpdateMappingなどのメソッドは、シャード マップメタデータにのみ影響します。 シャードに含まれるユーザー データを削除、追加、変更することはありません。 代わりに、これらのメソッドは、実際のデータベースを作成または削除するために実行される別の操作や、シャード化環境のバランスを再調整するためにシャードで行を移動する操作と組み合わせて使用するように設計されています (エラスティック データベース ツールに含まれる 分割/マージ ツールでは、これらの API を使用し、シャード間の実際のデータ移動を調整します)。 スケールアウトされたクラウド データベース間でのデータの移動を参照してください。

データ依存ルーティング

シャード マップ マネージャーは、アプリに固有のデータ操作を実行するためのデータベース接続を必要とするアプリケーションで使用されます。 これらの接続は、正しいデータベースに関連付けられている必要があります。 これを データ依存ルーティングといいます。 このようなアプリケーションの場合は、GSM データベースに対する読み取り専用アクセス権限を持つ資格情報を使用してファクトリからシャード マップ マネージャー オブジェクトをインスタンス化します。 後で個々の接続要求により、適切なシャード データベースに接続するために必要な資格情報が提供されます。

これらのアプリケーション (読み取り専用資格情報で開かれた ShardMapManager を使用) は、マップまたはマッピングに変更を加えることはできません。 このような操作を行うには、既に説明したように、高度な特権の資格情報を提供する管理操作専用のアプリケーションまたは PowerShell スクリプトを作成します。 「 Elastic Database クライアント ライブラリへのアクセスに使用する資格情報」を参照してください。

詳細については、「 データ依存ルーティングを使用してクエリを適切なデータベースにルーティングする」を参照してください。

シャード マップを変更する

シャード マップはさまざまな方法で変更できます。 次に示すどのメソッドを使用しでもシャードとそのマッピングを変更できますが、これらによってシャード内のメタデータが物理的に変更されたり、実際のデータベースが作成または削除されたりすることはありません。 シャード マップに対する次の操作の一部は、データを物理的に移動する管理アクション、またはシャードとして機能するデータベースを追加および削除する管理アクションと調整する必要がある場合があります。

これらのメソッドは、シャード化データベース環境内のデータの全体的な分散状況を変更するために使用できるビルド ブロックとして連携します。

  • シャードを追加または削除するには、シャードマップ (CreateShard.NET) クラスの (DeleteShard.NET) と (Java.NET) を使用します。

    • これらの操作を実行するには、サーバーとターゲット シャードを表すデータベースが既に存在している必要があります。 これらのメソッドは、データベース自体には作用せず、シャード マップ内のメタデータのみに作用します。
  • シャードにマップされているポイントまたは範囲を作成または削除するには、ListShardMap (CreateRangeMapping.NET) クラスの rangeShardMapping (JavaDeleteMapping) クラスの (Java.NET)、 (CreatePointMapping.NET) (Java.NET) を使用します。

    多くの異なるポイントまたは範囲を同じシャードにマップできます。 これらのメソッドはメタデータにのみ影響します。シャードに既に存在する可能性のあるデータには影響しません。 DeleteMapping操作と一貫性を保つためにデータベースからデータを削除する必要がある場合は、これらの操作を個別に実行しますが、これらのメソッドを使用する必要があります。

  • 既存の範囲を 2 つに分割するか、隣接する範囲を 1 つにマージするには、 SplitMapping (Java.NET) と MergeMappings (Java.NET) を使用します。

    分割操作とマージ操作 では、キー値がマップされるシャードは変更されません。 分割操作を実行すると、既存の範囲が 2 つの部分に分割されます。このとき、どちらの部分も同じシャードにマップされたままになります。 マージ操作を実行すると、同じシャードに既にマップされている 2 つの隣接する範囲が 1 つの範囲に結合されます。 シャード間でのポイントまたは範囲自体の移動は、実際のデータ移動と組み合わせて UpdateMapping を使用して調整する必要があります。 Elastic Database ツールの一部である Split/Merge サービスを使用すると、データの移動が必要な場合にシャード マップの変更をデータの移動と連携させることができます。

  • 個々のポイントまたは範囲を別のシャードに再マップ (または移動) するには、 UpdateMapping (Java.NET) を使用します。

    データは移動される可能性があるため、UpdateMapping操作と一貫性を保つには、これらのメソッドを使用することに加えて、その移動を個別に実行する必要があります。

  • マッピングをオンラインおよびオフラインにするには、 MarkMappingOffline (Java.NET) と MarkMappingOnline (Java.NET) を使用して、マッピングのオンライン状態を制御します。

    シャード マッピングに対する特定の操作は、UpdateMappingなど、マッピングがDeleteMapping状態の場合にのみ許可されます。 マッピングがオフラインのとき、そのマッピングに含まれるキーに基づくデータに依存する要求はエラーを返します。 さらに、範囲が初めてオフラインになったときは、変更が加えられている範囲に対するクエリによって一貫性のない結果または不完全な結果が生成されるのを防ぐために、影響を受けるシャードへのすべての接続が自動的に強制終了されます。

マッピングは、.NET では不変オブジェクトです。 マッピングを変更する上記のすべてのメソッドは、コード内のこれらへの参照もすべて無効にします。 マッピングの状態を変更する一連の操作を実行しやすくするため、マッピングを変更するすべてのメソッドは新しいマッピングの参照を返します。これにより、操作を連結できます。 たとえば、キー 25 を含むシャード マップ sm で既存のマッピングを削除するには、次のように実行できます。

    sm.DeleteMapping(sm.MarkMappingOffline(sm.GetMappingForKey(25)));

シャードを追加する

多くの場合、アプリケーションは、既に存在しているシャード マップに対し、新しいキーまたはキー範囲から予想されるデータを処理するために新しいシャードを追加する必要があります。 たとえば、テナント ID でシャード化されたアプリケーションでは、新しいテナントの新しいシャードをプロビジョニングする必要がある場合や、毎月シャード化されたデータに、新しい月の開始前に新しいシャードをプロビジョニングする必要がある場合があります。

キー値の新しい範囲が既に既存のマッピングの一部ではなく、データの移動が不要な場合は、新しいシャードを追加して、新しいキーまたは範囲をそのシャードに関連付けるようにすると簡単に済みます。 新しいシャードの追加の詳細については、「 Elastic Database ツールを使用したシャードの追加」を参照してください。

ただし、データの移動を必要とするシナリオでは、必要なシャード マップの更新と共にシャード間でのデータの移動を調整するために分割/マージ ツールが必要になります。 分割/マージ ツールの使用の詳細については、スケールアウトされたクラウド データベース間でのデータの移動に関するページを参照してください。

まだ弾力性データベース ツールを使用していない場合は、 ファースト ステップ ガイドを参照してください。 ご質問がある場合は、SQL Database に関する Microsoft Q&A 質問ページを参照してください。機能に関するご要望は、SQL Database に関するフィードバック フォーラムで新しいアイデアを追加したり、既存のアイデアに投票したりしてください。