リソースグループ¶
リソースグループは、リソースの使用量に制限を設け、その中で実行されるクエリに対してキューイングポリシーを強制したり、リソースをサブグループ間で分割したりできます。クエリは単一のリソースグループに属し、そのグループ(およびその上位グループ)からリソースを消費します。キューに入ったクエリの制限を除き、リソースグループがリソースを使い果たしても、実行中のクエリが失敗することはありません。代わりに、新しいクエリがキューに入れられます。リソースグループはサブグループを持つか、クエリを受け入れることができますが、両方を行うことはできません。
PrestoDBでは、リソースグループはクエリの実行とリソース割り当てを管理するための強力なツールです。これにより、管理者はPrestoクラスタでリソースがどのように割り当てられ、利用されるかを制御できます。
リソース使用量の制限¶
リソースグループは、CPU時間、メモリ使用量、クエリの総数など、リソース使用量に制限を設定できます。これは、単一のユーザーやクエリがシステムリソースを独占しないようにしたいマルチテナント環境で特に役立ちます。
リソース消費¶
クエリは単一のリソースグループに属し、そのグループだけでなく、親グループからもリソースを消費します。リソースグループが特定のリソースを使い果たしても、実行中のクエリが失敗することはありません。代わりに、リソースが再び利用可能になるまで、新しいクエリがキューに入れられます。
サブグループとクエリの受付¶
サブグループを使用すると、階層的なリソース割り当てが可能になり、各サブグループは独自のリソース制限とキューイングポリシーを持つことができます。クエリを直接受け入れるリソースグループはリーフグループであり、割り当てられたリソースを使用してクエリを実行します。
リソースグループと関連する選択ルールは、プラグイン可能なマネージャによって構成されます。Prestoのリソース管理は、次の2つの方法で実行できます。
ファイルベースのリソース管理¶
ファイルベースのリソースマネージャでは、リソースグループに関する構成情報はJSONファイルに保存されます。このファイルには、すべてのリソースグループの定義と、それらを選択するためのルールが含まれています。構成ファイルは、Prestoサーバーの起動時にロードされて使用されます。ファイルへの変更を有効にするには、Prestoサーバーの再起動が必要です。
データベースベースのリソース管理¶
データベースベースのリソースマネージャでは、リソースグループに関する構成情報はリレーショナルデータベースに保存されます。データベースには、すべてのリソースグループの定義と、それらを選択するためのルールが含まれています。ファイルベースのリソースマネージャとは異なり、データベースの構成に対する変更はすぐに有効になり、Prestoサーバーの再起動は必要ありません。
どちらの方法にも長所と短所があります。ファイルベースのリソース管理はセットアップが簡単ですが、柔軟性に欠けます。一方、データベースベースのリソース管理はセットアップが複雑ですが、より柔軟性と動的な変更が可能です。
ファイルリソースグループマネージャ¶
PrestoDBのファイルリソースグループマネージャは、JSON構成ファイルを使用してリソースを管理する方法です。このファイルには、すべてのリソースグループの定義と、特定のクエリに適切なリソースグループを選択するためのルールが含まれています。
ファイルベースのリソースグループマネージャをセットアップするには
ファイル
etc/resource-groups.properties
を作成します。etc/resource-groups.properties
で、resource-groups.configuration-manager
プロパティを、次のコード例を使用してfile
に設定します。resource-groups.configuration-manager=file
etc
にresource-groups.json
という名前のJSONファイルを作成します。このファイルには、リソースグループの定義が含まれている必要があります。各リソースグループは、最大メモリ、最大キューイングクエリ、最大実行中クエリなどを指定できます。リソースグループの定義の作成の詳細については、リソースグループのプロパティを参照してください。resource-groups.jsonファイルの例については、ファイルリソースグループマネージャを参照してください。
etc/resource-groups.properties
で、次のコード例を使用してJSONファイルの場所を指定する行を追加します。resource-groups.config-file
プロパティを<file_path>
に設定します。<file_path>
はJSONファイルへのパスです。resource-groups.config-file=etc/resource-groups.json
Prestoサーバーを再起動します。新しいリソースグループは、再起動直後に有効になります。
データベースリソースグループマネージャ¶
PrestoDBのデータベースリソースグループマネージャは、リレーショナルデータベースを使用してリソースを管理する方法です。
データベースベースのリソースグループマネージャをセットアップするには
ファイル
etc/resource-groups.properties
を作成します。resource-groups.configuration-manager
プロパティをdb
に設定します。リレーショナルデータベースを設定します。データベースはPrestoからアクセスできる必要があります。リソースグループの構成を保存するために使用されます。
リソースグループと選択ルール用のテーブルを作成します。データベースに、リソースグループの定義と、特定のクエリに適切なリソースグループを選択するためのルールを保存するテーブルを作成する必要があります。
Presto構成でデータベースを指定するには、
etc/resource-groups.properties
に、データベースのJDBC URLを指定する行を追加します。resource-groups.config-db-url = <jdbc_url>
。<jdbc_url>
はデータベースのJDBC URLです。注: 現在、MySQLのみがサポートされています。
etc/resource-groups.properties
は次の例のようになるはずです。
resource-groups.configuration-manager=db
resource-groups.config-db-url=jdbc:mysql://localhost:3306/resource_groups?user=<user>&password=<password>
<user>
と<password>
を実際のユーザー名とパスワードに置き換えます。
データベースリソースグループマネージャを使用すると、データベースの構成に対する変更はすぐに有効になり、Prestoサーバーの再起動は必要ありません。これにより、リソースグループの構成をより柔軟に動的に変更できます。
リソースグループの構成は、resource_groups_global_properties
、resource_groups
、およびselectors
のテーブルを通じて設定する必要があります。Prestoの起動時にテーブルが存在しない場合は、自動的に作成されます。
selectors
テーブルのルールは、priority
フィールドの値の降順で処理されます。
データベースリソースグループマネージャのプロパティ¶
プロパティ名 |
説明 |
デフォルト値 |
---|---|---|
|
構成をロードするデータベースURL。 |
|
|
リフレッシュの失敗後、構成が古くなった場合に、クラスターがクエリを受け入れ続ける最大時間。 |
|
|
このフラグを設定すると、追加の |
|
リソースグループのプロパティ¶
リソースグループは、リソースの割り当てと使用方法を決定する一連のプロパティを使用して定義されます。リソースグループに設定できる主なプロパティは次のとおりです。
name
(必須):リソースグループの名前。これは必須のプロパティです。maxQueued
(必須):リソースグループでキューに入れることができるクエリの最大数。この制限に達すると、新しいクエリは拒否されます。hardCpuLimit
(オプション):このグループが期間内に使用できる最大CPU時間。softMemoryLimit
(必須):リソースグループが使用できる最大メモリ量。これは、絶対値(「10GB」など)または利用可能な総メモリの割合(「50%」など)で指定できます。hardConcurrencyLimit
(必須):リソースグループが同時に実行できるクエリの最大数。softConcurrencyLimit
(オプション):同時実行クエリ数のソフト制限。この制限を超えると、スケジューラは新しいクエリの開始を阻止しようとしますが、実行中のクエリを強制的に停止することはありません。softCpuLimit
(オプション):このグループが期間内に使用できる最大CPU時間(cpuQuotaPeriod
を参照)。最大実行クエリ数にペナルティが適用される前に設定されます。hardCpuLimit
も指定する必要があります。schedulingPolicy
(オプション):リソースグループ内でクエリがどのようにスケジュールされるかを決定するポリシー。これは、4つの値fair
、weighted
、weighted_fair
、またはquery_priority
のいずれかに設定できます。fair
(デフォルト):キューに入ったクエリは先入れ先出しで処理され、サブグループは、キューに入っているものがある場合、新しいクエリの開始を順番に行う必要があります。weighted_fair
:サブグループは、schedulingWeight
と、すでに同時実行されているクエリの数に基づいて選択されます。サブグループの実行中のクエリの予想される割合は、現在対象となるすべてのサブグループの重みに基づいて計算されます。その割合に対して同時実行数が最も少ないサブグループが、次のクエリを開始するために選択されます。weighted
:キューに入ったクエリは、query_priority
{doc}session property </sql/set-session>
で指定された優先度に応じて確率的に選択されます。サブグループは、schedulingWeight
に比例して新しいクエリを開始するために選択されます。query_priority
:すべてのサブグループもquery_priority
で構成する必要があります。キューに入ったクエリは、優先度に従って厳密に選択されます。
schedulingWeight
(オプション):親グループがweighted
スケジューリングポリシーを使用する場合のリソースグループの重み。重みが大きいほど、グループは親グループのリソースのより大きなシェアを取得します。jmxExport
(オプション):true
に設定すると、リソースグループの統計がJMX経由でエクスポートされます。デフォルトはfalse
です。perQueryLimits
(オプション):リソースグループ内の各クエリが、強制終了される前に消費できる最大リソースを指定します。これらの制限は、親グループから継承されません。3種類の制限を設定できます。executionTimeLimit
(オプション):クエリの実行にかかる最大時間の絶対値(例:1時間
)を指定します。totalMemoryLimit
(オプション):クエリが消費できる最大分散メモリの絶対値(例:1GB
)を指定します。cpuTimeLimit
(オプション):クエリが使用できる最大CPU時間の絶対値(例:1時間
)を指定します。
workerPerQueryLimit
(オプション):各クエリで使用可能である必要があるワーカーの最小数を指定します。ワーカーの数が時間とともに変化する伸縮自在なクラスターで使用することを目的としています。subGroups
(オプション):サブグループのリスト。リソースグループ内のサブグループのリスト。各サブグループは、独自のプロパティセットを持つことができます。
スケジューリングの重みの例¶
スケジューリングの重み付けは、リソースに優先度を割り当てる方法です。スケジューリングの重みが大きいサブグループには、より高い優先順位が与えられます。たとえば、スケジュールされたパイプラインクエリのタイムリーな実行を保証するには、アドホッククエリよりも重み付けを高くします。
次に例を示します。
ルートリソースグループglobal
に、2つのサブグループ(engineering
とmarketing
)があるとします。engineering
サブグループのスケジューリングの重みは3で、marketing
サブグループのスケジューリングの重みは1です。この設定では、engineering
サブグループは親グループのリソースの75%(3は合計重み4の75%であるため)を取得し、marketing
サブグループは親グループのリソースの25%(1は合計重み4の25%であるため)を取得します。
スケジューリングの重み付けを使用すると、リソース割り当ての観点から特定のサブグループを他のサブグループよりも優先することができます。この例では、engineering
サブグループからのクエリは、marketing
サブグループからのクエリよりも優先されます。
セレクタールール¶
PrestoDBのセレクタールールの主要コンポーネントは次のとおりです。
group
(必須):これらのクエリが実行されるグループ。user
(オプション):これは、クエリを送信しているユーザーに一致する正規表現です。source
(オプション):これは、クエリのソース(通常はクエリを送信しているアプリケーション)と一致します。queryType
(オプション):送信されたクエリのタイプと照合する文字列SELECT
:SELECT
クエリ。EXPLAIN
:EXPLAIN
クエリ(ただし、EXPLAIN ANALYZE
は除く)。DESCRIBE
:DESCRIBE
、DESCRIBE INPUT
、DESCRIBE OUTPUT
、およびSHOW
クエリ。INSERT
:INSERT
、CREATE TABLE AS
、およびREFRESH MATERIALIZED VIEW
クエリ。UPDATE
:UPDATE
クエリ。DELETE
:DELETE
クエリ。ANALYZE
:ANALYZE
クエリ。DATA_DEFINITION
:スキーマ/テーブル/ビューのメタデータを変更/作成/削除し、プリペアドステートメント、権限、セッション、トランザクションを管理するクエリ。
clientTags
(オプション):タグのリスト。一致させるには、このリスト内のすべてのタグが、クエリに関連付けられているクライアント提供のタグのリストに含まれている必要があります。selectorResourceEstimate
(オプション):リソース推定に基づくリソースグループの選択。executionTime
peakMemory
cpuTime
clientInfo
(オプション):クライアント情報と照合する文字列。principal
(オプション):これは、クエリを送信しているプリンシパルに一致する正規表現です。schema
(オプション):これは、クエリのセッションスキーマと一致します。
セレクターは順番に処理され、最初に一致したものが使用されます。
グローバルプロパティ¶
cpuQuotaPeriod
(オプション):CPUクォータが適用される期間。cpuQuotaPeriod
は、指定された期間内にコンテナが使用できるCPUリソースの量を制御するために、コンテナベースの環境でよく使用されるグローバルプロパティです。
これらのプロパティの正確な実装と名前は、コンテナランタイムとオーケストレーションシステムによって異なる場合があることに注意してください。
セレクタープロパティの提供¶
ソース名は次のように設定できます。
CLI:
--source
オプションを使用します。クライアントアプリで使用する場合のJDBCドライバー:JavaアプリケーションでJDBCドライバーを使用する場合、接続構成に
source
プロパティを追加して値を設定します。Javaプログラムで使用するJDBCドライバー:
source
キーと値をConnection
インスタンスに追加します。例を参照してください。
クライアントタグは次のように設定できます。
CLI:
--client-tags
オプションを使用します。クライアントアプリで使用する場合のJDBCドライバー:JDBCドライバーを使用するJavaアプリケーションを使用する場合は、接続構成に
clientTags
プロパティを追加し、値を設定します。Javaプログラムで使用するJDBCドライバー:
clientTags
キーと値をConnection
インスタンスに追加します。例を参照してください。
例¶
以下の設定例では、いくつかのリソースグループがあり、そのうちのいくつかはテンプレートです。テンプレートを使用すると、管理者はリソースグループツリーを動的に構築できます。たとえば、pipeline_${USER}
グループでは、${USER}
はクエリを送信したユーザーの名前に展開されます。${SOURCE}
もサポートされており、クエリを送信したソースに展開されます。また、source
およびuser
正規表現で、カスタムの名前付き変数を使用することもできます。
どのクエリをどのリソースグループで実行するかを定義する4つのセレクターがあります。
最初のセレクターは
bob
からのクエリを照合し、それらをadminグループに配置します。2番目のセレクターは、
pipeline
を含むソース名からのすべてのデータ定義(DDL)クエリを照合し、それらをglobal.data_definition
グループに配置します。これにより、このクラスのクエリは高速であると予想されるため、キューの時間を短縮できます。3番目のセレクターは、
pipeline
を含むソース名からのクエリを照合し、global.pipeline
グループの下に動的に作成されたユーザーごとのパイプライングループに配置します。4番目のセレクターは、正規表現
jdbc#(?<toolname>.*)
に一致するソースを持ち、hi-pri
のスーパーセットであるクライアント提供のタグを持つBIツールからのクエリを照合します。これらは、global.pipeline.tools
グループの下に動的に作成されたサブグループに配置されます。動的なサブグループは、ソースの正規表現から抽出される名前付き変数toolname
に基づいて作成されます。ソースが
jdbc#powerfulbi
、ユーザーがkayla
、クライアントタグがhipri
とfast
であるクエリを考えてみましょう。このクエリは、global.pipeline.bi-powerfulbi.kayla
リソースグループにルーティングされます。最後のセレクターは、まだ一致していないすべてのクエリをユーザーごとのアドホックグループに配置するキャッチオールです。
これらのセレクターは、連携して次のポリシーを実装します。
ユーザー
bob
は管理者であり、最大50個の同時クエリを実行できます。クエリは、ユーザーが提供する優先度に基づいて実行されます。
残りのユーザーの場合
合計で100個を超えるクエリを同時に実行することはできません。
ソースが
pipeline
である最大5つの同時DDLクエリを実行できます。クエリはFIFO順に実行されます。非DDLクエリは、
global.pipeline
グループの下で、合計同時実行数が45、ユーザーごとの同時実行数が5で実行されます。クエリはFIFO順に実行されます。BIツールの場合、各ツールは最大10個の同時クエリを実行でき、各ユーザーは最大3個の同時クエリを実行できます。合計需要が10の制限を超える場合、実行中のクエリ数が最も少ないユーザーが次の同時実行スロットを取得します。このポリシーにより、競合下での公平性が実現します。
残りのすべてのクエリは、同様に動作する
global.adhoc.other
の下のユーザーごとのグループに配置されます。
ファイルリソースグループマネージャー¶
{
"rootGroups": [
{
"name": "global",
"softMemoryLimit": "80%",
"hardConcurrencyLimit": 100,
"maxQueued": 1000,
"schedulingPolicy": "weighted",
"jmxExport": true,
"subGroups": [
{
"name": "data_definition",
"softMemoryLimit": "10%",
"hardConcurrencyLimit": 5,
"maxQueued": 100,
"schedulingWeight": 1
},
{
"name": "adhoc",
"softMemoryLimit": "10%",
"hardConcurrencyLimit": 50,
"maxQueued": 1,
"schedulingWeight": 10,
"subGroups": [
{
"name": "other",
"softMemoryLimit": "10%",
"hardConcurrencyLimit": 2,
"maxQueued": 1,
"schedulingWeight": 10,
"schedulingPolicy": "weighted_fair",
"subGroups": [
{
"name": "${USER}",
"softMemoryLimit": "10%",
"hardConcurrencyLimit": 1,
"maxQueued": 100
}
]
},
{
"name": "bi-${toolname}",
"softMemoryLimit": "10%",
"hardConcurrencyLimit": 10,
"maxQueued": 100,
"schedulingWeight": 10,
"schedulingPolicy": "weighted_fair",
"subGroups": [
{
"name": "${USER}",
"softMemoryLimit": "10%",
"hardConcurrencyLimit": 3,
"maxQueued": 10
}
]
}
]
},
{
"name": "pipeline",
"softMemoryLimit": "80%",
"hardConcurrencyLimit": 45,
"maxQueued": 100,
"schedulingWeight": 1,
"jmxExport": true,
"subGroups": [
{
"name": "pipeline_${USER}",
"softMemoryLimit": "50%",
"hardConcurrencyLimit": 5,
"maxQueued": 100
}
]
}
]
},
{
"name": "admin",
"softMemoryLimit": "100%",
"hardConcurrencyLimit": 50,
"maxQueued": 100,
"schedulingPolicy": "query_priority",
"jmxExport": true
}
],
"selectors": [
{
"user": "bob",
"group": "admin"
},
{
"source": ".*pipeline.*",
"queryType": "DATA_DEFINITION",
"group": "global.data_definition"
},
{
"source": ".*pipeline.*",
"group": "global.pipeline.pipeline_${USER}"
},
{
"source": "jdbc#(?<toolname>.*)",
"clientTags": ["hipri"],
"group": "global.adhoc.bi-${toolname}.${USER}"
},
{
"group": "global.adhoc.other.${USER}"
}
],
"cpuQuotaPeriod": "1h"
}
データベースリソースグループマネージャー¶
-- global properties
INSERT INTO resource_groups_global_properties (name, value) VALUES ('cpu_quota_period', '1h');
-- Every row in resource_groups table indicates a resource group.
-- The enviroment name is 'test_environment', make sure it matches `node.environment` in your cluster.
-- The parent-child relationship is indicated by the ID in 'parent' column.
-- create a root group 'global' with NULL parent
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, scheduling_policy, jmx_export, environment) VALUES ('global', '80%', 100, 1000, 'weighted', true, 'test_environment');
-- get ID of 'global' group
SELECT resource_group_id FROM resource_groups WHERE name = 'global'; -- 1
-- create two new groups with 'global' as parent
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, scheduling_weight, environment, parent) VALUES ('data_definition', '10%', 5, 100, 1, 'test_environment', 1);
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, scheduling_weight, environment, parent) VALUES ('adhoc', '10%', 50, 1, 10, 'test_environment', 1);
-- get ID of 'adhoc' group
SELECT resource_group_id FROM resource_groups WHERE name = 'adhoc'; -- 3
-- create 'other' group with 'adhoc' as parent
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, scheduling_weight, scheduling_policy, environment, parent) VALUES ('other', '10%', 2, 1, 10, 'weighted_fair', 'test_environment', 3);
-- get ID of 'other' group
SELECT resource_group_id FROM resource_groups WHERE name = 'other'; -- 4
-- create '${USER}' group with 'other' as parent.
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, environment, parent) VALUES ('${USER}', '10%', 1, 100, 'test_environment', 4);
-- create 'bi-${toolname}' group with 'adhoc' as parent
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, scheduling_weight, scheduling_policy, environment, parent) VALUES ('bi-${toolname}', '10%', 10, 100, 10, 'weighted_fair', 'test_environment', 3);
-- create 'pipeline' group with 'global' as parent
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, scheduling_weight, jmx_export, environment, parent) VALUES ('pipeline', '80%', 45, 100, 1, true, 'test_environment', 1);
-- get ID of 'pipeline' group
SELECT resource_group_id FROM resource_groups WHERE name = 'pipeline'; -- 7
-- create 'pipeline_${USER}' group with 'pipeline' as parent
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, environment, parent) VALUES ('pipeline_${USER}', '50%', 5, 100, 'test_environment', 7);
-- create a root group 'admin' with NULL parent
INSERT INTO resource_groups (name, soft_memory_limit, hard_concurrency_limit, max_queued, scheduling_policy, environment, jmx_export) VALUES ('admin', '100%', 50, 100, 'query_priority', 'test_environment', true);
-- Selectors
-- use ID of 'admin' resource group for selector
INSERT INTO selectors (resource_group_id, user_regex, priority) VALUES ((SELECT resource_group_id FROM resource_groups WHERE name = 'admin'), 'bob', 6);
-- use ID of 'global.data_definition' resource group for selector
INSERT INTO selectors (resource_group_id, source_regex, query_type, priority) VALUES ((SELECT resource_group_id FROM resource_groups WHERE name = 'data_definition'), '.*pipeline.*', 'DATA_DEFINITION', 4);
-- use ID of 'global.pipeline.pipeline_${USER}' resource group for selector
INSERT INTO selectors (resource_group_id, source_regex, priority) VALUES ((SELECT resource_group_id FROM resource_groups WHERE name = 'pipeline_${USER}'), '.*pipeline.*', 3);
-- get ID of 'global.adhoc.other.${USER}' resource group for by disambiguating group name using parent ID
SELECT A.resource_group_id self_id, B.resource_group_id parent_id, concat(B.name, '.', A.name) name_with_parent
FROM resource_groups A JOIN resource_groups B ON A.parent = B.resource_group_id
WHERE A.name = '${USER}' AND B.name = 'other';
-- | 5 | 4 | other.${USER} |
INSERT INTO selectors (resource_group_id, priority) VALUES (5, 1);