特定のシナリオでは、スレッドがリソースを待機するため、パラレルクエリがキューイングされる可能性があります。
並行制御
テナントレベル変数 PARALLEL_SERVERS_TARGET を使用すると、テナントが各ノード上で提供できる並列実行ワーカースレッドの最大数を指定できます。並列クエリ開始前に、関連するすべての observer からワーカースレッドリソースを予約します。いずれか一つの observer が並列クエリに十分なリソースを提供できない場合、そのクエリは実行されません。この並列クエリは再キューされ、次回の実行時に再度スレッドリソースの取得を試み、十分なワーカースレッドリソースを確保できるまで続けます。クエリ全体の実行完了後、予約されたワーカースレッドリソースは直ちに解放されます。
この「ワーカースレッドリソースの取得を試みる - リソース不足で再キュー - 再度実行機会を得る - 再度ワーカースレッドリソースを取得を試みる」というプロセスを、並列クエリのキューイングと呼びます。並列実行リソースマネージャーは、すべての observer のワーカースレッドリソース予約を管理するモジュールです。
各並列クエリが必要とするワーカースレッド数を計算するために、並列実行リソースマネージャーはクエリプランを DFO に分割し、DFO スケジューリングプロセスをシミュレートし、parallel hint、table parallel などのパラメータに基づいて、そのクエリが各 observer 上で必要とする最大スレッド数を計算します。このスレッド数の集合を「リソースベクトル」と呼びます。
リソースベクトルは論理的な概念であり、並行性とキューイングを制御します。リソースベクトルを用いて並列実行リソースマネージャーから十分なワーカースレッドリソースを予約した後、その並列クエリは実行されます。実行中、異なる DFO のスケジューリング実行に伴い物理スレッドの取得と解放が繰り返されますが、論理的なスレッドリソースは並列実行リソースマネージャーに返却されません。並列クエリが完全に実行終了した後、このリソースベクトルの集合は並列実行リソースマネージャーに返却されます。
多数の並列クエリが並列実行リソースマネージャーからスレッドリソースを予約する際、リソースが枯渇し、いずれのクエリのリソース要件も満たせなくなるまで、先着順のポリシーが採用されます。その後のクエリはすべて再キューされ、次回のスケジューリング時にリソース取得を再試行します。
ワーカースレッドの割り当て
テナントの各 observer 上には、並列クエリタスクを実行するための並列実行スレッドプールがあります。タスク実行時、スレッドプール内のスレッド数が不足している場合、動的にスレッドプールを拡張します。スレッドプール内のスレッドのアイドル時間が10分を超えると、自動的に10個のスレッドに縮小されます。さらにアイドル時間が60分を超えると、さらに縮小され、0個のスレッドになる可能性があります。
並列クエリがスケジューリング実行を取得すると、各 DFO は常に関連する observer の並列実行スレッドプールから必要な並列スレッドリソースを取得できます。ただし、デフォルトでは、各 DFO がある observer 上に割り当てるスレッド数は、テナントの MIN CPU × 10 を超えてはなりません。DFO が要求するリソースがこの値を超える場合、自動的に MIN CPU × 10 に引き下げられます。
二段階のリソース制御
任意の並列クエリは、二段階のリソース制御を経験します:
- グローバル制御:実行リソースマネージャーの制御の下、十分な実行スレッドを含むリソースベクトルを予約します。
- ローカル制御:並列実行スレッドプールの制御の下、望ましい物理スレッド数を割り当てます。
グローバル制御は分散環境でのリソース取得を考慮し、ローカル制御は単一マシンのスレッドプールのリソース割り当てのみを考慮します。両者はそれぞれの役割を果たします。前者は、Query がチェックを通過した後は必ず実行可能であり、実行時にリソース取得できない問題に直面しないことを保証します。後者は、極端な状況下で単一の Query の DFO が効果的に利用可能な物理スレッド数よりもはるかに多くのスレッドを申請し、スレッドリソースの無駄遣いを防ぐことを保証します。並列クエリは、グローバル制御フェーズを通過すれば、並行度がどの程度高くても、物理スレッド数が不足する問題に直面することなくスムーズに実行できます。
パラレル実行リソース管理
パラレル実行リソースマネージャーはグローバルな視点を持ち、ビュー GV$OB_PX_TARGET_MONITOR を使用してテナント内の各 observer のスレッド予約状態を確認できます。ビューフィールドの詳細な意味については、GV$OB_PX_TARGET_MONITORを参照してください。
obclient> SELECT * FROM GV$OB_PX_TARGET_MONITOR;
+--------------+----------+-----------+-----------+-----------------+--------------+-----------+-------------+------------------+-------------------+------------------------------+
| SVR_IP | SVR_PORT | TENANT_ID | IS_LEADER | VERSION | PEER_IP | PEER_PORT | PEER_TARGET | PEER_TARGET_USED | LOCAL_TARGET_USED | LOCAL_PARALLEL_SESSION_COUNT |
+--------------+----------+-----------+-----------+-----------------+--------------+-----------+-------------+------------------+-------------------+------------------------------+
| 192.xx.xx.xx | 19512 | 1004 | N | 555393108309134 | 192.xx.xx.xx | 19510 | 10 | 6 | 0 | 0 |
| 192.xx.xx.xx | 19512 | 1004 | N | 555393108309134 | 192.xx.xx.xx | 19512 | 10 | 0 | 0 | 0 |
| 192.xx.xx.xx | 19510 | 1004 | Y | 555393108309134 | 192.xx.xx.xx | 19510 | 10 |
6 | 6 | 1 |
| 192.xx.xx.xx | 19510 | 1004 | Y | 555393108309134 | 192.xx.xx.xx | 19512 | 10 | 0 | 0 | 1 |
+--------------+----------+-----------+-----------+-----------------+--------------+-----------+-------------+------------------+-------------------+------------------------------+
4 rows in set
瞬間的な状況では、異なる observer が見るグローバル状態が一致しない場合がありますが、バックグラウンドで500ミリ秒ごとにグローバル状態が同期されます。全体として、各 observer が見る状態は基本的に一致し、大きな偏差は生じません。