36 パーティションの処理

Coherenceでデータ・アフィニティを使用し、デフォルトのパーティション設定を変更することもできます。その手順は分散キャッシュに固有です。

この章の内容は次のとおりです。

データ・アフィニティの指定

Coherenceでのデータ・アフィニティの使用方法、データ・アフィニティの構成方法について学習し、いくつかのデータ・アフィニティの例を確認します。

この項には次のトピックが含まれます:

データ・アフィニティの概要

データ・アフィニティは、関連するキャッシュ・エントリ・グループが単一のキャッシュ・パーティションに含まれることを保証する概念を表します。これにより、フォルト・トレランスを犠牲にすることなく、すべての関連データが単一のプライマリ・キャッシュ・ノードで管理されます。

アフィニティは、(同じキャッシュ・サービスで管理されている通常のケースでは)複数のキャッシュにまたがります。たとえば、Order-LineItemのようなマスター/ディテール・パターンでは、Orderオブジェクトが、関連付けられているLineItemオブジェクトのコレクション全体と共存する場合があります。

データ・アフィニティを使用する利点は2つあります。まず、一連の関連項目に対する問合せおよびトランザクションを、単一のキャッシュ・ノードのみで管理できます。また、すべての並行操作はローカルで管理可能であり、クラスタ化された同期処理は不要です。

標準的なCoherence操作のいくつかは、アフィニティが有益なものがあります。これには、キャッシュ問合せ、InvocableMapの操作、およびgetAllputAllおよびremoveAllなどのメソッドが含まれます。

ノート:

データ・アフィニティは、値ではなくエントリ・キーに関して指定されます。その結果、対応付け情報がキー・クラスに存在している必要があります。同様に、対応付けロジックは、値クラスではなくキー・クラスに適用されます。

アフィニティは、パーティション・キーとの関係で指定されます。前述のOrder-LineItemの例では、Orderオブジェクトが正常にパーティション化され、LineItemオブジェクトは適切なOrderオブジェクトと関連付けられます。

この関連付けは実際の親キーに対して直接実行する必要はなく、親キーの機能マッピングになるだけで十分です。親キーの単一フィールド(一意でない場合でも可能)、または親キーの整数ハッシュとなる場合もあります。重要なのは、すべての子キーで同じ関連キーが返されることだけです。関連キーが実際のキーであるかどうかは重要ではありません(このキーは、単なるグループID)。これにより、親キーの情報を含まない子キー・クラスのサイズの影響を最小限に抑えることができます(導出データであるため、データ・サイズを明示的に決定できるほか、キー動作への影響もありません)。対応付けを汎用化しすぎると(同じグループIDに関連付けられたキーが多すぎる場合)、均一に分散されないことがあります(親キーに関係なく、すべての子キーが同じ対応付けキーを返した場合、子キーはすべて単一パーティションに割り当てられ、クラスタ全体には分散されない)。

KeyAssociationを使用したデータ・アフィニティの指定

アプリケーション定義のキーでは、キャッシュ・キーのクラスは次のようにcom.tangosol.net.cache.KeyAssociationを実装できます。

例36-1 キー・アソシエーションの作成

import com.tangosol.net.cache.KeyAssociation;

public class LineItemId implements KeyAssociation
   {
   // {...}

   public Object getAssociatedKey()
       {
       return getOrderId();
       }

   // {...}
   }

KeyAssociatorを使用したデータ・アフィニティの指定

アプリケーションでは、KeyAssociatorインタフェースを実装するクラスを提供することもできます。

例36-2 カスタムのKeyAssociator

import com.tangosol.net.partition.KeyAssociator;

public class LineItemAssociator implements KeyAssociator
    {
    public Object getAssociatedKey(Object oKey)
        {
        if (oKey instanceof LineItemId)
            {
            return ((LineItemId) oKey).getOrderId();
            }
        else if (oKey instanceof OrderId)
            {
            return oKey;
            }
        else
            {
            return null;
            }
        }

    public void init(PartitionedService service)
        {
        }
    }

キー・アソシエータは、NamedCacheに関して、そのキャッシュを定義した<distributed-scheme>要素で構成されます。

例36-3 キー・アソシエータの構成

<distributed-scheme>
    ...
    <key-associator>
        <class-name>LineItemAssociator</class-name>
    </key-associator>
</distributed-scheme>

キーの関連付けチェックの遅延

キー・アソシエーションは、クラスタ上と拡張クライアント上のいずれでも実装できます。拡張クライアントを使用する場合、最適な方法はそのクライアント上でキー・アソシエーションを実装することです。これにより、キーはクラスタに送信される前に処理されて最適なパフォーマンスが得られます。キー・アソシエーションは、デフォルトではクライアント上で処理されます。クラスタ上でのキー・アソシエーションに依存している既存のクライアント実装で、クラスタ上でキー・クラスが処理されるように強制するには、defer-key-association-checkパラメータを設定する必要があります。

キーの関連付け処理をExtendクライアントによってではなくクラスタ側で実行するには、クライアント側キャッシュの構成で<remote-cache-scheme>要素の<defer-key-association-check>要素をtrueに設定します。たとえば:

<remote-cache-scheme>
   ...
   <defer-key-association-check>true</defer-key-association-check>
</remote-cache-scheme>

ノート:

パラメータがtrueに設定されている場合、キー・クラス実装は、キー・アソシエーションを使用していない場合でもクラスタ上に存在する必要があります。

.NETおよびC++クライアントをそれぞれ使用したキー・アソシエーションの遅延の詳細は、Oracle Coherenceリモート・クライアントの開発Javaバージョンの.NETオブジェクトの実装およびJavaバージョンのC++オブジェクトの実装を参照してください。

アフィニティの使用例

例36-4は、アフィニティを使用してより効率的な問合せ(NamedCache.entrySet(Filter))およびキャッシュ・アクセス(NamedCache.getAll(Collection))を作成する方法を示しています。

例36-4 アフィニティを使用した効率的な問合せの作成

OrderId orderId = new OrderId(1234);

// this Filter is applied to all LineItem objects to fetch those
// for which getOrderId() returns the specified order identifier
// "select * from LineItem where OrderId = :orderId"Filter filterEq = new EqualsFilter("getOrderId", orderId);

// this Filter directs the query to the cluster node that currently owns
// the Order object with the given identifier
Filter filterAsc = new KeyAssociatedFilter(filterEq, orderId);

// run the optimized query to get the ChildKey objects
Set setLineItemKeys = cacheLineItems.keySet(filterAsc);

// get all the Child objects immediately
Set setLineItems = cacheLineItems.getAll(setLineItemKeys);
 
// Or remove all immediately
cacheLineItems.keySet().removeAll(setLineItemKeys);

パーティションの数の変更

分散キャッシュ・サービスのデフォルト・パーティション数は257パーティションです。

分散キャッシュ・サービスをホストするクラスタ内のキャッシュ・サーバーはそれぞれ均等な数のパーティションを管理します。たとえば、4台のキャッシュ・サーバーからなるクラスタ内の各キャッシュ・サーバーは、64個のパーティションを管理します。デフォルト・パーティション数は、通常、最大16台のキャッシュ・サーバーを含むクラスタで許容されます。ただし、最適なパフォーマンスを確保するには、大きいクラスタほど多くのパーティションが必要です。

同じサービスのすべてのメンバーで、パーティション数が一貫して同じであることが必要です。デフォルトでは、アクティブな永続性でパーティション数を変更することはできません。『Oracle Coherenceの管理』で、永続的なサービスのパーティション数を変更して移行する際の回避策に関する項を参照してください。

この項には次のトピックが含まれます:

パーティション数の定義

分散キャッシュ・サービスのパーティション数を変更するには、キャッシュ構成ファイルを編集し、サービスに使用するパーティション数を含む<partition-count>要素を<distributed-scheme>要素内に追加します。たとえば:

<distributed-scheme>
   <scheme-name>distributed</scheme-name>
   <service-name>DistributedCache</service-name>
   <partition-count>1181</partition-count>
   ...
</distributed-scheme>

パーティション数の決定

パーティション数を選択するための正確な計算式はありません。理想的なパーティション数は、各クラスタ・メンバー上のパーティション数と、各パーティションによって保持されるデータ量とのバランスが取れているものです。パーティション数を選択する際は次のガイドラインを使用し、常にテストを実行してそのパーティション数でパフォーマンスが低下しないことを確認します。

  • パーティション数は常に素数にする必要があります。素数のリストは、http://primes.utm.edu/lists/にあります。

  • パーティション数は十分な大きさにして、各メンバーによって管理されるパーティション数が少なすぎることのないバランスのとれた分散がサポートされるようにする必要があります。たとえば、各メンバー上のパーティションが2つのみになるパーティション数では制約的すぎます。

  • パーティション数は、転送オーバーヘッドおよび多数のパーティション転送(転送単位は1パーティション)の記録処理にネットワーク帯域幅が浪費されるほど大きくしないでください。たとえば、数千のパーティションを新しいキャッシュ・サーバー・メンバーに転送すると、大量のネットワーク・リソースが必要になり、特に起動時にクラスタ・パフォーマンスが低下することがあります。

  • 1つのパーティションによって管理されるデータ量が大きすぎないようにしてください(1つのパーティションが管理するデータが多くなるほどパーティションのプロモーションおよび転送のコストが高くなります)。1つのパーティションによって管理されるデータ量は、キャッシュ・サーバーで使用可能なメモリー量によってのみ制限されます。通常は、パーティションの制限が50MBあれば、良好なパフォーマンスが保証されます。大規模なクラスタでは、パーティションの制限に50MBから100MB (速度が10GbE以上でさらに大きな容量)が使用されることもあります。さらに大きな制限を使用することもできますが、転送の待機時間がわずかに増加することと、オーバーヘッド領域が増加して大きなヒープが必要になることを理解しておいてください。

例として、4GBのヒープで構成され、索引を含まないプライマリ・データを約1.3GB格納する(ヒープの2/3をバックアップおよびスクラッチ領域のために残しておく)キャッシュ・サーバーを考えてみましょう。決定したパーティションの制限が控え目な25MBである場合、1台のキャッシュ・サーバーで問題なく53個のパーティションを使用できます(1365MB/25MBが切り捨てられてその前の素数になります)。したがって、20台のキャッシュ・サーバーを含む1つのクラスタは問題なく1051個のパーティションを使用でき(53*20が切り捨てられてその前の素数になる)、約25GBのプライマリ・データを格納します。100台のキャッシュ・サーバーからなる1つのクラスタは問題なく5297個のパーティションを使用でき、約129GBのプライマリ・データを格納できます。

パーティション分散戦略の変更

パーティション分散では、パーティションがどのように、記憶域が有効なクラスタ・メンバーに割り当てられるかを定義します。Coherenceは集中管理型パーティション分散を使用することで、記憶域が有効な各メンバーによってグローバルな分散決定が行われるようにします。集中管理型の分散は、表現力のある分散アルゴリズムを使用することを可能にし、サービスに関する完全かつグローバルなビューを使用します。また、com.tangosol.net.partition.PartitionAssignmentStrategyインタフェースを実装することで、カスタム集中管理型分散戦略を作成できます。

この項には次のトピックが含まれます:

パーティション割当て戦略の指定

使用可能な事前定義済パーティション割当て戦略は次のとおりです。

  • simple - (デフォルト)単純な割当て戦略は、マシンの安全性を確保しながらパーティション分散のバランスを取ることを試みます。

  • mirror:<service-name> – ミラー割当て戦略は、サービスのパーティションを、指定されたサービスのパーティションと共存させることを試みます。この戦略は、キーを関連付けられたクロスサービス・キャッシュ・アクセスがメンバーに対してローカルのままになる可能性を高めるために使用されます。

  • custom - com.tangosol.net.partition.PartitionAssignmentStrategyインタフェースを実装するクラス。

特定のパーティション・キャッシュ・サービスに対してパーティション割当て戦略を構成するには、分散キャッシュ定義内に<partition-assignment-strategy>要素を追加します。

<distributed-scheme>
   ...        
   <partition-assignment-strategy>mirror:<MyService>
   </partition-assignment-strategy>
   ...
</distributed-scheme>

分散キャッシュ・サービス・タイプのすべてのインスタンスに対してパーティション割当て戦略を構成するには、オペレーション・オーバーライド・ファイル内のパーティション・キャッシュ・サービスのpartition-assignment-strategy初期化パラメータをオーバーライドします。たとえば:

<?xml version='1.0'?>

<coherence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns="http://xmlns.oracle.com/coherence/coherence-operational-config"
   xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-operational-config
   coherence-operational-config.xsd">
   <cluster-config>
      <services>
         <service id="3">
            <init-params>
               <init-param id="21">
                  <param-name>partition-assignment-strategy</param-name>
                  <param-value>mirror:<MyService></param-value>
               </init-param>
            </init-params>
         </service>
      </services>
   </cluster-config>
</coherence>

カスタムのパーティション割当て戦略の有効化

カスタムのパーティション割当て戦略を指定するには、<partition-assignment-strategy>要素内に<instance>サブ要素を含めて、com.tangosol.net.partition.PartitionAssignmentStrategyインタフェースを実装する完全修飾クラス名を指定します。カスタム・クラスは、com.tangosol.net.partition.SimpleAssignmentStrategyクラスを拡張することもできます。instanceを参照してください。次の例では、MyPAStrategyクラスで実装されるパーティション割当て戦略を有効にします。

<distributed-scheme>
   ...        
   <partition-assignment-strategy>
      <instance>
         <class-name>package.MyPAStrategy</class-name>
      </instance>
   </partition-assignment-strategy>
   ...
</distributed-scheme>

代替案として、<instance>要素では、PartitionAssignmentStrategyインスタンスを作成するためのファクトリ・クラスを使用する<class-factory-name>要素、およびオブジェクトのインスタンス化を実行するファクトリ・クラス上で静的なファクトリ・メソッドを指定する<method-name>要素の使用がサポートされています。次の例では、MyPAStrategyFactoryクラスでgetStrategyメソッドを使用して、戦略のインスタンスを取得します。

<distributed-scheme>
   ...        
   <partition-assignment-strategy>
      <instance>
         <class-factory-name>package.MyPAStrategyFactory</class-factory-name>
         <method-name>getStrategy</method-name>
      </instance>
   </partition-assignment-strategy>
   ...
</distributed-scheme>

実装に必要な初期化パラメータはすべて、<init-params>要素を使用して指定できます。次の例では、iMaxTimeパラメータが2000に設定されます。

<distributed-scheme>
   ...        
   <partition-assignment-strategy>
      <instance>
         <class-name>package.MyPAStrategy</class-name>
         <init-params>
            <init-param>
               <param-name>iMaxTime</param-name>
               <param-value>2000</param-value>
            </init-param>
         </init-params>
      </instance>
   </partition-assignment-strategy>
   ...
</distributed-scheme>

パーティション・イベントのロギング

データの格納およびアクセスのためにCoherenceで最も一般的に使用されるサービスは、分散/パーティション化されたサービスです。このサービスでは、データの格納と取得のためにパーティション化されたアクセスが提供されるため、レプリカが確実に同期されるようにすることで、冗長性に加えてスケーラビリティが実現します。

Coherenceはキーをパーティションに、パーティションをメンバーに透過的にマップするため、パーティション化の概念はユーザー(エンド・ユーザー)にはまったく認識されないことがあります。所有権メンバーがパーティション化されたサービスに対して参加や離脱を行うと、パーティションは新しいメンバーや残りのメンバー間で再分散されるため、データの全体の再ハッシュが回避されます。また、Coherenceは、初期スナップショットを提供し、その後にプライマリ・メンバーで発生した更新のジャーナルを提供するレプリカを指定します。

これらのパーティション・ライフサイクル・イベント(サービスに対するメンバーとの参加と離脱)によって、パーティションがブロックされます。そのため、Coherenceでは、この使用できない時間をできるだけ短縮しようとします。これまでは、このパーティションを使用できない状態を追跡する手段は最小限でした。ロギングにより、これらのパーティション・ライフサイクル・イベントを把握でき、開始および終了のタイミングが強調表示されます。この機能は、レスポンス時間の増加とこれらのライフサイクル・イベントとの関連付けを行うのに役立ちます。

この項には次のトピックが含まれます:

データ可用性

パーティション・イベントが発生したとき(メンバー間のパーティション移動など)にデータの整合性を保持するため、データへの読取りおよび書込みアクセスが一時的にブロックされます。再分散が実行されるか、索引が作成されると、データはブロックされます。通常、所要時間は短いですが、キャッシュに大量のデータが含まれている場合は時間がかかることがあります。

表36-1 イベントのタイプ

イベント・タイプ 説明

再分散

サーバーがクラスタに対して参加や離脱を行うと、既存と新規の両方のクラスタ内の各メンバーで多くのイベントが発生し、パーティション戦略に従ってデータおよびバックアップ・パーティションの移動に対応します。このスキームは、パーティションを所有するメンバーの名前と、バックアップを所有するメンバーの名前を判別するのに役立ちます。

バックアップからのリストア

プライマリ・パーティションが失われた後、バックアップは、そのパーティションが存在するメンバーのプライマリ記憶域に移動されます。これらのパーティションは、イベントが完了するまでロックされます。

永続性からのリカバリ

スナップショットの作成や永続性からのリカバリなどの永続性メンテナンスによって、影響を受けるパーティションが使用できなくなります。

索引の作成

アプリケーションでデータの索引を作成する必要がある場合は、通常、NamedCacheaddIndexをコールすることで行われます。キャッシュにすでに大量のデータが含まれている場合、またはエントリ当たりの索引を計算するコスト(ValueExtractor)が高い場合、この操作には時間がかかることがあり、その間、送信された問合せがブロックされ、索引データ構造が移入されるのを待機します。

ノート: 要素の追加や削除などの定期的な索引メンテナンスでは、同じ使用不可のペナルティは発生しません。

パーティション・イベント・ログの使用

デフォルトでは、パーティションが使用できない時間のロギングは、大量のログが生成されるため、オフになっています。パーティション・イベントのロギングを有効にするには、coherence.distributed.partition.eventsプロパティをlogに設定し、ログ・レベルの値を8以上に設定します。

たとえば:
-Dcoherence.distributed.partition.events=log

イベントのロギング

次の表に示すイベントは、パーティションの初期割当て時を除き、パーティションごとに1つずつログに記録されます。イベントとともに、所有メンバーおよびパーティションが使用不可になった時間もログに記録されます。

表36-2 ログに記録されるイベントのリスト

イベント・タイプ 説明

ASSIGN

パーティションは、最初に、またはプライマリ・バックアップとすべてのバックアップが失われたために、クラスタ・メンバーに割り当てられます。

PRIMARY_TRANSFER_OUT

パーティションは別のメンバーに転送されます。

BACKUP_TRANSFER_OUT

プライマリ・パーティション所有者は、バックアップ・レプリカのチェーンに含まれるように、パーティションのスナップショットとそのすべてのコンテンツをターゲット・メンバーに転送します。

PRIMARY_TRANSFER_IN

このメンバーは、プライマリ所有権のパーティションおよびすべての関連データを受け取ります。このイベントは、パーティションの既存の所有者からのPRIMARY_TRANSFER_OUTイベントが原因で発生します。

RESTORE

プライマリ・パーティションが失われると、バックアップ所有者(レプリカ)は、バックアップ記憶域から影響を受けるパーティションのプライマリ・メンバーにデータをリストアします。

INDEX_BUILD

索引データ構造は、関連するパーティションに対して移入されます。このイベントは、索引を使用する問合せに影響しますが、キーベースのデータ・アクセスまたは変更はブロックしません。

PERSISTENCE

永続性メンテナンス操作のために、関連するパーティションが使用できなくなります。これらの操作には、永続性およびスナップショット作成からのリカバリが含まれます。

ノート:

これらのイベントでログに記録される時間はミリ秒単位です。

例36-5 ロギング・イベント

メンバー1の場合:

起動時:

2021-06-11 09:26:10.159/5.522 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=PartitionedTopicDedicated:0x000A:5, member=1): PartitionSet{0..256}, Owner: 1, Action: ASSIGN, UnavailableTime: 0
...
アプリケーションはキャッシュでaddIndex()をコールします。
2021-06-11 09:28:36.872/152.234 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=PartitionedCacheDedicated:0x000B:152, member=1): PartitionId: 43, Owner: 1, Action: INDEX_BUILD, UnavailableTime: 3
...
リストされたパーティションは、バックアップとともに別のメンバーに転送されます(バックアップとパーティションは同じではないことに注意してください)。
2021-06-11 09:28:45.573/160.935 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=DistributedCache:PartitionedCache, member=1): PartitionId: 132, Owner: 1, Action: BACKUP_TRANSFER_OUT, UnavailableTime: 1
2021-06-11 09:28:45.678/161.040 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=DistributedCache:PartitionedCache, member=1): PartitionId: 133, Owner: 1, Action: BACKUP_TRANSFER_OUT, UnavailableTime: 1
...
2021-06-11 09:28:49.911/165.273 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=DistributedCache:PartitionedCache, member=1): PartitionId: 2, Owner: 1, Action: PRIMARY_TRANSFER_OUT, UnavailableTime: 5
2021-06-11 09:28:50.017/165.379 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=DistributedCache:PartitionedCache, member=1): PartitionId: 3, Owner: 1, Action: PRIMARY_TRANSFER_OUT, UnavailableTime: 3
...

メンバー2の場合:

パーティションを受信します。パーティションに索引がある場合は、受信直後に再構築されます。
2021-06-11 09:28:49.805/8.033 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=DistributedCache:PartitionedCache, member=2): PartitionId: 1, Owner: 2, Action: PRIMARY_TRANSFER_IN, UnavailableTime: 1
2021-06-11 09:28:49.806/8.034 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=PartitionedCacheDedicated:0x000B:8, member=2): PartitionId: 1, Owner: 2, Action: INDEX_BUILD, UnavailableTime: 0

メンバー2が停止し、メンバー1に戻る:

パーティションはバックアップからリストアされ、パーティションに関連する索引は再構築されます。
2021-06-11 10:29:19.041/3794.322 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=DistributedCache:PartitionedCache, member=1): PartitionId: 0, Owner: 1, Action: RESTORE, UnavailableTime: 109
2021-06-11 10:29:19.041/3794.322 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=DistributedCache:PartitionedCache, member=1): PartitionId: 1, Owner: 1, Action: RESTORE, UnavailableTime: 109
...
2021-06-11 10:29:19.062/3794.343 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=PartitionedCacheDedicated:0x000E:3794, member=1): PartitionId: 1, Owner: 1, Action: INDEX_BUILD, UnavailableTime: 12
2021-06-11 10:29:19.066/3794.347 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=PartitionedCacheDedicated:0x000D:3794, member=1): PartitionId: 0, Owner: 1, Action: INDEX_BUILD, UnavailableTime: 16
2021-06-11 10:29:19.067/3794.349 Oracle Coherence GE 14.1.1.2206.1 <D8> (thread=PartitionedCacheDedicated:0x000E:3794, member=1): PartitionId: 2, Owner: 1, Action: INDEX_BUILD, UnavailableTime: 5
...

ノート:

Coherence VisualVMプラグインには、イベント・ロギングを有効にして生成されたログを分析するオプションがあります。Coherence VisualVMプラグインのリリース・ノートを参照してください。