ApacheIgniteトランザクションアーキテクチャ

この記事では、トランザクションがでどのように機能するかを見てみましょうアパッチのIgniteをKey-Valueストレージの概念については詳しく説明しませんが、Igniteでの実装方法について説明します。アーキテクチャの概要から始めて、トレースを使用してトランザクションロジックの要点を説明しましょう。簡単な例を使用すると、トランザクションがどのように機能するか(および、どのような理由でトランザクションが機能しないか)がわかります。



必要なものは別として:Apache Ignite Cluster



Igniteにおけるクラスタは、一連のあるサーバクライアントサーバノードがリング状に論理構造に結合され、クライアントノードは、対応するサーバ・ノードに接続されているノード。クライアントノードとサーバーノードの主な違いは、前者はデータを保存しないことです。







論理的な観点から、データはパーティションに属します。パーティションは、いくつかのアフィニティ関数に従って、ノード間で分散されますIgniteでのデータ分散の詳細)。プライマリ(プライマリ)パーティションには、コピー(バックアップ)を含めることができます







ApacheIgniteでのトランザクションのしくみ



Apache Igniteのクラスターアーキテクチャは、トランザクションメカニズムに特定の要件を課します。分散環境でのデータの一貫性です。これは、異なるノードにあるデータは、ACIDの原則の観点から全体的に変更する必要があることを意味しますあなたがやりたいことをするために利用できるプロトコルはたくさんあります。Apache Igniteは、次の2つの段階で構成される2フェーズコミットアルゴリズム使用します。



  • 準備する;
  • コミット;


トランザクションの分離レベル、ロックを取得するメカニズム、およびその他の多くのパラメーターによっては、フェーズの詳細が変更される場合があることに 注意してください



次のトランザクションを例として使用して、両方のフェーズがどのように行われるかを見てみましょう。



Transaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED);
client.cache(DEFAULT_CACHE_NAME).put(1, 1);
tx.commit();


準備フェーズ



  1. — (near node Apache Ignite) — prepare- , primary- , .
  2. primary- Prepare- backup-, , . backup- .
  3. backup- Acknowledge- primary-, , , , .




Commit



次の図に示すように、プライマリパーティションを含むすべてのノードから確認メッセージを受信した後、トランザクションコーディネーターノードはコミットメッセージを送信します。







トランザクションコーディネーターがすべての確認メッセージを受信した瞬間に、トランザクションは完了したと見なされます。



理論から実践へ



トランザクションのロジックを検討するために、トレースに移りましょう。



Apache Igniteでトレースを有効にするには、次の手順に従います。
  • ignite-opencensusモジュール有効にして、クラスター構成でOpenCensusTracingSpiをtraceingSpiとして設定しましょう

    <bean class="org.apache.ignite.configuration.IgniteConfiguration">
        <property name="tracingSpi">
            <bean class="org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi"/>
        </property>
    </bean>
    


    または



    IgniteConfiguration cfg = new IgniteConfiguration();
    
    cfg.setTracingSpi(
        new org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi());
    


  • :



    JVM_OPTS="-DIGNITE_ENABLE_EXPERIMENTAL_COMMAND=true" ./control.sh --tracing-configuration set --scope TX --sampling-rate 1
    






    ignite.tracingConfiguration().set(
                new TracingConfigurationCoordinates.Builder(Scope.TX).build(),
                new TracingConfigurationParameters.Builder().
                        withSamplingRate(SAMPLING_RATE_ALWAYS).build());
    


    :



    • API
      JVM_OPTS="-DIGNITE_ENABLE_EXPERIMENTAL_COMMAND=true"
    • sampling-rate , , . , .
    • , SPI, . , , .


  • PESSIMISTIC, SERIALIZABLE .



    Transaction tx = client.transactions().txStart(PESSIMISTIC, SERIALIZABLE);
    client.cache(DEFAULT_CACHE_NAME).put(1, 1);
    tx.commit();




レッツにターンGridGainコントロールセンター(ツールの詳細な概要)、そして得られたスパンツリーを見てみましょう: 図では、我々は見ることができる取引の開始時に作成したトランザクションのルートスパン、()TxStart呼び出し、スポーン2つの条件付きスパン・グループ。:











  1. put()操作によって開始されたロックキャプチャマシン:

    1. transactions.near.enlist.write
    2. transactions.colocated.lock.map
  2. transactions.commit, tx.commit(), , , — prepare finish Apache Ignite (finish- commit- ).


次に、トランザクションの準備フェーズを詳しく見てみましょう。このフェーズでは、トランザクションコーディネーターノード(Apache Ignite用語ではnear-node)から開始して、transactions.near.preparespanを生成します。



プライマリパーティションに到達すると、prepare-requestはtransactions.dht.prepareスパンの作成をトリガーし、その中でprepare-requestsはtx.process.prepare.reqバックアップに送信され、そこでtx.dht.process.prepare.responseによって処理されて送信されます。プライマリパーティションに戻ります。プライマリパーティションは、スパンtx.near.process.prepare.responseを作成する途中で、トランザクションコーディネーターに確認メッセージを送信します。この例の終了フェーズは準備フェーズと同様であるため、詳細な分析の必要がありません。



スパンのいずれかをクリックすると、対応するメタ情報が表示されます。







したがって、たとえば、ルートトランザクションスパンの場合、クライアントノード0eefdで作成されたことがわかります。



また、通信プロトコルのトレースを有効にすることで、トランザクショントレースの粒度を高めることができます。



トレースパラメータの設定
JVM_OPTS="-DIGNITE_ENABLE_EXPERIMENTAL_COMMAND=true" ./control.sh --tracing-configuration set --scope TX --included-scopes Communication --sampling-rate 1 --included-scopes COMMUNICATION




       ignite.tracingConfiguration().set(
           new TracingConfigurationCoordinates.Builder(Scope.TX).build(),
           new TracingConfigurationParameters.Builder().
               withIncludedScopes(Collections.singleton(Scope.COMMUNICATION)).
               withSamplingRate(SAMPLING_RATE_ALWAYS).build())








これで、クラスターノード間のネットワークを介したメッセージの送信に関する情報にアクセスできるようになりました。これは、たとえば、潜在的な問題がネットワーク通信の微妙な違いによって引き起こされたかどうかの質問に答えるのに役立ちます。詳細については詳しく説明しません。多くのsocket.writeスパンとsocket.readスパンが、それぞれメッセージの書き込みと読み取りを担当していることに注意してください。



例外処理とクラッシュリカバリ



したがって、Apache Igniteでの分散トランザクションプロトコルの実装は標準的なものに近く、選択したトランザクション分離レベルに応じて、適切な程度のデータ整合性を取得できることがわかります。明らかに、悪魔は細部にあり、論理の大きな層は上で分析された資料の範囲外のままでした。たとえば、参加しているノードが落下した場合のトランザクションの操作と回復のメカニズムについては考慮していません。これを今すぐ修正します。



Apache Igniteのトランザクションのコンテキストでは、3つのタイプのノードを区別できることを前述しました。



  • トランザクションコーディネーター(ノードの近く);
  • 対応するキーのプライマリノード(プライマリノード)。
  • バックアップキーパーティションのあるノード(バックアップノード)。


トランザクション自体の2つのフェーズ:

  • 準備する;
  • 終了;


簡単な計算により、ノードクラッシュの6つのオプションを処理する必要があります。準備フェーズでのバックアップのフォールから、終了フェーズでのトランザクションコーディネーターのフォールまでです。これらのオプションについて詳しく見ていきましょう。



準備段階と終了段階の両方での落下バックアップ



この状況では、追加のアクションは必要ありません。データは、プライマリノードからのリバランスの一部として独立して新しいバックアップノードに転送されます。







準備フェーズでのプライマリノードの落下



一貫性のないデータを受信するリスクがある場合、トランザクションコーディネーターは例外をスローします。これは、トランザクションを再開するか、クライアントアプリケーションに問題を解決する別の方法を決定するために、制御を転送するためのシグナルです。







終了フェーズでのプライマリノードのフォール



この場合、トランザクションコーディネーターは、追加のNodeFailureDetectionメッセージを待機します。その後、データがバックアップパーティションに書き込まれたかどうかを、トランザクションの正常な完了を判断できます。







トランザクションコーディネーターの堕落



最も興味深いケースは、トランザクションコンテキストの喪失です。このような状況では、プライマリノードとバックアップノードがローカルトランザクションコンテキストを相互に直接交換し、それによってグローバルコンテキストを復元します。これにより、コミットを検証する決定を下すことができます。たとえば、ノードの1つが完了メッセージを受信しなかったと報告した場合、トランザクションはロールバックされます。







概要



上記の例では、トランザクションのフローを調べ、内部ロジックを詳細に示すトレースを使用して説明しました。ご覧のとおり、Apache Igniteでのトランザクションの実装は、2フェーズコミットの従来の概念に近く、ロックを取得するメカニズム、障害後の回復機能、トランザクションタイムアウトロジックに関連するトランザクションパフォーマンスの領域でいくつかの調整が行われています。



All Articles