こんにちは。クルーズ株式会社CTOの鈴木です。
「SHOPLISTの脱レガシーシステム」の記事も5回目となりました。
今回はDBインスタンスのリプレイスの障壁となりそうなDBのテーブル容量を減らす話です。
今までメンテナンスを定期的に実施できなかった弊害
「SHOPLIST.com のシステムをモダンなアーキテクチャに変えようとしたら予想以上に闇が深かった話」でも触れた通り、今までほとんどメンテナンスが行われていなかったため、メンテナンスを行わないとサービスに影響が出るような作業が未着手となっていました。
その結果、DBの容量も日々膨張し、1.6TB、テーブル数も全スキーマを合算すると1,800を超える状況となってしまっていました。
・DB容量⇒BackUp &Restoreや今回のようなリプレイス時の作業時間
・テーブル件数⇒可読性
にそれぞれ影響が出る可能性ものなので、仕様上許容される範囲で少ないこしたことは無く、まずはDB容量を減らす算段を立てました。
容量削減対象のテーブルと容量の洗い出し
容量削減に際し、まず以下の3つの視点でテーブルを洗い出しました。
⓵昨年度(2019-04-01)以降にデータ更新が行われていないテーブル
⇒要するに、「機能終了時の消し忘れ?いらなくね?」というテーブル。
②論理削除フラグが立っているデータが全レコードの50%以上のテーブル
⇒「いらなくない?そのデータ。」があるかもしれないテーブル。
③エンジニアへのヒアリングでデータを使っていない可能性のあるテーブル
⇒データ更新はされてるけどいらないかもしれないテーブル。
この3つの視点で各テーブルのデータを調査し、最終的に15テーブル、データ容量にして合計で515GB(元のDB容量の32%分)のデータについて本番のDBインスタンスから削除可能であることが分かりました。
本番DBインスタンスからのデータ退避を計画する
本番DBインスタンスからのデータ退避については以下3方針としました。
⓵サービス上も業務上も不要なものはTruncateもしくはDelete。
②サービス上で不要だけど調査や分析で必要なものはSubDBに退避。
③削除フラグが50%以上のものは、テーブル名を別名に変更し、新規作成テーブルに削除フラグが立っていないデータのみインサート、元テーブルは⓵または②で対処。
SubDBというのは今回のインフラ構成変更のタイミングで用意したDBインスタンスで、データ保管コストを安くするために準備した退避専用のDBインスタンスです。サービスに投入しているDBインスタンスとの違いについては、インスタンスサイズが小さく割り当てられているシステムリソースが本番DBインスタンスの半分以下であること、本番DBインスタンスのSlave台数が6~10台(セール状況により変動)なのに対しSlave1台の合計2台構成であることと、InnoDBテーブルの圧縮設定がデフォルトでしていることです。InnoDBのテーブル圧縮機能についての検証結果については「MariaDBのテーブル圧縮の検証を検証した話」に投稿してあるので興味のある方は確認してみてください。
今回データ削除を行う15テーブルについて、Backup環境で事前にデータ退避を行う際と同じオペレーションを事前に実施し、実際にかかる時間を算出したところトータルで5時間、余裕を見て6時間ほどの作業時間が必要であることが分かり、メンテで作業可能な時間が4.5時間しか取れない状況だったため、実際にはデータ退避は2回のメンテナンスをに分けて実施することにしました。
第1回目の計画メンテナンスを行う
第1回目の計画メンテナンスは2020年の9月2週に実施しました。ただこの際はすべてのメンテナンス時間がデータ退避以外にも、EC2インスタンスをMulti-AZ化するためのVPC上ネットワーク構成の変更、その他メンテ中でないと実施できないテーブル構成の変更、インデックス付与などの作業があり、メンテナンス時間フルフルを今回のデータ退避作業に使えない状況だったので、15テーブルのうちの4テーブル、容量にして約300GBについてデータ退避を行う作業計画を立て、当日のメンテナンスに臨みました。
メンテ開始時直後、メンテ表示の不具合調査で作業時間が30分なくなる
うそでしょwと思うかもしれないのですが、メンテナンスに入った直後にメンテナンス画面の表示(メンテナンス明け日時)に誤りがあることが発覚して、原因箇所の特定で30分ほど意図しない作業が発生してしまいました。定期的にメンテナンスを行っていないと、メンテナンス時のナレッジも陳腐化してしまいこのような問題も発生してしまうようです。
調べて分かったことなのですが、メンテナンスの案内のテキストなのですがどうやら複数箇所で設定しているらしく、今回は片方のテキスト設定が漏れたため表示誤りが発生していたようです。
データ退避作業を開始する
その後DB作業ができるようになったため、ほかの作業と並行しながらdumpでバックアップを取得してその後データ退避を行っていったのですが、なぜかテーブルのdumpの実行速度が遅く、結局4テーブル中3テーブル、サイズにして約265GBまでしか実行できず、残り1テーブルについては2度目の計画メンテナンスに回しました。
第2回目の計画メンテナンスを行う
第2回目の計画メンテナンスは第1回目の計画メンテナンスの2週間後に実施しました。
このメンテナンスのゴールは前回データ退避のできなかった1テーブルを含む12テーブル、データサイズにして残りの約265GBを本番DBインスタンスから退避することです。
前回の反省点として、本番インスタンスのdump取得にかかる時間が事前検証を元に算出した時間を超えてしまっていたため、今回は作業時間の削減のために複数テーブルを並行して実施しました。
メンテ開始時直後、メンテ表示のステータスコードでトラブる
実は今回のメンテナンスに合わせてメンテナンスアナウンス時にブラウザに返すHTTPのステータスコードの変更をする修正を入れたのですがそれが正常に動作しておらずブラウザ表示としては正常なのですが、返しているステータスコードが異なるという問題が起こり、原因調査のためDB作業開始が少し遅れました。
データ退避作業、無事完了する
その後、複数テーブル並行してdumpとデータ退避を行い何とか今回行いたかった合計15テーブル、データ量にして約515GBのデータ退避が完了しました。
但し、第1回目のメンテナンス時に既存テーブルに対するインデックスの追加作業があったためDB容量は約80GB増えてしまい最終的には約1.2TBのDB容量となりました。
まとめ
今回の教訓としては
⓵計画メンテナンスが本当に機会損失で絶対にメンテナンスを入れたくない、もしくは回数をできる限り最小にしたいのであれば、何でもかんでもDBに突っ込むべきじゃない。
なぜならデータ削除の際にスレーブ遅延を起こすのでサービス稼働中に消込ができないから。業務にしか使用しないのであればテキストで吐いてバッチで別DBに突っ込むとかやり方はあるため。
②論理削除を前提とする設計を極力しない。
なぜならdeleteではidbファイルのサイズが減るわけじゃないから。
③とはいっても計画メンテナンスを行わないは論外。
目標として目指すはいいけど、メンテ中でないと出来ないことは事実としてあるし、先送りし続けると今回みたいなことになるし、データ保管コストも発生する。
以上です。
-------------------------------------------------------------------------------------------------
※2020年の内容を記事にしており、2020年11月以降PHP7サポート切れをはじめとした脆弱性リスクへの対処は完了しております。