はじめに
リソースプールのリソース獲得タイムアウトエラーは、お客様からサポートセンターに、よくお問い合わせをいただきます。エラーは、以下のような出力です。<ERROR> @v_kkadb_node0001: 53000/3587: Insufficient resources to execute plan on pool general
[Timedout waiting for resource request: Request exceeds limits:
Memory(KB) Exceeded: Requested = 10921995,
Free = 10672151 (Limit = 174751920, Used = 164079769) (queueing threshold)]
要求したメモリサイズ : 10921995 KB
空きメモリサイズ : 10672151 KB
[Timedout waiting for resource request: Request exceeds limits:
Memory(KB) Exceeded: Requested = 10921995,
Free = 10672151 (Limit = 174751920, Used = 164079769) (queueing threshold)]
要求したメモリサイズ : 10921995 KB
空きメモリサイズ : 10672151 KB
本記事では、リソースプールのリソース獲得タイムアウトエラーが発生した場合のトラブルシューティングをご紹介します。
原因
メモリを大量に消費するクエリの実行によってリソースプールのメモリが不足し、後続クエリが長時間メモリ割り当て待ち状態となった場合に発生します。以下の図の例は、GENERALプールのメモリ上限は160GB、タイムアウト値は5分(デフォルト)に設定されています。
Query A が140GB、Query B が20GBのメモリを消費しているため、Query C はメモリの割り当てが行えずキュー待ちの状態となります。この状態のまま、5分が経過するとタイムアウトエラーが発生します。
対処方法
対処方法は以下が考えられます。①→⑦の順に対応の難易度は高くなります。① 何もしない(経過観察)
② 運用方法の検討(利用者のアクセス制御)
③ タイムアウト時間の延長
④ クエリスペシフィックプロジェクションの作成
⑤ SQLのチューニング
⑥ ユーザ定義リソースプールの作成
⑦ 物理メモリの増設
各対処方法の説明やメリット・デメリットは、以下のとおりです。
対処方法 | 説明 |
---|---|
①何もしない(経過観察) | エラーの発生頻度が少ないようであれば、様子をみることも選択肢として挙げられる。 メリット:作業工数が発生しない。 デメリット:繁忙期の場合などに、エラーが多発する可能性が考えられる。 |
②運用方法の検討(利用者のアクセス制御) | 特定のSQLで発生している場合は、SQLを発行している利用者のアクセスを制御する等、運用での回避も考えられる。 メリット:作業工数は発生しない。 デメリット:システムを利用したいタイミングで、使うことができない。 |
③タイムアウト時間の延長 | GENERALプールのタイムアウトをデフォルトの5分から延長することで、タイムアウトで失敗したクエリのエラーを抑止する。 メリット:オンライン(サービス影響なし)で、パラメータ変更のみで対応できる。 デメリット:大量のキュー待ちが発生する可能性があり、最大接続数の設定に抵触し新規接続ができない可能性がある。 |
④クエリスペシフィックプロジェクションの作成 | 特定のSQLで発生している場合は、クエリスペシフイックプロジェクションを作成して、処理に必要なメモリサイズが小さくなるようにする。 メリット:Verticaのコマンド実行やツール操作(admintoolsやMC)による対応のため、SQLの改修に比べて、作業工数を抑えることができる。 デメリット:他のSQL性能に影響を与えないかテストの必要がある。 |
⑤SQLのチューニング | 特定のSQLで発生している場合は、SQLの構造を見直して、処理に必要なメモリサイズを小さくするように改修する。 メリット:SQLのメモリ使用量を減らすことにより、根本的な解決につながると考えられる。 デメリット:改修に大きな工数がかかると予想される。 |
⑥ユーザ定義リソースプールの作成 | メモリを大量に消費するロングクエリ用と、それ以外のショートクエリ用のプールを作成し、リソースを管理する。 メリット:ロングクエリが影響して、メモリ割り当てができなかった、ショートクエリのエラーは防止できる。 デメリット:リソースプールは、やや難解であり、知識習得が必要となる。 |
⑦物理メモリの増設 | 各ノードのメモリを増設する。 メリット:根本的な解決につながると考えられる。 デメリット:モリ増設にあたり、費用が発生する。 |
上の対処方法の中で、Vertica側で対応するものは③~⑥です。
難易度の低い③から対応し、解消しない場合は④、⑤、⑥の順で対応することをお薦めします。
「④クエリスペシフィックプロジェクションの作成」と「⑤SQLのチューニング」については、以下の記事で説明しています。ご確認ください。
http://vertica-tech.ashisuto.co.jp/join_inner_did_not_error/
本記事では、「③タイムアウト時間の延長」と「⑥ユーザ定義リソースプールの作成」の対処方法を説明します。
対処方法③ タイムアウト時間の延長
GENERALプールのタイムアウト値を延長することで、タイムアウトエラーの発生を抑止します。以下の手順で行います。Step1:タイムアウト時間の確認
Step2:タイムアウト時間の変更
Step3:タイムアウト時間の確認
Step4:SQLの再実行
Step1:タイムアウト時間の確認
以下のコマンドで、GENERALプールのqueuetimeoutを確認します。
1 2 3 4 5 6 7 8 9 10 11 |
SQL=> SELECT * FROM resource_pools WHERE name = 'general'; … memorysize | maxmemorysize | Special: 95% executionparallelism | AUTO priority | 0 runtimepriority | MEDIUM runtimeprioritythreshold | 2 queuetimeout | 00:05 ★ plannedconcurrency | AUTO … |
GENERALプールのqueuetimeoutは、デフォルトの5分であることが分かります。
Step2:タイムアウト時間の変更
以下コマンドで、queuetimeoutを変更します。この例では10分に延長しています。
1 |
SQL=> ALTER RESOURCE POOL general QUEUETIMEOUT 600; |
※延長する時間の目安はないため、少しずつ増やしながら経過を観察していく必要があります。
Step3:タイムアウト時間の確認
Step2で変更した値が反映されていることを確認します。
1 2 3 4 5 6 7 8 9 10 11 |
SQL=> SELECT * FROM resource_pools WHERE name = 'general'; … memorysize | maxmemorysize | Special: 95% executionparallelism | AUTO priority | 0 runtimepriority | MEDIUM runtimeprioritythreshold | 2 queuetimeout | 00:10 ★ plannedconcurrency | AUTO … |
Step4: SQLの再実行
SQLを再実行して、タイムアウトエラーが解消されたことを確認します。キュー待ちのSQLを確認することが可能です。SQLの再実行中、必要に応じてキュー待ちのSQLをご確認ください。確認方法は以下をご参考ください。
http://vertica-tech.ashisuto.co.jp/resource-queue/
対処方法⑥ ユーザ定義リソースプールの作成
大量にメモリを消費するロングクエリ用とそれ以外のショートクエリ用にリソースプールを作成します。それぞれのクエリ用にリソースプールを作成することで、ショートクエリがロングクエリの影響を受けなくなり、タイムアウトエラーの発生を抑止できます。以下の手順で行います。Step1:SQLのワークロードを分析
Step2:パラメータ値の検討
Step3:ユーザ定義リソースプールの作成
Step4:DB接続用のユーザを変更
Step5:SQLの再実行
Step6:ユーザ定義リソースプールの使用状況を確認
Step1:SQLのワークロードを分析
まずは、実行されているSQLのメモリ使用状況を分析します。以下の「Resource Manager Analysis」及び「Appendix」をご参考ください。
https://www.vertica.com/kb/BestPracticesforManagingResourcePools/Content/BestPractices/BestPracticesforManagingResourcePools.htm
Step2:パラメータ値の検討
Step1で実施した分析結果をもとに、ロングクエリ用とショートクエリ用のユーザ定義リソースプールについて、パラメータの値を検討します。主に利用するリソースパラメータの意味と検討ポイントは以下のとおりです。
パラメータ名 | 説明 |
---|---|
MEMORYSIZE | 予約済みのメモリサイズ 指定しない場合(0%)は、必要になった時点でGENERALプールから必要なメモリ リソースを借りる |
MAXMEMORYSIZE | MEMORYSIZEではメモリが足りない場合に、GENERALプールから借りるサイズも含んだ使用可能な最大メモリサイズ |
PLANNEDCONCURRENCY | プールに対して想定されるクエリ実行数 デフォルト値は1ノード当たりのCPUコア数 1セッションあたりのメモリの初期割当サイズを決定するために使用される |
MAXCONCURRENCY | 同時実行処理の最大数 同時実行数が設定値を超えた場合、以降の処理はキュー(待ち状態)に入る |
RUNTIMEPRIORITY | CPU / IO帯域の優先度(有効値:HIGH、MEDIUM、LOW) 処理を実行する際に割り当てられるCPU / IO帯域の優先度を決定するために使用される |
●MEMORYSIZE/MAXMEMORYSIZE
・ロングクエリ用プール
ロングクエリはメモリを多く使用する場合が多いためメモリサイズを大きめに設定します。
※MEMORYSIZEで設定すると実行していない状態でも指定サイズ分のメモリが確保されてしまい、他のプールが使用できるメモリが減ってしまうため、MAXMEMORYSIZEで設定します。これにより、必要なときだけメモリを確保する動作となります。
・ショートクエリ用プール※MEMORYSIZEで設定すると実行していない状態でも指定サイズ分のメモリが確保されてしまい、他のプールが使用できるメモリが減ってしまうため、MAXMEMORYSIZEで設定します。これにより、必要なときだけメモリを確保する動作となります。
ショートクエリはロングクエリに比べて必要なメモリが少ない場合が多いため、MEMORYSIZEは小さめに設定します。
他のプールの影響を受けないように(メモリを予約できるように)MEMORYSIZEで設定します。
他のプールの影響を受けないように(メモリを予約できるように)MEMORYSIZEで設定します。
●PLANNEDCONCURRENCY
・ロングクエリ用プール
ロングクエリはメモリを多く使用する場合が高いため、PLANNEDCONCURRENCYの値を小さく設定し、メモリの初期割当サイズを大きくします。
これによりメモリの追加割当のオーバーヘッドを抑えることができます。
・ショートクエリ用プールこれによりメモリの追加割当のオーバーヘッドを抑えることができます。
ショートクエリはロングクエリに比べて必要なメモリが少ない場合が多いため、PLANNEDCONCURRENCYの値を大きくし、メモリの初期割当サイズを小さくします。
●MAXCONCURRENCY
・ロングクエリ用プール
ロングクエリは負荷が高い処理の場合が高いため、 MAXCONCURRENCYの値を小さくし、同時実行処理の最大数を少なめにします。
これにより、他のプールの処理への影響を抑えることができます。
これにより、他のプールの処理への影響を抑えることができます。
●RUNTIMEPRIORITY
・ロングクエリ用プール
ロングクエリはショートクエリと比較すると、ある程度処理に時間がかかっても許容される場合が多いため、RUNTIMEPRIORITYは低く設定します。
これにより、ロングクエリとショートクエリが同時に実行されている場合でも、ショートクエリへの影響を小さくできます。
・ショートクエリ用プールこれにより、ロングクエリとショートクエリが同時に実行されている場合でも、ショートクエリへの影響を小さくできます。
ショートクエリはロングクエリと比較すると、処理を優先したい(速くしたい)場合が多いため、ショートクエリはRUNTIMEPRIORITYを高く設定します。
これにより、他のプールより優先してCPUリソースを使用できます。
これにより、他のプールより優先してCPUリソースを使用できます。
Step3:ユーザ定義リソースプールの作成
Step2で決定したパラメータ値でユーザ定義リソースプールを作成します。作成方法は以下をご確認ください。http://vertica-tech.ashisuto.co.jp/user_defined_resource_pool/
ここでは、ロングクエリ用に「long_pool」、ショートクエリ用に「short_pool」というリソースプールを作成しています。
1 2 3 4 5 6 7 8 9 10 11 12 |
/*ロングクエリ用のリソースプールを作成*/ SQL=> CREATE RESOURCE POOL long_pool MEMORYSIZE '0G' MAXMEMORYSIZE '10G'; /*ショートクエリ用のリソースプールを作成*/ SQL=> CREATE RESOURCE POOL short_pool MEMORYSIZE '1G' MAXMEMORYSIZE '1G'; /*ユーザ定義リソースプールの設定値を確認*/ SQL=> SELECT pool_name,memory_size_kb,max_memory_size_kb FROM resource_pool_status 2 WHERE pool_name IN('long_pool','short_pool'); pool_name | memory_size_kb | max_memory_size_kb ------------+----------------+-------------------- long_pool | 0 | 10485760 short_pool | 1048576 | 1048576 |
作成したユーザ定義リソースプールをユーザに割り当てます。CREATE USER 文で新たにユーザを作成して割り当てたり、ALTER USER文で既存のユーザに対して割り当てたりすることが可能です。以下の例では、ロングクエリ用のユーザ「long_user」に「long_pool」、ショートクエリ用のユーザ「short_user」に「short_pool」を割り当てています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/*ロングクエリ用*/ SQL=> CREATE USER long_user RESOURCE POOL long_pool; SQL=> ALTER USER long_user RESOURCE POOL long_pool; /*ショートクエリ用*/ SQL=> CREATE USER short_user RESOURCE POOL short_pool; SQL=> ALTER USER short_user RESOURCE POOL short_pool; /*ユーザに割り当てられたユーザ定義リソースプールを確認*/ SQL=> SELECT user_name,resource_pool FROM users 2 WHERE user_name IN('long_user','short_user'); user_name | resource_pool ------------+--------------- long_user | long_pool short_user | short_pool |
Step4:DB接続用のユーザを変更
アプリケーションからDBに接続するドライバや接続文字列に、ロングクエリ用とショートクエリ用のユーザをそれぞれ設定します。
以下は、設定例です。ロングクエリを実行するアプリケーションのドライバにはlong_user、ショートクエリを実行するアプリケーションのドライバにはshort_userに接続するよう設定します。
Step5:SQLの再実行
ロングクエリ用とショートクエリ用の各ユーザから、SQLを再実行します。ロングクエリとショートクエリが重なった場合に、ショートクエリで「Insufficient resources to execute plan on pool general 」が発生しないことを確認します。「対処方法③のStep4」と同じく、SQLの再実行中、必要に応じてキュー待ちのSQLをご確認ください。
http://vertica-tech.ashisuto.co.jp/resource-queue/
Step6:ユーザ定義リソースプールの使用状況を確認
「Step1:SQLのワークロードを分析」を参考に、ロングクエリ用とショートクエリ用に作成したユーザ定義リソースプールが、SQL実行時に想定どおり使用されたことを確認します。https://www.vertica.com/kb/BestPracticesforManagingResourcePools/Content/BestPractices/BestPracticesforManagingResourcePools.htm
検証バージョンについて
この記事の内容はVertica 12.0で確認しています。更新履歴
2022/08/19 本記事を公開- 投稿タグ
- ユーザ定義リソースプール, タイムアウト, timeout, resource_pools, pool, queue, リソースプール, resource_pool, タイムアウトエラー