はじめに
下記の記事で触れたように、Couchbase Server Java SDKには、分散トランザクションを実現するにあたり、クリーンアップメカニズムが含まれます。
まず、上記の記事でも触れた基本的な内容を振り返るところから始めます。
クリーンアップの基本
失敗したトランザクションが、他のトランザクションを無期限にブロックしないようにするため、Couchbase SDKは、「クリーンアップ」と呼ばれるメカニズムを提供します。
トランザクションは、失敗が発生したときに、まず自分自身でクリーンアップしようとします。
非同期クリーンアップ
アプリケーションのクラッシュなどの原因で、そのトランザクション自身によってクリーンアップされなかった、「ロスト」トランザクションが作成される状況があります。
そのためクリーンアップメカニズムには、Transaction
オブジェクトの作成時に開始される非同期クリーンアップのためのバックグラウンドプロセスが含まれます。このプロセスは、任意のアプリケーションによって作成された、すべてのバケットにおける期限切れのトランザクションをスキャンします。つまり、アプリケーションは、別のアプリケーションによって作成されたトランザクションをクリーンアップするケースも起こりえますが、そのことは問題となりません。
逆に開発中など、アプリケーションが継続的に実行されていないケースでは、停止したアプリケーションプロセスによってクリーンアップされなかったトランザクション情報をクリーンアップするためにアプリケーションを起動することも考えられます。
アプリケーションが実行されていない期間、非同期クリーンアップは実行されていないことに注意する必要があります。これは、単体テスト実行の場合に顕著になります。このことが問題となる場合、非同期クリーンアップが常に実行されていることを確実にするために、 Transactions
オブジェクトをオープンするだけの単純なアプリケーションを実行しておくことが考えられます。
非同期クリーンアップ詳細
クリーンアップは、各バケットで実行されます。
Transactions
オブジェクトを作成すると、バックグラウンドクリーンアップタスクが生成されます。このタスクの役割は、期限切れのトランザクションを定期的にスキャンしてクリーンアップすることです。
具体的には、バケットに含まれるアクティブトランザクションレコード(ATR)をスキャンすることによって行われます。ATRは、トランザクションが正常に完了した後のある時点、またはクリーンアップ中に削除されます。バケット上のすべてのATRは、すべてのクリーンアッププロセスを実行している全てのクライアントから削除される可能性があります(つまり、処理は分散されます)。
同じクラスターに接続してトランザクションを実行しているすべてのアプリケーションは、クラスター内の各バケットに作成される「_txn:client-record
」メタデータドキュメントのクリーンアップを(ロータッチ通信プロトコルを介して)共同で実行します。このドキュメントは可視的ですが、外部から変更してはいけません。
バックグラウンドプロセスの負荷と設定
デフォルト設定は、スキャンプロセスに必要なバックグラウンド読み取りによる影響を無視できるレベルに抑えながら、期限切れのトランザクションを適度に迅速に検出できるように調整されています。具体的には、デフォルト設定では、60秒以内に期限切れのトランザクションが検出され、通常1秒あたりの読み取り数は20未満です。これがクラスターのパフォーマンスに影響を与える可能性は低いですが、設定は必要に応じて調整できます。
クリーンアップ設定
クリーンアップ設定は次のように構成できます。
cleanupWindow
デフォルト値:60秒
この設定により、クリーンアップの「実行」の長さが決まります。つまり、このクライアントがATRドキュメントのサブセットをチェックする頻度です。
アプリケーションで、この設定を変更することができます。デフォルトの値は控えめに設定されています。この値を減らすと、有効期限トランザクションがより迅速に検出されるかわり、スキャンプロセスに使用される1秒あたりの読み取り数が増えるというトレードオフが発生します。
cleanupLostAttempts
デフォルト値:true
この設定は、クライアントが上記の分散クリーンアッププロセスに参加するスレッドを実行するかどうかを示します。
有効のままにしておくことが強く推奨されます。
cleanupClientAttempts
デフォルト値:true
この設定は、クライアント自身によって作成されたトランザクションをクリーンアップするためにスレッドを実行しているかどうかを示します。
クライアントは、自身が作成したトランザクションを優先的に処理することを目的とし、強制された場合(たとえば、アプリケーションのクラッシュ時)にのみ分散クリーンアッププロセスに参加します。
有効のままにしておくことが強く推奨されます。
クリーンアップ監視
アプリケーションがクリーンアップを監視したい場合は、次のように、イベントをサブスクライブできます。
cluster.environment().eventBus().subscribe(event -> {
if (event instanceof TransactionCleanupAttempt || event instanceof TransactionCleanupEndRunEvent) {
// log this event
}
});
TransactionCleanupEndRunEvent
クリーンアップが終了するたびに発生し、クリーンアップ実行からの統計情報が含まれます。(実行は通常、デフォルト構成で約60秒ごとです。)
TransactionCleanupAttempt
このプロセスによって期限切れのトランザクションが発見され、クリーンアップの試みが行われたときにイベントが発生します。これには、その試行が成功したかどうかと、その試行に関連するログが含まれます。
さらに、クリーンアップが有効期限を過ぎて2時間以上経過したトランザクションのクリーンアップに失敗した場合にも、このTransactionCleanupAttempt
イベントが、(デフォルトのDEBUG
ではなく)WARN
レベルで発生します。
この場合、イベントがWARN
レベルで発生するため、典型的な環境では、イベントがログに記録されると考えられます。
何らかの外部要因(ノードダウンなど)、クリーンアップが失敗する正当な理由がない場合、問題として扱う(サポートに報告する等)日ことが推奨されます。