32 リエントラント・コールに対する制約

サービスのリエントラント・コールには制約があり、サービスのスレッド間でコールを行うためのガイドラインがあります。

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

リエントラント・コールに対する制約の概要

Coherenceでは、リエントラント・コールがサポートされていません。リエントラント・サービス・コールは、サービス・スレッドがリクエストを処理しようとするときにその同じサービスに対してリクエストが行われると発生します。サービスに対するリクエストはすべてインバウンド・キューを使用して配信され、Coherenceはリクエストごとに1スレッドのモデルを使用するため、リエントラント・リクエストのそれぞれが他のスレッドを消費することになります(レスポンスを待っている間はコール側のスレッドがブロックします)。用語としては再帰型に似ていますが、概念が異なるため区別する必要があります。

Coherenceのアーキテクチャは、サービスの集合に基づいています。Coherenceの各サービスは、関連付けられた構成とともに、サービスを実装するCoherenceコードで構成されています。サービスは、リクエストを受信してレスポンスを返すキューが関連付けられているスレッドの割当てプールで実行されます。

リエントラント、サービスおよびサービス・スレッド

サービスは、サービス名とサービス・タイプ(起動、レプリケート、分散など)の一意の組合せとして定義されます。アプリケーションは、サービスとサービス・タイプの間でサービス・コールを行うことができます。たとえば、分散サービスDist-CustomersからDist-Inventoryという名前の分散サービスをコールしたり、Dist-Customersという名前の分散サービスからRepl-Catalogという名前のレプリケート・サービスをコールできます。サービス名は、<service-name>要素を使用して、キャッシュ構成ファイルで構成されます。

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

オブジェクトの親子関係

Coherenceの現在の実装では、コールがローカルであるかリモートであるかは重要ではありません。このため、親子関係の構築の効率化をサポートするキー・アソシエーションの使用法が複雑になります。キー・アソシエーションを使用して親オブジェクトとそのすべての子オブジェクトを共存させる場合は、親オブジェクトにEntryProcessorを送信して、そのEntryProcessorで(ローカルの)子オブジェクトを把握することはできません。これは、子オブジェクトが処理中である場合も同様です。

親オブジェクトと子オブジェクトの両方にアクセスするには、次のいずれかの方法を使用できます。

  • 子オブジェクトを親オブジェクトに埋め込みます(集約パターンを使用)、または

  • サーバー側のバッキング・マップへの直接アクセスを使用します(安全に実行するには高度な知識が必要です)、または

  • 別のサービス(たとえば、PartitionedService.getKeyOwnerを使用することでターゲット指定される起動)でロジックを実行し、そのサービスからNamedCacheインタフェースを使用してデータにアクセスします、または

  • リエントラント・コールが可能な別のサービスに子オブジェクトを配置します(ただし、複数の異なるキャッシュ・サービスのパーティション間にはアフィニティがないためネットワーク・アクセスが発生します)。

ほとんどの使用状況では、集約パターンの使用が最適な方法になります。ただし、この方法が(サイズの制限などによって)現実的でなく、クライアント/サーバー・モデルを使用しないで親オブジェクトと子オブジェクトの両方にアクセスする必要がある場合には、起動サービスを使用する方法が、大半の用途で最適な解決方法になります。

デッドロックの回避

リエントラントが許容される場合も、スレッド・プールの飽和および壊滅的なデッドロックが発生する可能性を慎重に回避する必要があります。たとえば、サービスAがサービスBをコールし、サービスBがサービスAをコールする場合、同時コールが多数発生して、スレッド・プールで使用される構成済のスレッドが最大になり、一種のデッドロックが発生する可能性があります。従来のロックと同様、アクセスに順序付けすること(たとえば、サービスAはサービスBのコールが可能であるが、サービスBはサービスAをコールできないようにする)が回避に役立ちます。また、動的なスレッド・プールに依存することが役立つ場合もあります。

したがって、次のようになります。

  • サービスAからサービスAをコールすることは許されません

  • サービスAからサービスBをコールし、サービスBからサービスAをコールすることは技術的には可能ですが、デッドロックが発生しやすくなるため、可能なかぎり回避する必要があります。

    • サービスAがサービスBを、サービスBがサービスCを、サービスCがサービスAをコールすることは、同様に制限されます

  • サービスAからサービスBをコールすることは許されます

    • サービスAがサービスBを、サービスBがサービスCを、サービスAがサービスCをコールすることは、同様に許されます

サービス・スレッドは、Coherence APIリクエストの実現に関連するスレッドとして定義されます。サービス・スレッドは、次のエンティティのいずれかを起動できます。

  • マップ・リスナー

  • メンバーシップ・リスナー

  • カスタムのシリアライズ/デシリアライズ(ExternalizableLite実装など)

  • バッキング・マップ・リスナー

  • CacheLoader/CacheStoreモジュール

  • 問合せロジック(AggregatorsFiltersValueExtractorsComparatorsなど)

  • エントリ・プロセッサ

  • トリガー

  • InvocationService起動可能ファイル

これらのエンティティは、自己のサービスに対するリエントラント・コールを行いません。

リエントラントおよびリスナー

メンバーシップ・リスナーは、クラスタまたは特定のサービスに参加するアクティブなメンバー・セットを監視できます。メンバーシップ・リスナーのスレッディングは複雑になる場合があるため、メンバー・リスナーからCoherenceのサービスへのリエントラント・コールは使用しないでください。