特定のシナリオでは、スレッドリソースを待機するため、パラレルクエリがキューイングされる可能性があります。
パラレル制御
テナントレベルの変数PARALLEL_SERVERS_TARGETを使用すると、各ノードでテナントが提供できるパラレル実行ワーカースレッド数を指定できます。パラレルクエリが開始される前に、すべての関連observerからワーカースレッドリソースを予約します。いずれかのobserverがパラレルクエリに十分なリソースを提供できない場合、そのクエリは実行されません。このパラレルクエリは再キューイングされ、次回の実行時にワーカースレッドリソースの取得を再試行し、十分なワーカースレッドリソースを確保できるまで待機します。クエリ全体の実行が完了すると、予約したワーカースレッドリソースは即座に解放されます。
この「ワーカースレッドリソースの予約を試行 - リソース不足で再キューイング - 再び実行機会を得る - 再度ワーカースレッドリソースの予約を試行」というプロセスを、パラレルクエリのキューイングと呼びます。パラレル実行リソースマネージャーは、すべてのobserverワーカースレッドリソースの予約を管理するモジュールです。
各パラレルクエリに必要なワーカースレッド数を計算するために、パラレル実行リソースマネージャーはクエリ計画をDFO分割し、DFOスケジューリングプロセスをシミュレートし、parallel hint、table parallelなどのパラメータに基づいて、各observerで必要な最大スレッド数を計算します。このスレッド数の集合を「リソースベクトル」と呼びます。
リソースベクトルは論理的概念であり、並行処理とキューイングを制御するために使用されます。リソースベクトルを使用してパラレル実行リソースマネージャーから十分なワーカースレッドリソースを予約した後、そのパラレルクエリは実行されます。実行中、異なるDFOのスケジューリング実行に伴い、物理スレッドの取得と解放が繰り返されますが、論理的なスレッドリソースはパラレル実行リソースマネージャーに返却されることはありません。パラレルクエリが完全に実行終了した後、このリソースベクトルの集合はパラレル実行リソースマネージャーに返却されます。
多数のパラレルクエリがパラレル実行リソースマネージャーからワーカースレッドリソースを予約する場合、リソースが枯渇し、いずれのクエリのリソース要件も満たせなくなるまで、先着順のポリシーが採用されます。その後のクエリはすべて再キューイングされ、再スケジューリング時にリソースの取得を再試行します。
ワーカースレッドの割り当て
テナントの各observerには、パラレルクエリタスクを実行するためのパラレル実行スレッドプールがあります。タスクを実行する際、スレッドプール内のスレッド数が不足している場合、スレッドプールは動的に拡張されます。スレッドプール内のスレッドのアイドル時間が10分を超えると、自動的に10個のスレッドに縮小されます。スレッドプール内のスレッドのアイドル時間が60分を超えると、さらに縮小され、0個のスレッドになる可能性があります。
一度パラレルクエリがスケジューリング実行を許可されると、各DFOは常に関与するobserverのパラレル実行スレッドプールから必要なパラレルスレッドリソースを取得できます。注意すべき点として、デフォルトでは、各DFOが1つの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が見る状態は基本的に一致し、大きな偏差は生じません。