分散ロッキング

Mule Runtime Engine では、Mule コンポーネント内のリソースへのアクセスを同期するためのロックを作成できます。リソースへの同時アクセスを管理するため、Mule はロックファクトリーを提供します。このロックファクトリーに、ユーザーはスクリプトを使用してプログラムでアクセスしたり、​Java SDK​ で作成したカスタム拡張機能でアクセスしたりできます。

Mule ロックファクトリーで作成したロックは、1 つのサーバーまたはサーバーのクラスターを使用するデプロイメントモデルでシームレスに機能します。つまり、複数のスレッドで同じフローを実行しているサーバーや、同じアプリケーションを実行しているクラスター環境がある場合、Mule ロックを使用してリソースの同期を保証できます。また、Mule ロッキングシステムは、共有されたロックにアクセスするための簡単な API を提供します。

LockFactory​ は、​java.util.concurrent.Lock​ を実装する ​Lock​ を作成しますが、メソッド ​newCondition()​ をサポートしません。​newCondition()​ を使用すると、Mule は ​UnsupportedOperationException​ をスローします。Mule は、​lockInterruptibly()​ や ​tryLock()​ など、ロックと連動する他のメソッドをサポートします。

ロックを作成する

ロックを作成するには、次の手順を実行します。

  1. 挿入を使用して ​LockFactory​ にアクセスします。
    Java SDK で拡張機能を作成している場合、いずれかの操作でロッキングが必要になったときは、​LockFactory​ をクラスに挿入します。

  2. LockFactory​ を使用して、ロックの作成を開始します。
    以下のサンプルコードを参照してください。これは、Mule ロックを使用してコードアクセスを管理する、つまり、(Scatter-Gather スコープや異なるクラスターノードなどで) 操作を並列で実行するときの同期の問題を回避する拡張操作を宣言しています。

  3. 作成するロックの識別子を使用します。
    識別子を使用すると、異なるスレッド間で同じロックインスタンスを明示的に共有することなく、それらのスレッドから 1 つのロックにアクセスできます。

このロックは ​java.util.concurrent.Lock​ インターフェースを実装しているため、メソッド ​lock()​ をコールすると、スレッドはロックを取得するまで待機します。

ロックを作成したら、重要なコードセクションを実行できますが、このロックを待機している他のスレッドでのデッドロックを回避するためのロックリリースメカニズムも作成する必要があります。これを実現するには、​lock.unlock​ コールを ​finally​ ブロックで囲みます。

public class ClusterOperations {

  @Inject
  private LockFactory lockFactory;

  public void sharedResourceOperation() {
      Lock lock = lockFactory.createLock("sharedResourceId");
      lock.lock();
      try {
          // Lock acquired, execute critical code.
      } finally {
          lock.unlock();
      }
  }
}

スクリプティングを使用したロックの作成

スクリプティング拡張機能を使用している場合は、まずレジストリにアクセスして ​LockFactory​ を取得してから、スクリプティングコードを使用してロックを作成します。以下の例は Groovy を使用して前の例と同じ結果を達成します。つまり、​LockFactory​ を取得し (この場合は ​Registry​ を使用します)、特定の ID 用の新しい ​Lock​ を作成し、ロックを取得するまで待機して、重要なコードを実行した後、ロックをリリースします。

lockFactory = registry.lookupByName("_muleLockFactory").get()
lock = lockFactory.createLock("sharedResourceId")
lock.lock()
try {
	// Lock acquired, execute critical code.
} finally {
	lock.unlock()
}

操作間でのロックの共有

ロッキングは、同じ操作を実行する複数のスレッドのロックを作成するのに役立つだけでなく、並列で実行される可能性がある異なる操作で使用することもできます。同じロック ID を使用してさまざまな操作でロックを作成すると、それらの操作で同じロックへのアクセス権を取得できます。次のコードサンプルは、同じロック ID を使用してロックを作成する 2 つのカスタム操作を示しています。

public class ClusterOperations {

  @Inject
  private LockFactory lockFactory;

  public void sharedResourceOperationA() {
      Lock lock = lockFactory.createLock("sharedResourceId");
      lock.lock();
      try {
          // Lock acquired, execute critical code.
      } finally {
          lock.unlock();
      }
  }

  public void sharedResourceOperationB() {
      Lock lock = lockFactory.createLock("sharedResourceId");
      lock.lock();
      try {
          // Lock acquired, execute critical code.
      } finally {
          lock.unlock();
      }
  }
}