AWS RDS/AuroraのDDL運用を最適化する

AWS re:Invent 2022 にて RDS の Blue/Green が発表されたことを受けて、この辺の具体的な運用をどのように改善できるのか考えていきます。

たいした内容ではないですが、丁寧に最適化して慣れれば、それなりに強い効果を発揮できそうな感じはあります。



ALTER TABLE の辛み

まず復習からですが、RDS に Blue/Green が実装されるほど辛い運用はなんだったかというと、重い ALTER TABLE にあります。

ALTER には色々あるのでアレですが大雑把に言うと、容量や行数が大きいテーブルに対して実行すると、数時間単位~の処理時間がかかることが多く、しかもパッと見で進捗を把握できないという問題を抱えていました。それに対して色んな対策を取っていたと思います。例えば……

Handler_write

SHOW GLOBAL STATUS LIKE ‘Handler_write’; の値で進捗を確認するというもの。

テーブルコピーが発生するような、カラム追加などの場合は役に立ちますが、基本的に INSERT に対する値なので役に立たない ALTER もあり万能ではありません。

TMPデータ

フルマネージドではない、自己管理 mysqld の場合、データディレクトリに #sql-.frm , #sql-.ibd のような TMPデータが作成されるのを確認できるため、その容量変化を追うことで終了時間を推測することができました。

が、クラウドでは意味のない知識であります。

事前検証

いざメンテインからの本番実行で、何時間かかるかわかりません!だとメンテ計画が立たないので、事前にバックアップからリストアした検証環境で、同様のクエリを発行して実行時間や STATUS を記録し、計画や進捗確認に利用する、といった運用です。

しかし、検証サーバーと本番サーバーはあくまで別物なので、実は本番のパフォーマンスが悪かった、とか想定外の事象で 10時間想定が 20時間に延びた、というのもなくはなく、確実性という意味ではあと一歩でした。


RDS Blue/Green

で、そういった悩みをほぼ一掃する発表がこちら。


挙動をザックリまとめるとこんな感じ。

  • 対象はMySQL互換 5.6 以降の RDS/Aurora
  • 現行 production (Blue) の binlog を有効にし(OFF → MIXED)
  • 新規 staging (Green) を起動し、レプリケーションを開始
  • staging でスキーマ変更を行う。ただし対応処理は以下
    • テーブル末尾へのカラム追加
    • インデックスの作成と削除
  • Blue/Green切り替え発動時、双方に1分程の書き込みロックが発生
  • Green が production になり、Blue だった production は残るので不要になったら削除

データの同期はレプリケーションなので、バイナリログのクエリ適用でエラーが出るような処理はダメってのと、

説明には本番環境のトラフィックが少ないときを推奨、って書いてあるけど、切り替え時は書き込みロックが発生するので、サービス稼働中にサラッとやっていいものではないし、ECSのような他サービスと連携した Blue/Green というわけでもないです。

制約もいくつかありますが、それらを許容できれば長時間DDLを事前に済ませることができ、計画メンテナンスの時間を大幅に短縮できる可能性があります。


INSTANT DDL

MySQL 8.0.12 以降には INSTANT DDL という仕組みがあります。


AWS Aurora 3 (8.0.23) でも、この機能はちゃんとあり、多少カラムの並びが汚くなることを我慢すれば、数時間の処理を丸ごと秒にできます。


いくつか条件があり、それを満たす必要はありますが、さほど難しい条件はありません。多くの場合、パーティションが切られていないテーブルに対しての、NULLを許容した最後尾へのカラム追加ならば、適用されて秒で終わることができます。

==追記 始==
上記条件は Aurora 2 での話であり、Aurora 3 ではコミュニティMySQL 8.0 のインスタントDDLと互換性がある、とドキュメントにも書いてあるので、本家8.0 の説明を参考にしてください
==追記 終==

本家の条件と異なる部分があり、例えば本家では ROW_FORMAT=COMPRESSED は非対応とあるのに、RDS Aurora に書いていないのは、そもそも Aurora では COMPRESSED 自体が非対応だから、と思われます。全く同じなわけではない以上、動作確認は Aurora 上でするのが筋ですが、数回試せば大丈夫感は掴めるでしょう。

並び順については、例えば Rails だと id, created_at, updated_at というカラムがありますが、id を先頭、DATETIME を最後尾にしていると、追加カラムは真ん中で位置指定をしたくなります。しかしそれをやると INSTANT DDL にならなくテーブルコピーが発生してしまうので、必須系カラムは全て先頭にするよう設計することで、キレイ好きにも位置指定不要な運用にできるでしょう。


使い分け

では実際の運用ではどのように使っていくかですが、まずは使用されやすい DDL についてまとめてみると……

処理メンテより短いメンテより長い
INSTANT DDL なカラム追加秒で終わる
通常のカラム追加/削除/変更数分~数時間数時間以上
インデックス追加/削除数分~数時間数時間以上
これらをサービスのオンライン中にやるか、メンテ中にやるかについては、オンラインでやれるものがあるとしても、それはアプリケーションによって可否が異なるので、今回はメンテ中にやることを前提とします。

そしてメンテナンス時はデータベースの作業だけではなく、アプリケーションの更新やプラットフォームへの反映待ちなど色々あるので、数時間単位のメンテナンスになるということで考えていきます。

Blue/Green 不要

変更点が INSTANT DDL のみ、もしくはそれ以外の変更にかかる時間がメンテナンス時間以下の場合、いちいち Blue/Green を使わずにメンテ中に作業を済ませる方が無難と思われます。

これまでと同じ運用になるし、Blue/Green用の作業・費用が不要になるので、無理に使っていく必要はないということですが、要不要をいちいち確認・判断しないで運用を統一するという意味では、この選択を破棄して Blue/Green のみにするってのもアリかもしれません。

Blue/Green 採用

Blue/Green の恩恵を大きく受けられるのは以下のような場合と思われます。

  • 通常のメンテナンス時間を大きく上回る変更処理になる
  • データベース処理をカットしてメンテナンス時間を大幅に短縮したい
  • 事前に完全な staging としてのテストを行いたい
  • 本番でのみ起こるかもしれない想定外の事象を回避したい

適用できれば、それまで数時間だったところを数分に短縮でき、かつ色々安定するので、標準的な手法に確立するのもよし、ピンポイントで困った時のために手順の検証だけしておくのもよし、ってところでしょうか。少なくとも知っておいて損はない仕組みだと思います。


その他

いくつか補足情報をば。


バイナリログ

binlog について、有効化の方法や保存期間はドキュメントに書いてあるのですが、容量上限や費用については記載が見当たりませんでした。

有効/無効にするには Writer の再起動が必要になるので、Blue/Green を採用する場合の多くはずっと有効にすることになるでしょうし、モノによっては容量が激しいことになるので気をつけたいポイントではあります。

が、書いてないので気になる場合は容量制限と費用についてサポートに確認するとよいでしょう。

Blue/Green 費用

よくある質問に書いてある通り、Green 起動中は丸ごと費用が2倍になるので、それなりに計画的な利用を心がけることになります。

通常1クラスタ30日分のところ、Green を3日間起動したら、そのクラスタは33日分と1割増しになります。全体の費用から見たらそこまでインパクトはないですが、ダラダラ取り扱う感じは避け、キリッとメリハリつけた計画でお安く済ませましょう。



長期間運用されたサービスのテーブルデータは TBクラスになっていることもあり、それを計画的に扱うために事前検証をして、本番でも長時間待機する、みたいな運用が必要でした。こういう必要だけど虚無な時間を、設計の工夫や、少しのお金と手間をかけて先に時間と安全を確保するってのはとても良いことだと思います。

また、長時間処理の進捗がパッと見でわからないってのはエンジニアのストレスにもなるので、データベースに限らず長時間を必要とする処理を作る時は、雑でもいいから必ず進捗がわかるようにコーディングするようにしています:-)