始めに
弊社では、膨大なデータの夜間バッチ処理にRedshiftを採用しています。
適材適所でサービスを選択しており、夜間以外はお役御免で停止しておき、費用面を抑えるよう工夫しています。
メンテナンスウィンドウも設けて運用していて概ね問題なく稼働しています。
しかし、稀に全体的にクエリが遅くなってしまう謎の事象に悩まされていました。
今回この事象の原因を突き止めたので、その内容を共有したいと思います。
発生事象
データ量や統計に問題もなく、同じような処理を日々行っているのに、ある日突然、全般的に遅くなっていました。
遅延の度合いはクエリ1本あたり数十秒〜数分レベルです。
数本レベルなら影響は無視できますが、数百もの処理を行っているため、遅延の積み重ねで全体として大きく遅延が発生している状況になっていました。
一方でその後もずっと同じく遅延かというとそういうわけではなく、翌日のバッチ処理では通常に戻るのです。
発生条件
ある日突然に見えていましたが、過去に発生した日を並べてみたとき、ある法則性が見えてきました。
2024/02/21(水)
2024/02/28(水)
2024/04/25(木)
2024/05/01(水)
2024/06/12(水)
そう、水曜日がやたらと多いのです。
そしてメンテナンスウィンドウを火曜日に設定していたことから、メンテナンスが入ってなにかが変わったとき
キャッシュなどのクリアがなされているのではないかという疑いがでてきました。
原因
結論をいうと、何らかのパッチがあったときに発生しているのではないか?という仮説はビンゴでした。
そして、このことはAWS公式ページにもきっちり書かれているものでした。
AWS公式より)クエリパフォーマンスに影響を与える要因
コードコンパイル – Amazon Redshift は、各クエリ実行プランのコードを生成してコンパイルします。 コンパイル済みコードは、インタプリタを使用してオーバーヘッドを削除するため、高速で実行されます。通常、コードが初めて生成およびコンパイルされるときは、ある程度のオーバーヘッドコストが生じます。その結果、最初に実行したときのクエリのパフォーマンスは、誤解を招く場合があります。1 回限りのクエリを実行するときは、オーバーヘッドコストは特に顕著になります。クエリのパフォーマンスを判断するには、必ず 2 回目にクエリを実行します。Amazon Redshift は、サーバーレスコンパイルサービスを使用して、Amazon Redshift クラスターのコンピューティングリソースを超えてクエリコンパイルをスケーリングします。コンパイルされたコードセグメントは、クラスターでローカルにキャッシュされるだけでなく、事実上無制限のキャッシュに保存されます。このキャッシュは、クラスターの再起動後も保持されます。同じクエリをそれ以降に実行すると、コンパイルフェーズをスキップできるため、高速になります。 キャッシュは Amazon Redshift のバージョン間で互換性がないため、バージョンのアップグレード後にクエリが実行されると、コンパイルキャッシュがフラッシュされ、コードが再コンパイルされます。クエリに厳密な SLA がある場合は、クラスターテーブルのデータをスキャンするクエリセグメントを事前に実行することをお勧めします。これにより、Amazon Redshift でベーステーブルデータがキャッシュされるため、バージョンアップグレード後のクエリの計画時間を短縮できます。スケーラブルなコンパイルサービスを使用することで、Amazon Redshift はコードを並行してコンパイルし、常に高速のパフォーマンスを実現できます。ワークロードの高速化の大きさは、クエリの複雑さと同時実行性によって異なります。
要約すると、
「初回実行はクエリのコンパイル処理があり、その分オーバーヘッドがかかりますが、
2回目以降はキャッシュされ高速になります。
このキャッシュは再起動を行っても維持されますが、クラスターのバージョンが変わった場合は互換性がないので、キャッシュクリアされ、再びコンパイルが走るので、速度影響が気になるなら事前に実行することをお勧めします。」
ということです。
初回が遅くなることは、開発時やチューニング時に出くわす事象なので知っていましたが、バージョンアップでそれがクエリ全般で発生してしまうという点は完全に見落としていました。
裏付け
本当にこのケースに該当しているのか?コンパイルは感覚的にちょっと遅いぐらいの認識だったので、本当にこれが原因なのか?深堀りもしてみました。
コンパイルは普段からもなされていますが、アップグレードした日はいつもより件数が200ほど増え、時間に至っては80分以上も多く掛かっていました。
クラスターバージョン | クエリ時間合計 (並列も積上げ) | 再利用 セグメント数 | コンパイル セグメント数 | コンパイル 時間 | |
---|---|---|---|---|---|
普通の日 | P180(1.0.66954)に変化なし | 279分 | 10,807 | 1,791 | 4分 |
遅い日 | P181(1.0.68540)にアップグレード | 381分 | 11,183 | 1,995 | 87分 |
クエリ時間はSTL_QUERYのendtime-starttimeでTATを割り出しそれを集計
再利用セグメント数はSVL_COMPILEのcompileが0となるレコード数
コンパイルセグメント数はSVL_COMPILEのcompileが1となるレコード数
コンパイル時間はSVL_COMPILEのendtime-starttimeでTATを割り出しそれを集計
ちなみに
このコンパイル時間問題については、下記の通り、クエリ高速化である程度対策はなされているようです。しかしながらクエリの複雑さや数によっては許容できない差が生まれます。
では、クラスターバージョンを固定にしてしまえば?という話も出てきそうですが、
一時的に遅らせることはできますが、基本的にはバージョンアップはセキュリティや様々な改修も含まれるため、避けては通れません。
まとめ
如何だったでしょうか?
今回はRedshiftのクラスターバージョンアップに伴うコンパイル処理で無視できないほどの性能影響が発生しうる実例をご紹介しました。
本件の有効な対策については次回ご紹介できればと思います。
Comments