第7章 永続ストレージのセットアップ

Data Grid はインメモリーデータを外部ストレージに維持し、以下のようなデータを管理する追加機能を提供します。

持続性
キャッシュストアを追加すると、不揮発性ストレージにデータを永続化できるため、再起動後も存続することができます。
ライトスルーキャッシュ
Data Grid を永続ストレージの前のキャッシュレイヤーとして設定すると、Data Grid が外部ストレージとのすべての対話を処理するため、アプリケーションのデータアクセスが簡素化されます。
データオーバーフロー
エビクションとパッシベーションの手法を使用すると、Data Grid は頻繁に使用されるデータのみをメモリー内に保持し、古いエントリーを永続ストレージに書き込みます。

7.1. Data Grid キャッシュストア

データグリッドを永続データソースに接続するキャッシュストアは、NonBlockingStore インターフェイスを実装します。

7.1.1. キャッシュストアの設定

チェーンの Data Grid キャッシュにキャッシュストアを追加します。宣言的またはプログラムのいずれかです。キャッシュ読み取り操作は、データの有効な null 要素を見つけるまで、設定された順序で各キャッシュストアを確認します。書き込み操作は、読み取り専用として設定したものを除いて、すべてのキャッシュストアに影響します。

手順

  1. persistence パラメーターを使用して、キャッシュの永続層を設定します。
  2. キャッシュストアがノードに対してローカルになるか、またはクラスター全体で共有されるかどうかを設定します。

    shared 属性を宣言的に、または shared(false) メソッドをプログラムを使用して使用します。

  3. その他のキャッシュストアプロパティーを随時設定します。カスタムキャッシュストアには、プロパティー パラメーターを含めることもできます。

    注記

    キャッシュストアを共有または非共有 (ローカルのみ) として設定すると、設定する必要のあるパラメーターが決まります。キャッシュストア設定でパラメーターの組み合わせが正しくないと、データ損失やパフォーマンスの問題が発生することがあります。

    たとえば、キャッシュストアがノードにローカルにある場合は、起動時に状態をフェッチし、パージする方が理にかなっています。しかし、キャッシュストアが共有されている場合は、起動時に状態をフェッチしたり、パージしたりしないでください。

ローカル (非共有) のファイルストア

<persistence passivation="false">
   <file-store shared="false"
               path="${java.io.tmpdir}">
      <write-behind modification-queue-size="123" />
   </file-store>
</persistence>

共有カスタムキャッシュストア

<local-cache name="myCustomStore">
   <persistence passivation="false">
      <!-- Specifies the fully qualified class name of a custom cache store. -->
      <store class="org.acme.CustomStore"
             shared="true"
             segmented="true">
         <write-behind modification-queue-size="123" />
         <!-- Sets system properties for the custom cache store. -->
         <property name="myProp">${system.property}</property>
      </store>
   </persistence>
</local-cache>

単一ファイルストア

ConfigurationBuilder builder = new ConfigurationBuilder();
builder.persistence()
      .passivation(false)
      .addSingleFileStore()
         .preload(true)
         .shared(false)
         .location(System.getProperty("java.io.tmpdir"))
         .async()
            .enabled(true)

参照資料

7.1.2. ファイルベースのキャッシュストアのグローバル永続場所の設定

Data Grid は、グローバルファイルシステムの場所を使用して、データを永続ストレージに保存します。

重要

グローバルの永続場所は各 Data Grid インスタンスに固有の必要があります。複数のインスタンス間でデータを共有するには、共有の永続的な場所を使用します。

Data Grid サーバーは、$RHDG_HOME/server/data ディレクトリーをグローバルの永続場所として使用します。

カスタムアプリケーションと global-state に組み込まれたライブラリーとして Data Grid を使用している場合、グローバル永続場所はデフォルトで user.dir システムプロパティーに設定されます。このシステムプロパティーは、通常、アプリケーションが開始するディレクトリーを使用します。適切な場所を使用するようにグローバル永続の場所を設定する必要があります。

宣言型設定

<cache-container default-cache="myCache">
   <global-state>
      <persistent-location path="example" relative-to="my.data"/>
   </global-state>
   ...
</cache-container>

new GlobalConfigurationBuilder().globalState().enable().persistentLocation("example", "my.data");

ファイルベースのキャッシュストアおよびグローバル永続の場所

ファイルベースのキャッシュストアを使用する場合は、必要に応じてストレージのファイルシステムディレクトリーを指定できます。絶対パスが宣言されない限り、ディレクトリーは常にグローバル永続の場所と相対的になります。

たとえば、以下のようにグローバル永続の場所を設定します。

<global-state>
   <persistent-location path="/tmp/example" relative-to="my.data"/>
</global-state>

次に、以下のように myDataStore という名前のパスを使用する Single File キャッシュストアを設定します。

<file-store path="myDataStore"/>

この場合、設定では /tmp/example/myDataStore/myCache.dat に Single File の File キャッシュストアが作成されます。

グローバルの永続場所外にある絶対パスを設定しようとし、global-state が有効になっている場合は、Data Grid は以下の例外を出力します。

ISPN000558: "The store location 'foo' is not a child of the global persistent location 'bar'"

7.1.3. パッシベーション

パッシベーションは、これらのエントリーをメモリーからエビクトする際に、ストアにエントリーを書き込むように Data Grid を設定します。この方法により、パッシベーションは、インメモリーまたはキャッシュストアのいずれかによって単一のエントリーのコピーのみが維持されるようになります。これにより、不要な書き込みや永続ストレージへのコストがかかる可能性があります。

アクティベーションとは、パッシベートされたエントリーにアクセスしようとすると、キャッシュストアからメモリーにエントリーを復元するプロセスのことです。このため、パッシベーションを有効にすると、CacheWriter インターフェイスと CacheLoader インターフェイスの両方を実装するキャッシュストアを設定して、永続ストレージからエントリーを書き込み、読み込めるようにします。

Data Grid がキャッシュからエントリーをエビクトすると、エントリーがパッシベートされてからキャッシュストアにエントリーを保存するようキャッシュリスナーに通知します。Data Grid がエビクトされたエントリーへのアクセス要求を取得すると、キャッシュストアからエントリーをメモリーにロードし、エントリーがアクティブになるキャッシュリスナーに通知します。

注記
  • パッシベーションは、Data Grid 設定の最初のキャッシュローダーを使用し、その他はすべて無視します。
  • パッシベーションは以下ではサポートされません。

    • トランザクションストア。パッシベーションは、実際の Data Grid コミット境界の範囲外のストアからエントリーを作成し、削除します。
    • 共有ストア。共有キャッシュストアでは、他の所有者に対して常にストアにエントリーが存在する必要があります。そのため、エントリーを削除できないため、パッシベーションはサポートされません。

トランザクションストアまたは共有ストアでパッシベーションを有効にすると、Data Grid は例外を出力します。

7.1.3.1. パッシベーションおよびキャッシュストア

無効のパッシベーション

メモリーのデータへの書き込みにより、永続ストレージが書き込まれます。

Data Grid がデータをメモリーからエビクトする場合、永続ストレージのデータにはメモリーからエビクトされるエントリーが含まれます。このようにして、永続ストレージはインメモリーキャッシュのスーパーセットになります。

エビクションを設定しない場合、永続ストレージのデータはメモリーにデータのコピーを提供します。

有効のパッシベーション

Data Grid は、メモリーからデータをエビクトする場合にのみ、データを永続ストレージに追加します。

Data Grid がエントリーをアクティベートすると、メモリーのデータが復元され、永続ストレージからデータが削除されます。これにより、永続ストレージのメモリーおよびデータ内のデータは、データセット全体のサブセットを切り離し、2 つの間の交差はありません。

注記

共有ストレージのエントリーは、共有キャッシュストアの使用時に古くなる可能性があります。これは、Data Grid はアクティブ時に共有キャッシュストアからパッシベートされたエントリーを削除しないため発生します。

値はメモリーで更新されますが、以前にパッシベートされたエントリーは、古い値で永続ストレージに残ります。

以下の表は、一連の操作後のメモリーおよび永続ストレージのデータを示しています。

操作無効のパッシベーション有効のパッシベーション共有キャッシュストアでパッシベーションが有効になっている

k1 を挿入します。

Memory: k1
Disk: k1

Memory: k1
Disk: -

Memory: k1
Disk: -

k2 を挿入します。

Memory: k1, k2
Disk: k1, k2

Memory: k1, k2
Disk: -

Memory: k1, k2
Disk: -

エビクションスレッドが実行され、k1 をエビクトします。

Memory: k2
Disk: k1, k2

Memory: k2
Disk: k1

Memory: k2
Disk: k1

k1 の読み取り

Memory: k1, k2
Disk: k1, k2

Memory: k1, k2
Disk: -

Memory: k1, k2
Disk: k1

エビクションスレッドが実行され、k2 をエビクトします。

Memory: k1
Disk: k1, k2

Memory: k1
Disk: k2

Memory: k1
Disk: k1, k2

k2 を削除します。

Memory: k1
Disk: k1

Memory: k1
Disk: -

Memory: k1
Disk: k1

7.1.4. キャッシュローダーおよびトランザクションキャッシュ

トランザクション操作をサポートする JDBC 文字列ベースのキャッシュのみ。キャッシュをトランザクションとして設定する場合は、transactional=true を設定して、永続ストレージのデータをメモリー内のデータと同期させる必要があります。

他のすべてのキャッシュストアでは、Data Grid はトランザクション操作でリストキャッシュローダーをエンリスト化しません。これにより、メモリー内のデータの変更中にトランザクションが正常に実行されたものの、キャッシュストアのデータへの変更が完全に適用されない場合は、データの不整合が生じる可能性があります。この場合、手動リカバリーはキャッシュストアでは機能しません。

7.1.5. セグメント化されたキャッシュストア

キャッシュストアは、キーがマップされるハッシュ空間セグメントにデータを編成できます。

セグメント化ストアは、一括操作の読み取りパフォーマンスを向上させます。たとえば、データ (Cache.sizeCache.entrySet.stream) をストリーミングし、キャッシュを事前読み込み、状態遷移操作を行います。

ただし、セグメントストアを使用すると、書き込み操作のパフォーマンスが低下する可能性があります。このパフォーマンス損失は、トランザクションまたはライトビハイストアで実行可能なバッチ書き込み操作に対して特に該当します。このため、セグメント化されたストアを有効にする前に、書き込み操作のオーバーヘッドを評価する必要があります。書き込み操作のパフォーマンスが大幅に低下した場合、一括読み取り操作のパフォーマンスは許容できない場合があります。

重要

キャッシュストア用に設定するセグメント数は、clustering.hash.numSegments パラメーターと Data Grid 設定で定義するセグメントの数と一致している必要があります。

セグメント化されたキャッシュストアを追加した後に設定の numSegments パラメーターを変更すると、Data Grid はそのキャッシュストアからデータを読み取ることができません。

参照資料

キーの所有者

7.1.6. ファイルシステムベースのキャッシュストア

多くの場合、ファイルシステムベースのキャッシュストアは、サイズや時間の制限を超えた、メモリーからオーバーフローするデータのローカルキャッシュストアに適しています。

警告

ファイルシステムベースのキャッシュストアは、NFS、Microsoft Windows、Samba 共有などの共有ファイルシステムで使用しないでください。共有ファイルシステムは、ファイルロック機能を提供しないため、データが破損する可能性があります。

同様に、共有ファイルシステムはトランザクションではありません。共有ファイルシステムとトランザクションキャッシュの使用を試みると、コミットフェーズでファイルへの書き込み時に回復不可能な障害が発生する可能性があります。

7.1.7. ライトスルー

書き込みは、メモリーへの書き込みおよびキャッシュストアへの書き込みが同期されるキャッシュ書き込みモードです。クライアントアプリケーションがキャッシュエントリーを更新すると、Cache.put() を呼び出すと、Data Grid はキャッシュストアを更新するまで呼び出しを返しません。このキャッシュ書き込みモードを使用すると、クライアントスレッドの境界内にあるキャッシュストアに更新されます。

Write-through モードの主な利点は、キャッシュとキャッシュストアが同時に更新されるので、キャッシュストアが常にキャッシュと一貫性を持たせるようにします。

ただし、Write-Through モードは、キャッシュストアにアクセスして更新を行う必要がないため、キャッシュ操作のレイテンシーが直接追加されるため、パフォーマンスが低下する可能性があります。

キャッシュストアに Write-Behind モードを明示的に設定しない限り、Data Grid はデフォルトで Write-Through モードに設定されます。

ライトスルー設定

<persistence passivation="false">
   <file-store fetch-state="true"
               read-only="false"
               purge="false" path="${java.io.tmpdir}"/>
</persistence>

参照資料

Write-Behind

7.1.8. Write-Behind

write-Behind は、メモリーへの書き込みが同期され、キャッシュストアへの書き込みが非同期になるキャッシュ書き込みモードです。

クライアントが書き込み要求を送信すると、Data Grid はこれらの操作を変更キューに追加します。Data Grid は、呼び出しスレッドがブロックされず、操作がすぐに完了しないように、キューに参加する際に操作を処理します。

変更キューの書き込み操作の数がキューのサイズを超えた場合、Data Grid はこれらの追加操作をキューに追加します。ただし、これらの操作は、すでにキューにある Data Grid が処理するまで完了しません。

たとえば、Cache.putAsync を呼び出すとすぐに戻り、変更キューが満杯でない場合はすぐに Stage も完了します。変更キューが満杯であったり、Data Grid が書き込み操作のバッチを処理している場合、Cache.putAsync は即座に戻り、Stage は後で完了します。

write-Behind モードは、基礎となるキャッシュストアへの更新が完了するまで待機する必要がないため、Write-Through モードよりもパフォーマンス上のメリットが得られます。ただし、キャッシュストアのデータは、変更キューが処理されるまでキャッシュ内のデータと一貫性がありません。このため、Write-Behind モードは、非共有およびローカルのファイルシステムベースのキャッシュストアなど、低レイテンシーでキャッシュストアに適しています。ここでは、キャッシュへの書き込みとキャッシュストアの書き込みの間隔が可能な限り小さくなります。

ライトビハインドの設定

<persistence passivation="false">
   <file-store fetch-state="true"
               read-only="false"
               purge="false" path="${java.io.tmpdir}">
   <write-behind modification-queue-size="123"
                 fail-silently="true"/>
   </file-store>
</persistence>

上記の設定例は fail-silently パラメーターを使用して、キャッシュストアが利用できないか、変更キューが満杯の場合に何が起こるかを制御します。

  • fail-silently="true" の場合、Data Grid は WARN メッセージをログに記録し、書き込み操作を拒否します。
  • fail-silently="false" の場合、書き込み操作中にキャッシュストアが利用できないことを検知すると、Data Grid は例外を出力します。同様に、変更キューがいっぱいになると、Data Grid は例外を出力します。

    Data Grid の再起動および書き込み操作が変更キューに存在すると、データ喪失が発生する可能性があります。たとえば、キャッシュストアはオフラインになりますが、キャッシュストアが利用できないことを検知するのにかかると、フルではないため、変更キューへの書き込み操作が追加されます。Data Grid が再起動するか、キャッシュストアがオンラインに戻る前に利用できなくなると、永続化していないため、変更キューへの書き込み操作が失われます。

参照資料

ライトスルー