BASEプロダクトチームブログ

ネットショップ作成サービス「BASE ( https://thebase.in )」、ショッピングアプリ「BASE ( https://thebase.in/sp )」のプロダクトチームによるブログです。

AWS Aurora MySQL v3 アップグレード時のgh-ostの活躍について

BASE も Aurora MySQL v3 となりました

SRE Groupの ngsw です。 2024/10/14〜10/15の深夜メンテナンスにて、BASEで利用しているAmazon Aurora MySQLのバージョンは、v2系からv3系となりました。 アップグレードの前提条件で大きなつまずきがありましたが、gh-ost を利用することで、乗り越えることができました。 この記事では当該アップグレードの中で gh-ost をどのように利用し、どういう恩恵を受けたかについて述べていきます。

おさらい : v3 対応しないとどうなるの?

Aurora MySQL v2は標準サポート終了が発表されており、v3への移行を終えていないDBクラスターには自動的に有償の延長サポートが適用される流れです。

費用はこちらをご確認ください。そこまで安くありません。

有償サポート提供によりある程度の時間猶予が与えられたとはいえ、アップグレードを先延ばしにするメリットはほとんどありません。 たとえば、このアップグレードよりも企業にとって利益のある施策やサービスの開発/改修があればまた別の意思決定が働くでしょうが、そんな施策はそうそうないでしょう。

簡単にアップグレードできない問題

Aurora MySQL v2→v3アップグレード検証段階で問題が見つかりました。 BASEでは本番環境のデータにマスキングをほどこしたものを、開発環境で利用できるようにしています。 このマスキングしたDB Clusterで、以下にあるようなインプレースアップグレードの検証を行いましたが、エラーのためアップグレード処理は停止してしまいました。

停止理由はupgrade-prechecks.log をみることで確認ができます。

原因となる問題は大きく二つありました。

  1. mysql.event に関するアップグレード時の不整合エラー
  2. 多数のテーブルに古いディスクフォーマットで datetime型カラムが作成されていたためのエラー

mysql.event に関するアップグレード時の不整合エラー

AWS サポートにより対応いただけました。 こちらは数日程度で解決でき、検証作業をブロックするほどの問題ではありませんでした。

多数のテーブルに古いディスクフォーマットで datetime型カラムが作成されていたためのエラー

問題はこちらのエラーです。

MySQL :: MySQL 8.0: Removing support for old temporal datatypes

解決方法が「当該カラムを持つテーブルを新しく再作成する」ということになり、

  • Dump & Restoreする
  • ALTER TABLE {table_name} FORCE;

というような、つまりv2上で CREATE TABLE 相当のことを行う必要がありました。

おそらくはMySQL5.6以前のAWSのRDSで稼働し、そのままAuroraに引き継がれてきたテーブルで、かつ datetime型カラムを含むものがこの対象となるのでしょう。 Aurora からサービスを開始したプロダクトなどでは見ることがないエラーなのかもしれません。

どのような困難が伴うか

このあとに控える困難を想像し頭を抱えてしまった理由、今回の datetime型カラム再作成対象となった2つのDB Cluster、XとYについて説明します。 X はショップの情報や商品の情報などを持ちます。 Y は各種履歴などが蓄積されています。

以下に規模感を記載します。

対象テーブル数とその合計サイズ

テーブル数 容量
X全体 976tables 約7.5TB
対象テーブル 268tables 600GiB

対象テーブルはDB Clusterのデータサイズにして全体の約8% 4テーブルあれば、うち1つが対象という形。

テーブル数 容量
Y全体 236tables 約5.3TB
対象テーブル 37tables 615GiB

対象テーブルはDB Cluster のデータサイズにして全体の約11% 10テーブルあれば、うち1つか2つが対象という形。

結論としてこれだけのテーブルに対して、 なるべくサービス無停止でALTER文を発行しきる必要があります。

前提として、

  • 当該アップグレードのメンテナンスは1回の深夜メンテナンスで行う
  • 全断して行う予定であるが、メンテナンス時間は5〜6時間程度しかとれない

というのがありました。 当初はメンテナンス時間の中で当該テーブルに対してdump&restoreするなども考えましたが、 実行時間的に無理だということがわかりました。1

オンラインスキーマチェンジ/オンラインスキーママイグレーションツール

メンテ当日にALTER TABLE or Dump/Restore + upgrade すべてを行うことは(当然に)無理、ということがわかりました。 それならばメンテ当日までに事前に下準備として行う方法を考えました。 下準備として、ということから暗黙的に無停止でなければなりません。

サービス無停止でALTER TABLE発行というところから、オンラインスキーマチェンジ/オンラインスキーママイグレーションツールに行き着くでしょう。 わたしはこの手のツールの利用経験がなかったため、ひとまず以下を候補にあげました。 2

結果として、われわれは gh-ost をはじめに検証し、目的に際し十分であると考え、そのまま今回の作業遂行ツールとして採用しました。 以下の理由から gh-ost の検証を優先し、結果的にわれわれの要件的には gh-ost で十分ということがわかったため、pt-osc の検証自体をスキップしました。

pt-oscよりgh-ostを優先して検証候補にした理由は以下になります。

  • pt-oscを選ばなかった : pt-osc では元テーブルと新テーブルの同期にトリガーが採用されており、トリガー利用による負荷が、サービス提供にどのように影響を与えるのか懸念し、検証優先度を下げた
  • gh-ostを選んだ : 処理時間は長くなりそうではあるが、DB負荷自体は軽そうに思えたため
  • gh-ostを選んだ : 一番の懸念であったDB Cluster Xでbinlog replicationをすでに運用していたため、gh-ost利用適正が高いだろうと思えたため
  • そもそも pt-osc は完了までの処理速度を、gh-ost は小さな負荷での実行(つまりサービス影響の最小化)を重視しているよう思え、今回は後者の哲学を支持したため

gh-ost

簡単にgh-ostの特徴および利用しての実感を書きます。

特徴については gh-ost/README.md at master · github/gh-ost を読むとわかりやすいです。

  • 複数方式があるが、replication側からbinlogを取得するパターンが推奨されている
  • 別名テーブルに元テーブルからデータを抽出して挿入する、更新分はbinlogで対応する
  • 負荷が高くなると自動でthrottlingする
    • 指定ファイルをtouchすれば、手動でthrottlingさせることもできる
  • なにかしらのエラーが発生して処理途中で落ちた場合、また作業途中であった別名テーブルを削除して、最初から実行する必要がある
  • 1テーブルにあたり、とてもゆっくり動くので対象テーブルデータ量によっては業務時間内に1テーブル終わるかわからないくらい
  • 別名テーブルと元テーブルを切り替える処理をcut-overというが、この時間を指定することもできる(夜中に切り替えたい、昼間に切り替えたくない場合などに有効)

cut-over という単語が出てきましたが gh-ostでは「ALTER TABLE用の別名テーブルを対象テーブルに変名し本番運用へと切り替える」ことをいいます。

gh-ost/doc/cut-over.md at master · github/gh-ost

利用していた実感では cut-overに至るまではまったく問題が起きませんでした。 明示的な問題として1回だけ発生したのは cut-overタイミングと更新タイミングが噛み合ったときに、cut-overが止まってしまうという現象でした。 一度gh-ostの処理をとめ、新たにやり直すだけで解消するので、cut-over間近のタイミングだけ気にしておけばよい、という形で以後の作業もすすめることができました。

gh-ost の好きなところ

個人的に gh-ost で気に入ったところも書いておきましょう。

  • sock fileを経由することで対話式にコマンド実行が可能
  • 処理が遅いのだけが欠点、実運用への副作用がまったくといっていいほどない

という感じです。

最終的にはほとんど放置して、一日の終わりに進捗状況を確認する程度になりました。 運用作業者(ひいてはサービス)に優しいツールだなと感じました。

参考 : 実際の作業スケジュール

当初は本番作業時にどのような影響がでるかわからなかったため、開発陣に対象テーブルのリストとALTER TABLE実行スケジュールを共有するようしました。 うまくいっても08月上旬から09月末くらいかかるのではないかと不安でしたが、gh-ostのおかげで08/08〜08/26という想定よりも短い期間で終えることができました。

データ総量が作業時間を左右する傾向がみられたため、見積もりのため以下のようなクエリでテーブルごとのデータの一覧を出しています。 total_sizeを主に見て実行時間の見積もりを行っていました。

SELECT
  table_schema,
  table_name,
  data_length AS `data_size`,
  index_length AS `index_size`,
  (data_length + index_length) AS `total_size`,
  table_comment AS `comment`
FROM
  information_schema.TABLES
WHERE
  table_schema != 'sys'
AND
  table_schema != 'information_schema'
AND
  table_schema != 'performance_schema'
GROUP BY
  table_schema, TABLE_NAME
ORDER BY
  total_size DESC;

注意点1

今回Aurora v2 -> v3 へのアップグレードだったため、gh-ost のバージョンは v1.1.5 を採用しています。

注意点2

第140回 オンラインスキーママイグレーションツール gh-ostを使ってみよう[その3] | gihyo.jp には以下のような記述があります。

ユニークキーの追加

gh-ostを使用して、ユニークキーを追加することは可能です。
しかし、ユニークキーを追加するカラムの値が事前にユニークな値になっていることを確認してから実行しないと、
データがなくなってしまう恐れがあります。

われわれの今回の作業においては関係がなかったものですが、この記事より興味をもって利用される方においては、用途によっては気にしていただきたい内容であるため、ここに引用しました

参考URL

今回のタスクでは以下のDocumentを参考にしました

BASEでは随時メンバーを募集しています。 2024.10現在、私の所属するSRE Groupの募集はないようですが、興味を持たれた読者諸氏におかれましては、以下リンク先をご覧いただければ幸いです。 採用情報 | BASE, Inc. - BASE, Inc.


  1. 検証ではdumpだけで想定メンテナンス時間をすべて消費してしまうことがわかりました
  2. チーム内にこれらツールの検証目的の過去Issuesが立っていたため