Aurora運用Tips IOPS編

久々にAuroraについて、小ネタ系で書いてみるテスト。

主にストレージIOPSにまつわるTipsで、光り輝くモノは別にないですけど、基本が大事ということで。




ストレージIOPSのグラフ生成

データベースの運用において、監視データであるメトリクスを色々収集するのは基本ですが、その中でも最重要に位置する項目である ストレージのIOPS についてです。

まず、Auroraのストレージ構成は共有型であり、IOPSメトリクスはホスト毎ではなくクラスタ毎のデータとして記録されています。

 参考ページ

RDS Aurora の管理画面でモニタリングを見ると、グラフ名が
  • [請求済み] ボリューム読み取り IOPS (カウント)
  • [請求済み] ボリューム書き込み IOPS (カウント)
となっていて、ホスト別でも表示されますが、クラスタ単位で同じように見ると、配下のホスト分を同時に見れるようになっています。

具体的には、CloudWatch でみるとわかりやすいのですが、ホスト別データである DBInstanceIdentifier ではなく、クラスタ別 DBClusterIdentifier としてのデータであり、それぞれ VolumeReadIOPs | VolumeWriteIOPs であることがわかります。

このデータ、気をつける点が2つあります。

1つはデータが5分単位ということです。ドキュメントより

5 分以内の、クラスターボリュームからの課金読み取り I/O オペレーションの回数。

課金読み取りオペレーションはクラスターボリュームレベルで計算され、Aurora DB クラスター内のすべてのインスタンスから集計された後、5 分おきに報告されます。この値は、5 分間にわたる読み取りオペレーションメトリクスの値を受け取ることによって計算されます。課金読み取りオペレーションメトリクスの値を受け取って 300 秒で割ることで、1 秒あたりの課金読み取りオペレーションの回数を決定できます。たとえば、課金読み取りオペレーションが 13,686 を返す場合、1 秒あたりの課金読み取りオペレーションは 45 (13,686 / 300 = 45.62) です。


Period = 300 で取得した値を、300 で割った値が、実際の IOPS になるということです。IOPS(Input/Output Per Second)という表記をそのまま信じて読み取ると、数万~数十万IOPS ぐらいになって、1秒で10万IOPS ってどないなっとんねんクラァ!となるので、注意しましょう。

もう1つは、更新頻度です。

APIでデータを取得していると、5分間隔で更新されているようなデータに見えることもあるけれど、ちゃんとログを残して見てみると、数十分間は新データが取得できなかったりします。だいたい20分おきくらいにデータが更新されるっぽいのですが、それもマチマチっぽく不安定なので、取得条件を工夫する必要があります。

グラフとして途切れないようにするなら、30分以上前を StartTime とし、現在を EndTime、Period=300 として、Timestamp で reverse ソートしつつ1つ目のデータを 300 で割る…… と無事に、できるだけ最新のIOPS値になります。

ちゃんとやるなら、現在時間のデータがないなら未取得として、過去20分4データが入った時点で、4メトリクスとして送るのが正しいでしょうけど……そうできるかはシステム次第でしょう。

更新頻度にラグがあるのは、データベースとしては致命的とは言わないまでも、ちょっとイケてないメトリクス管理になりますね。それよりも、

IOPS(Input/Output Per Second) とは一体なんぞや。
実は単位が Per Second じゃないのかな……
それ言い出したらInputがWriteでOutputがReadだろうに、
Write IOPS , Read IOPS って重複してるやろって……

宇宙の 法則が 乱れる!

グラフの単位が嘘っぱちなのはヨクないので、(←ハメられた)
ちゃんと IOPS値にするか、Per5Minutes にでもしといてけれ!!(怒)


ホスト別IOPSは不明

IOPSメトリクスの説明の通り、アレはクラスタとしての値になります。なので、ホスト別のIOPS値は存在しない、ということになります。

Auroraで SHOW STATUS をすると、すぐわかるのですが、通常のMySQLサーバーで扱っていたような read/write 系の項目は軒並み記録されないようになっています。よーく見ると Innodb_buffer_pool_write_requests あたりが近似した数値になっていそうなのですが、確証はないので使うわけにもいきません。

ホスト単位でのIOPSがわからない、ということはクラスタ内で参照分散をした場合、どこで ReadIOPS をいっぱい発生させてしまった、とかが判断できないということになります。

各クエリ数(QPS)はメトリクスにあるので、ある程度DMLのQPSでアタリをつけるしかなさそうです。あとは、よほど重たい系ならスロークエリとか。ちょっと経験則でなんとかする場面も出そうな感じですね。


IOs費用の確認

そんな感じでメトリクスとしては少々構成が不規則&曖昧気味なIOPSなので、もし慣れてなかったり、メトリクスの収集と診察がおぼつかない状態なら、定期的にIOsの費用を確認したほうがよいかもしれません。

Auroraは優秀がゆえに多少IOPSが高くなったとしても、サービスのパフォーマンスにあまり悪化を感じさせずに動いてくれるのですが、知らないうちにIOs費用が高騰しているかもしれないからです。

IOs費用の確認は、コスト管理画面の Cost Explorer という集計ツールで見ることができ、
  • 日付範囲を指定
  • フィルタの[サービス]で”Relational Database Service”を選択
  • フィルタの[使用タイプ]で”APN1-Aurora:StorageIOUsage (IOs)”を選択

すると、Aurora の IOs に絞った日毎の費用を確認できます。


ReadIOPSに注意

これはAuroraに限った話ではないですが、Read | Write IOPS を監視するにあたって、それぞれの特徴としては

必ず一定以上の値が記録されるのは Write IOPS です。これは多くが INSERT や UPDATE によるもので、トラフィックに連動するものであり、サービスの処理として必須な消費リソースとなります。更新によるデータ容量やデータ行数、インデックス数やそのマルチカラム数なども影響し、当然大きいほどIOPSも高くなります。

必須の消費リソースとはいえ、デプロイ後などに急増した場合は、一応原因の調査を手掛けたほうがよいでしょう。

Read IOPS は、理想はゼロが望ましい値です。1以上……実践的には数百~数千となった場合、メモリからはみ出たデータをストレージから呼び出しているということなので、メモリ不足や、スロークエリの発生、広すぎる範囲への参照、データ削減の必要性、といった診断となるからです。

現実的にはReadIOゼロはできたりできなかったりですが、少なくともIOs費用の発生だけでなく、パフォーマンスの劣化にも確実につながっているので、原因を特定して改善すると一石二鳥のオイシイ対応となります。

すっげー放置した巨大データがあって、気づかぬうちにReadIOPSが高くなっても、サービスとしてはパッと見は健康的なパフォーマンス……というか許容範囲のパフォーマンスで稼働してしまうこともあるでしょう。

その状態で費用確認してみると、インスタンス費用と同じくらい支払ってた、ということもなくはないです。そうなると当然解決に乗り出すべきですが、もし早い対応ができないけど、物凄くIOs費用が高くなっていた場合、インスタンスタイプを1つ上げてメモリ容量を増やすことで、インスタンス費用は倍になるけど、IOs費用はそれ以上に下がる、という面白いパターンを見れるかもですね。


ストレージ容量を放置しない

最大64TB という実質的に上限のない容量のせいで、蓄積系のデータを放置しがちになります。そこまでガチガチに不要データを削除対応しろということではないのですが、肥大データの放置は2つの悪化要素があります。

1つは単純に容量費用が膨らむことです。
もう1つは、クエリの内容次第で ReadIOPS が発生しやすくなることです。

例えば、所有ポイントなどで数年分溜まった数百GB単位のデータがあるとして、集計対象はほぼ直近数週間の未消化データだけ必要なのに、数年分の消化済みデータも入れて集計するようなクエリがあった場合、かなりの無駄なストレージからの読み込みが毎回発生することを推測できます。実際、そのような事例で過去1年分を消しただけで数百~数千のReadIOPSがほぼゼロになったこともあります。

そもそものスキーマがってツッコミもできますが、クエリの変更やインデックスの改善だけが、ReadIOに対する対処じゃないということで、見ていて面白い事例でした。


定期的なチェックと最適化を怠らない

ioDriveやらAuroraが出るたびに、エンジニアが怠慢になりやすい環境になっていくなと感じてきましたが、ずっと我々を苦しめてきたストレージ容量とIOPS性能が苦労せずほぼ解決したことで、やはりそうなってしまうなという実態と感想です。

多少IOPSが増えてもレスポンスタイムが許容範囲なら、その改善を怠ったり、不要な蓄積データが膨大になっても、上限がほぼないがゆえに放置しがちになります。

サービスが正常に、ユーザーにストレスを与えることなく稼働している、ということは最重要ではあります。が、技術的観点で重要なのは、どのクラウドだろうと、どんなサーバー性能であろうと、データベースに必要なメトリクスをしっかり収集し、定期的もしくは重要なタイミングにおいて、変化に敏感になり、健康的なデータベースとして適した値になるよう、改善を積み重ねることだと考えます。

HDDの時代から苦労してきた勢なら、それを「言葉」ではなく「心」で理解できてると思うんですが、いきなりNANDフラッシュやらAuroraから参入した勢にとっては厳しい話になるでしょうから、それを職人芸とせずに、なんとか引き継いでいきたいところです。

昔からコーディングもデータベースもインフラもそうですが、

動いてればイィってもんじゃねーんだよ:-(
ってのを自戒を込めて:-)