Redshiftのworkload management
Redshiftのパフォーマンス検証記事は見かけるのですが、WLMに関して言及されているものをみないのと、ちょっと複雑なのでまとめておきます。
管理面については Redshiftの管理面 - まめ畑を参照下さい。
WLMの重要性
DWHでは往々にして、実行時間のかかるクエリからサクッと終わるもの、バッチがガリガリと長時間かけて実行するクエリまで様々なタイプのクエリが投げ込まれます。
これらクエリはリソースをガッツリ割り当ててさっさと思ってほしいものから、重要でないから気長に実行をまてるものまで要件は様々です。これら、クラスタリソースを管理してクエリ毎に割り当てることで1つのクラスタ内で様々な種類・用途のクエリを扱いやすくすることが出来ます。
Redshiftでは標準で1キュー・5並列とParameter Groupで設定されています。この状態では実行時間が長くかかるクエリが5本実行されている状態で、数秒で終わるようなクエリが続いて実行されると、この早く終るはずのクエリは先行している5本のクエリのうち1本が終わるまで実行されないため、結果として数秒で終わるはずが数時間たたないと結果が帰ってこないとか、タイムアウトしてしまうということになってしまいます。
Redshiftでいうworkload management(WLM)とは
ドキュメントはImplementing Workload Management - Amazon Redshift
WLMはクラスタに対して実行されるクエリをキューで管理するものです。Redshiftでは、ユーザグループ・クエリグループ毎にキューを設定することができます。
それぞれのグループは以下のまとまりになっています。
- ユーザグループ: 接続アカウントに対して
- クエリグループ: 実行するSQLに対して
このグループ毎にクエリが実行される際の並列度を制御することが可能です。こちらのキューは標準では1つ設定されており、並列度は5となっていますので、同時に5つのSQLを実行することが可能です。最大で8つのキューを定義することが可能で、全てのキューの並列度の合計は15までとなっています。この8つのキューの1つはデフォルトキューに設定しないといけないため、グループを割り当てることが出来るのは7つとなります。
また、暗黙的に並列度1のSuperuserキュー(クエリグループ)というものが存在しますが、こちらはデバッグ用など管理用に使うために割り当てないことが推薦されます。Superuserクエリグループを設定するにはsuperuserでログインしている必要があります。
Redshiftではキューに対してクラスタリソースの配分などの優先度をつけることが出来ないため、メモリ・CPUなどの計算機資源は全てのキューで実行されているクエリに対して等しく割り当てられます。擬似的に優先度をつけるという意味では、キュー毎に並列度を変え、クエリの実行時間や用途毎に分類するくらいです。
キュー毎に優先度をつける事ができ、優先度でCPUなどのリソース割り当て優先順位が付けられれば実行時間が長いクエリは優先度低くなどの使い方も出来るので、こちらは将来の機能拡張に期待したいところです。
Redshiftでの設定
Redshiftでは、Management ConsoleのRedshift Parammeter Groupで設定を行います。設定項目名はwlm_json_configurationです。こちらにjson形式で設定します。
しかし、Editのタブ内でこちらの項目を編集することが出来ません。設定は隣のWLMタブで行います。
こちらのタブを開くと
このような形で並列度と各グループ名を割り当てます。最後の1つがデフォルトキューとなるため、ユーザグループ・クエリグループ共に何も入れてはいけません。
こちらで設定すると、
[{"user_group":["fast"],"query_group":[],"query_concurrency":5},{"user_group":["middle"],"query_group":[],"query_concurrency":2},{"user_group":[],"query_group":["batch"],"query_concurrency":1},{"user_group":[],"query_group":[],"query_concurrency":3}]
というjsonファイルがwlm_json_configurationにセットされます。
default.redshift-1.0がデフォルトで用意されているParameter Groupですがこちらは全ての項目が編集することが出来ないので、独自にParameter Groupを作って、そちらを変更します。既に起動しているクラスタにParameter Groupの変更を適用するとクラスタのrebootが必要になるので、運用中の場合は注意が必要です。Parameter Groupの箇所がpending-rebootになっています。普段はin-syncです。
キューの使用方法
- ユーザグループ
以下のクエリでユーザをグループに追加することが可能です。
1. グループ作成と同時にユーザ追加 (with以下はオプション)
2. ユーザ作成時にグループに指定 (既に存在するグループに対して)
3. 既存のグループにユーザ追加
1# create group fast with user user1, user2; 2# create user user3 in fast,middle password 'hoge'; 3# alter group fast add user user3, user4, user5;
Redshiftに接続するユーザでキューを切り替えるという方法です。速いクエリを発行するアプリケーション・バッチ・長時間かかるクエリ用といった感じでアカウントを切り替えて使うことが出来ます。
- クエリグループ
こちらは、クエリを発行するタイミングで、set query_group / reset query_group で囲まれている間、指定したクエリグループが使用されます。
もし、存在しないクエリグループを指定した場合は影響を及ぼしません。
set query_group to 'batch'; select count(*) from big_table; select user_name, city, age from hoge_table order by age desc limit 100; reset query_group;
アカウントは一つで、クエリを投げる段階で個々に指定するという感じです。
キューの適用規則
キューの適用規則についてはドキュメントにフローチャートが乗っています。
1. Superuserでログインしていて、クエリグループでSuperuserを指定している場合はSuperuerキューで実行
2. ログインユーザがユーザグループに含まれている場合は、一番最初にマッチするユーザグループで指定されているキューで実行
3. ユーザグループに存在しておらず、クエリグループが指定されている場合は、最初にマッチしたクエリグループのキューで実行
4. どれにも当てはまらない場合はデフォルトキューで実行
つまり、ユーザグループがクエリグループよりも優先されます。
例えば、user1 が fastユーザグループに入っていて、クエリパラメータとして batchを指定した場合はどうなるでしょうか。その場合はfastユーザグループで指定されているキューで実行されます。
どのキューでクエリが実行されているかなどの情報をwlm system tableから取得することが可能です。詳細はMonitoring Workload Management - Amazon Redshiftのドキュメントに書かれています。
service_classがWLM設定画面で指定した際のQueue番号です。
キューの並列度
キューの並列度の設定については、運用しながらクラスタリソースの使用状況を見ながら変えていくのが最初はいいですが、変更にはクラスタのrebootが必要なため、運用前にある程度想定クエリで様子をみて調整しておくと後で困らないと思います。
実行時間が短いクエリ用に多めに並列度を設定したキューを割り当て、長い時間実行されリソースも消費するクエリ用には並列度が低いキューを割り当てることで、クラスタリソースの使用量をある程度制限出来ます。
しかし、キューを多くするとクラスタ全体として並列度も上がってしまうため、1つのクエリに割り当てられるクラスタリソースが減ってしまうので注意が必要です。
まとめ
WLMでキューを設定することで、クラスタリソースの使用をある程度クエリに分配することが可能になります。実際は実行されているクエリそれぞれに等しくリソースが割り当てられるため、キューの細分化で全体の並列度の増加にならないように気をつけることが大切です。
また、パフォーマンステストを行う際に、同時実行数もパラメータに含める場合は、WLMの設定を変えないと、6同時接続・実行以上になった場合に6本目からは先の5本のクエリのうち1本が終わるまで待たされている状態になるので、レスポンスタイムに待ちの時間も含まれてしまいます。こちらも注意です。
おまけ
Redshiftはleader nodeで実行計画が作られた後、C++のコードに変換されコンパイルされたものが各データノードに配布され実行されますが、このcompiled comdeは2回目以降はキャッシュがあればそれが使われるので、1回目だけオーバヘッドが乗るためクエリの実行時間が長くなります。パフォーマンステストでは1回めのクエリの結果は含めない方がよいとRedshiftのドキュメントでも触れられています。
また、こちらのcompiled codeですが、 JDBC と ODBC・psql (libpq)で接続した場合はそれぞれ別の物が作られます。JDBCで接続して1回クエリを実行し、全く同じクエリをpsqlで接続したて実行した場合はそれぞれ別々のcompiled codeが作られるため、2回めの実行ですが、コンパイルのオーバヘッドがかかるため実行が遅くなります。