この記事はDistributed computing Advent Calendar16日目の記事です。
PrestoはFacebookがメインとなって開発しているオンメモリでの処理を特徴とする分散クエリエンジンです。各タスクの中間データをメモリにのせたまま処理するためHiveなどと比べて高速に大きなデータに対して処理を行うことができます。Prestoは現在でも活発に開発が進められており最新のバージョンは0.160となります。この2ヶ月程でもminor versionが5つくらい出ているので安定バージョンがなかなか得られない代わりにbug fixやコミュニティからのfeedback迅速に取り入れられています。
今回はまだexperimentalなものではありますが、新しい機能であるPrestoのResource Groupについて書きたいと思います。
Resource Groupとは
Resource Groupはグループやアカウント毎に利用できるリソースに制限をかけることのできる機能です。これまでもPrestoではquery.max-memory
などでクエリ毎、node毎に利用できるメモリは制限できたのですが、アカウントやsource propertyに従って柔軟に制限を設定することは簡単ではありませんでした。またアカウントの同時実行数などもかけることはできませんでした。これらをPrestoの機能として提供するものがResource Groupです。詳細はResource Group Configurationに記載されています。
Resource Groupの使い方
設定は形式はJSONファイルで下記の用に記載します。このファイルの場所はresource-groups.properties
内のresource-groups.config-file
propertyで指定します。
{
"rootGroups": [
{
"name": "global",
"softMemoryLimit": "80%",
"maxRunning": 100,
"maxQueued": 1000,
"schedulingPolicy": "weighted",
"jmxExport": true,
"subGroups": [
{
"name": "adhoc_${USER}",
"softMemoryLimit": "10%",
"maxRunning": 2,
"maxQueued": 1,
"schedulingWeight": 9,
"schedulingPolicy": "query_priority"
},
{
"name": "pipeline",
"softMemoryLimit": "20%",
"maxRunning": 5,
"maxQueued": 100,
"schedulingWeight": 1,
"jmxExport": true,
"subGroups": [
{
"name": "pipeline_${USER}",
"softMemoryLimit": "10%",
"maxRunning": 1,
"maxQueued": 100,
"schedulingPolicy": "query_priority"
}
]
}
]
},
{
"name": "admin",
"softMemoryLimit": "100%",
"maxRunning": 100,
"maxQueued": 100,
"schedulingPolicy": "query_priority",
"jmxExport": true
}
],
"selectors": [
{
"user": "bob",
"group": "admin"
},
{
"source": ".*pipeline.*",
"group": "global.pipeline.pipeline_${USER}"
},
{
"group": "global.adhoc_${USER}"
}
],
"cpuQuotaPeriod": "1h"
}
まず大きくわけて3つの項目があります。
-
rootGroups
: Resource Groupは上記のように入れ子に記述することができ、すべてのResource GroupはこのrootGroups
の下に置かれます。 -
selectors
: すべてのクエリはどれかのResource Groupに関連づけられますが、このときのマッチングルールを記載するのがこのselectors
です。詳細は後述します。 -
cpuQuotaPeriod
: CPUに関する制限を計算するときの基準となる値です。詳細は後述します。
ひとつずつ見ていきます。
rootGroups
各Resource Groupは入れ子にすることができ、以下の要素を持ちます。
名前 | 意味 |
---|---|
name |
Resource Groupにつける一意な名前。selectorで使う |
maxQueued |
queued状態のクエリの最大数 |
maxRunning |
running状態のクエリの最大数 |
softMemoryLimit |
利用できる最大メモリ。容量(e.g. 10GB )かクラスタ全体からの割合(e.g. 10% )で指定。これを超えてからsubmitされたクエリはqueued状態になる。 |
softCpuLimit |
cpuQuotaPeriod で指定された時間内に利用できる最大CPU時間。これを超えると実行可能な最大クエリ数が減らされる |
hardCpuLimit |
cpuQuotaPeriod に利用できる最大CPU時間。これを超えると新しく入ってきたクエリはqueued状態になる。 |
schedulingPolicy |
queued状態のクエリがどのように実行されるかを指定するパラメタ。fair , weighted ,query_priority の3種類がある |
schedulingWeight |
同階層のサブグループと比較した場合も重み |
jmxExport |
JMXでResource Groupのメトリクスを出すかどうか |
subGroups |
サブグループのリスト |
schedulingPolicy
で指定されるpolicyそれぞれは
-
fair
: FIFO.クエリ、サブグループともに早いもの勝ちで処理されていく -
weighted
:query_priority
に比例した形で確率的に次のクエリ、サブグループが選ばれていく -
query_priority
: 確率的にではなくquery_priority
が大きい順に厳密に次のクエリ、サブグループが選ばれていく
となります。クエリが所属するgroupはleafとなっているgroup、つまりsubGroups
を持たないものになります。またある設定値がsubGroups
がoverrideされてない場合は親の設定値が使われます。
selectors
submitされたクエリはselectorによって所属するgroupを決められます。selectorが持てる設定値は下記の3つです。
-
user
: session propertyのuserにマッチするような正規表現 -
source
: session propertyのsourceにマッチするような正規表現 -
group
: マッチしたクエリが所属するgroup名
つまりselectorはクエリが所属するgroupを決めるためのマッチングロジックを記述するためのものになります。マッチするものが複数ある場合には先頭のselectorが優先されます。
ちなみに内部的にはselectorはSelectionContext
というクラスタが担っているのですが、これらに加えて認証情報とクエリの優先度も持っているので将来的にこれらでgroupをマッチングさせることもできるかもしれません。
動的なResource Group
設定ファイルは管理者が生成するファイルですが、ユーザや部署毎に異なるResource Groupを作りたい場合もあると思います。この場合同じような設定を並べると、いちいち設定をする必要があり面倒です。実は上記の例でお気づきかもしれませんが、Resource Groupの名前、selectorにはplace holder的に変数を使うことができます。例えば各account毎にscheduledとadhocクエリを使い分けたい場合。下記のように書くことで新規ユーザがクエリを投げた場合でもsourceを指定することでadhoc, scheduledの両Resource Groupを利用することができます。対応するResource Groupへの初めてのクエリの場合には自動的に作成されます。
{
"rootGroups": [
{
"name": "global",
"schedulingPolicy": "weighted",
"subGroups": [
{
"name": "adhoc_${USER}",
//
},
{
"name": "scheduled_${USER}",
//
}
]
}
],
"selectors": [
{
"source": "scheduled",
"group": "global.scheduled_${USER}"
},
{
"source": "adhoc",
"group": "global.adhoc_${USER}"
}
]
}
このplace holderに利用できる変数はselectorで利用する${USER}
と${SOURCE}
の2種類があります。
Last but not least
大事なことですが、Resource Groupはまだexperimentalな機能として提供されています。そのためdefaultでは有効になっておらず利用するためには下記のpropertyをONにする必要があります。
experimental.resource-groups-enabled=true
私が所属するTreasure Dataでも現在このResource Groupの評価、試験を行っており細かいリソース制限が簡単にかけられることを確認しています。是非試してみてください。
Learn more in Resource Groups