実行エンジン

このバージョンの Mule は、拡張サポートが終了する 2023 年 5 月 2 日にその すべてのサポート​が終了しました。

このバージョンの Mule を使用する CloudHub には新しいアプリケーションをデプロイできなくなります。許可されるのはアプリケーションへのインプレース更新のみになります。

標準サポートが適用されている最新バージョンの Mule 4 にアップグレード​することをお勧めします。これにより、最新の修正とセキュリティ機能強化を備えたアプリケーションが実行されます。

Mule Runtime Engine は、非ブロックで非同期の実行用に調整されたリアクティブ実行エンジンを実装します。
リアクティブプログラミングの詳細は、​https://en.wikipedia.org/wiki/Reactive_programming を参照してください。

タスク指向の実行モデルでは、非ブロック I/O を高い同時実行レベルで透過的に活用できます。つまり、ユーザーはフローのスレッドや非同期性を考慮する必要がありません。Mule フロー内の各操作は実行に関するメタデータを提供するタスクで、Mule はそのメタデータに基づいて調整の決定を行います。

Mule イベントプロセッサーは、CPU Intensive (CPU 負荷大)、CPU Light (CPU 負荷小)、I/O Intensive (I/O 負荷大) のいずれの操作を行うかを Mule に示します。これらのワークロード種別によって、Mule はさまざまなワークロードを調整することができ、最適なパフォーマンスを実現するためにユーザーがスレッドプールを手動で管理する必要がなくなります。Mule は、システム内で使用可能なリソース (メモリや CPU コアなど) を調査し、スレッドプールを自動的に調整します。

処理種別

Mule イベントプロセッサーは、実行する処理の種類を Mule に示します。これは、次のいずれかです。

  • CPU Light (CPU 負荷小)
    短時間の操作 (約 10 ミリ秒) または非ブロック I/O 用。たとえば、ロガー (​logger​) や HTTP 要求操作 (​http:request​) など。これらのタスクではブロック I/O アクティビティを実行できません。ログで該当する文字列は ​CPU_LIGHT​ と ​CPU_LIGHT_ASYNC​ です。

  • Blocking I/O (ブロック I/O)
    コール元スレッドをブロックする I/O 用。たとえば、Database Select 操作 (​db:select​) や SFTP 読み取り (​sftp:read​) など。ログで該当する文字列は ​BLOCKING​ と ​IO​ です。

  • CPU Intensive (CPU 負荷大)
    CPU の負荷が大きい計算用。通常は実行時間が 10 ミリ秒を超えます。これらのタスクでは I/O アクティビティを実行できません。たとえば Transform Message コンポーネント (​ee:transform​) など。ログで該当する文字列は ​CPU_INTENSIVE​ です。

特定のコンポーネントやモジュールがサポートする処理種別については、それらのドキュメントを参照してください。指定しない場合、デフォルトの種別は CPU Light (CPU 負荷小) です。

Mule SDK を使用して作成されたコネクタの場合は、コネクタの実装方法に基づいて SDK によって最適な処理種別が決定されます。そのメカニズムについての詳細は、​Mule SDK のドキュメント​を参照してください。

最適化

内部の最適化により、特定の条件下でのフロー実行時に、Mule がイベントプロセッサーに対して提案されている処理種別を無視することがあります。

スレッド

コンポーネントの処理種別に基づき Mule はそのコンポーネントをその種別の処理専用に調整したスレッドプールで実行します。これらのスレッドプールは Mule によって管理され、同じ Mule インスタンス内のすべてのアプリケーションで共有されます。

Mule は、起動時にシステム内で使用可能なリソース (メモリや CPU コアなど) を調査し、実行中の環境に合わせてスレッドプールを自動的に調整します。デフォルトのスレッドプール設定は、パフォーマンステストによって確立されたもので、ほとんどの状況で最適な値になっています。

異なるスレッドプールを使用することで Mule のリソース管理効率が向上し、同じ量のワークロードを処理するために必要なスレッド数 (およびそれに伴うメモリフットプリント) が大幅に削減されます。

次に、各スレッドプールの主要な側面について説明します。

CPU Light (CPU 負荷小)

CPU Light (CPU 負荷小) スレッドプールは、比較的小さくなっています (デフォルトでは使用可能なコアごとに 2 スレッド)。

CPU Light (CPU 負荷小) プロセッサーの実行以外に、このプールはフロー内のプロセッサー (ルーターを含む) 間のイベントのハンドオフと、非ブロック I/O の応答処理も実行します。

アプリケーションでスループットが落ちたり応答がなくなったりした場合は、一部のコードが CPU Light (CPU 負荷小) スレッドプールを誤用している可能性があります。この問題は、ランタイムのスレッドダンプを作成し、​WAITING​ または ​BLOCKED​ を探すか、CPU Light (CPU 負荷小) スレッド内で実行時間が長いプロセスを探すことで簡単に見つけることができます。

CPU Intensive (CPU 負荷大)

CPU Intensive (CPU 負荷大) も小さなスレッドプール (デフォルトでは使用可能なコアごとに 2 スレッド) ですが、より多くのタスクを受け付けるためのキューがあります。

IO

IO スレッドプールは、可変で必要に応じて大きくなります。

このプールで実行するタスクは、ほとんどの時間、CPU で処理されるのではなく ​WAITING​ または ​BLOCKED​ の状態でいるため、他のプールの処理と競合しません。

また、トランザクションがアクティブである場合にも (多くのトランザクションマネージャーでは同じトランザクションのすべてのステップを同じスレッドによって処理する必要があるため) ​IO​ プールが使用されます。

トランザクションがアクティブである場合、多くのトランザクションマネージャーではトランザクションのすべてのステップを 1 つのスレッドで処理する必要があるため、Mule では ​IO​ プールが使用されます。

カスタムスレッドプール

3 つの主要なスレッドプール以外に、Mule または一部のコンポーネントによって特定の目的のために次のような追加プールが作成される場合があります。

  • NIO セレクター
    非ブロック I/O を有効にします。各コネクタは、必要に応じて何個でも作成できます。

  • 繰り返しタスクプール
    一部のコネクタやコンポーネント (有効期限監視、キューコンシューマーなど) によって、繰り返しタスクを実行するための特定のプールが作成される場合があります。

プロアクターパターン

プロアクターは非同期実行のための設計パターンです。プロアクター設計パターンのしくみを理解するには、​https://en.wikipedia.org/wiki/Proactor_pattern を参照してください。

この設計パターンに従うと、すべてのタスクは各 Mule スレッドプールに対応するカテゴリに分類され、各タスクは対応するスレッドプールに送信されて実行されます。

次の例を考えてみます。フローは JSON 形式で記述された Person オブジェクトの JSON 配列を読み取り、HTTP 要求によってコンテンツをプッシュし、最初のエントリの名前を選択して追加処理を行います。

<flow>
  <sftp:read path="personsArray.json" /> (1)
  <http:request path="/persons" method="POST" /> (2)
  <set-variable variableName="firstEntryName" value="#[payload[0].name]" /> (3)
  <ee:transform ... /> (4)
  <logger message="#[vars.firstEntryName]" /> (5)
</flow>

プロアクターパターンに従うと、Mule はタスクを次のように送信します。

1 ブロック操作 (​<sftp:read>​) が IO プールで実行されます。
2 Mule は、現在のスレッドで非ブロック操作 (​<http:request>​) を実行します。フローが応答を受信すると、Mule は ​CPU_LIGHT​ (CPU 負荷小) プールに切り替えます。
3 <set-variable>​ 操作は非常に短時間なので、スレッドを切り替えず ​CPU_LIGHT​ (CPU 負荷小) のままで実行します。
4 <ee:transform>​ は計算負荷が高い変換である可能性があるため、Mule は ​CPU_INTENSIVE​ (CPU 負荷大) プールに切り替えます。
5 Logger は ​CPU_INTENSIVE​ (CPU 負荷大) のままで実行します。. スレッドの切り替えは行いません。
遅延に関する最適化のため、IO または ​CPU_INTENSIVE​ (CPU 負荷大) タスクの後に ​CPU_LIGHT​ (CPU 負荷小) タスクを実行する場合にはスレッド切り替えが省略されます。これは、その ​CPU_LIGHT​ (CPU 負荷小) タスクを実行する方がスレッド切り替えよりも負荷が小さい可能性が高いためです。

設定

Mule Runtime Engine は、起動時に CPU やメモリなどの利用可能なリソースを考慮する数式を適用して、Mule インスタンス全体のスレッドプールを自動的に設定します。

Mule Runtime Engine をオンプレミスで実行している場合、ローカル Mule インスタンスで ​MULE_HOME/conf/schedulers-pools.conf​ ファイルを編集することで、これらのグローバル数式を変更できます。ただし、このファイルの設定を編集することはお勧めしません。

MuleSoft ではデフォルト設定を使用して Mule を実行することをお勧めしているため、スレッドプール設定をカスタマイズする場合は、実際のシナリオを使用してすべてのアプリケーションで負荷テストとストレステストを実行し、同じ Mule インスタンスにデプロイされたすべてのアプリケーションへの影響を検証してください。

アプリケーションレベルでの設定

グローバル設定以外に、アプリケーションコードに次のコードを追加することで、アプリケーションレベルで各プールの設定を定義できます。

<ee:scheduler-pools gracefulShutdownTimeout="15000">
   <ee:cpu-light
           poolSize="2"
           queueSize="1024"/>
   <ee:io
           corePoolSize="1"
           maxPoolSize="2"
           queueSize="0"
           keepAlive="30000"/>
   <ee:cpu-intensive
           poolSize="4"
           queueSize="2048"/>
</ee:scheduler-pools>

アプリケーションレベルでプール設定を適用すると、Mule アプリケーション用の完全に新しいスレッドプールセットが作成されます。この設定によって ​scheduler-conf.properties​ ファイル内で設定されるデフォルト設定は変更されません。オンプレミスデプロイメントでは同じ Mule インスタンスに多くの Mule アプリケーションをデプロイできるため、特にこれが重要です。

アプリケーションレベルでスレッドプール設定をカスタマイズする場合は、実際のシナリオを使用して影響を受けるすべてのアプリケーションで負荷テストとストレステストを実行し、この設定の影響を検証してください。

CloudHub にデプロイされた Mule アプリケーションのアプリケーションレベルでプール設定を定義する場合、断片的 vCore はメモリが少ないため、ワーカーサイズに注意してください。詳細は、​「CloudHub ワーカー」​を参照してください。

バックプレッシャー管理

バックプレッシャーは、負荷が大きい場合に Mule が特定のイベントを処理するために使用可能なリソースがないときに発生する可能性があります。この問題は、スレッドがすべて使用中で新しく受信したイベントのハンドオフを実行できない場合や、現在のフローの ​maxConcurrency​ 値をすでに超過している場合に発生する可能性があります。

Mule がイベントを処理できない場合、その状況に関する次のメッセージが記録されます: Flow 'flowName' is unable to accept new events at this time​ (フロー「flowName」は、現在新しいイベントを受け付けられません)。. また、フローのソースには、必要なアクションを実行するように通知されます。 バックプレッシャーのために Mule が実行するアクションは、各コネクタの取得元に固有です。たとえば、​http:listener​ は ​503​ エラーコードを返す可能性があり、メッセージブローカーリスナーはリソースが使用可能になるまで待つかメッセージを削除する可能性があります。

場合によっては、取得元は処理しきれないデータを取得しないようにリモートシステムから切断し、サーバーが正常な状態に戻った後に再接続することがあります。