はじめに
クラウドファンディングプラットフォーム Makuake でウェブオペレーションをメインで担当している吉田慶章 ( @kakakakakku ) です.Developers Blog では,過去に『Well-Architected を目指した改善と組織文化への影響』を執筆したり,『「経営層を巻き込まないと開発組織は変わらない」――急成長するクラウドファンディングサービス「Makuake」エンジニアが社長と取り組んだこと』で組織変革をテーマにしたインタビューを受けたりしています.今回はサービスで使っているデータベースを MySQL 5.5 on EC2 から Amazon Aurora(以下,Aurora)に完全に移行した事例を紹介したいと思います.既にリリースをして約1ヶ月稼働していますが,大きな問題もなく安定稼働しています.
背景
例えばウェブサーバなど,既にスケールアウトが前提になったアーキテクチャの場合,一時的にインスタンスをサービスアウトしたり,検証用のインスタンスを並行稼動させたり,無停止で技術的負債を改善する方法はいくらでもあります.しかし,技術的負債を改善するときに困るのは,1台構成だったり,フェイルオーバーができなかったり,完全に SPOF になっているアーキテクチャです.サービスで使っている MySQL は今まで EC2 上で稼働していて,サービスをリリースしてから約3年間以上,1度も止まることなく稼働し続けていました.私がウェブオペレーションをメインで担当するようになって約1年ですが,もし近い将来に大規模障害が起きるとするならば,この MySQL なのではないかなと予想していました.よって,大規模障害が発生する前に,リプレイスしなければと考えていました.
また去年の夏頃に,本番環境でスレーブとして稼働させているインスタンスが,Scheduled Events (system-reboot) の対象となってしまったため,一時的にスレーブを参照をしないようにアプリケーションを修正したり,社内サービスを停止したり,運用面で様々な工夫をする必要がありました.このような経験からも,データベースの運用を改善したいという思いが日々強くなっていました.
課題を整理した
「データベースの運用を改善する」というプロジェクトを立ち上げる前に,まず現状の課題を全て洗い出して,分類してみました.すると,以下のように分類することができました(本当はもっと多くの課題がありましたが!).
- アーキテクチャの課題
- フェイルオーバーができない
- MySQL のバージョンアップができない
- 1TB 以上の EBS (Magnetic) がアタッチされているのに,ほぼ使われていない
- 分析用のクエリが本番環境のスレーブに投げられて,スレーブが高負荷状態になってしまう
- 運用面の課題
- MySQL のメトリクスをモニタリングできていない
- mysqldump の結果にポジションが含まれていない
- アプリケーションの課題
- 不要なテーブルやデータが大量に残っている
- スレーブがアプリケーションからほとんど参照されていない
- アプリケーションが非効率なクエリを発行している
このように課題を洗い出してみたところ,今すぐに改善できる部分も多いと感じました.特に「運用面の課題」と「アプリケーションの課題」です.そこで,「運用面の課題」と「アプリケーションの課題」の部分から改善に着手することにし,「アーキテクチャの課題」の部分は,Aurora に移行することによって改善しようと考えました.また「運用面の課題」として挙げた「MySQL のメトリクス」に関しては,Aurora の見積もりをする際にも必要になることがわかっていたため,最優先で着手しました.
「運用面の課題」を改善する
MySQL のメトリクスをモニタリングできるようにした
以前の記事にも書いた通り,私の口癖は「全てはモニタリングから始まるんだ!」です.MySQL では mysqladmin extended-status
コマンドと mysqladmin variables
コマンドを使うと,様々なメトリクスを取得することができます.今回は以下のメトリクスを中心に取得し,Zabbix でモニタリングをできるようにしました.
- コネクション数(
Connections
) - ハンドラー(
Handler_*
) - セレクト種別(
Select_*
) - ステートメント件数(
Com_*
) - スレッド数(
Threads_*
) - InnoDB 情報(
Innodb_*
)
具体的なメトリクスを紹介します.まず InnoDB Buffer Pool の使用率をモニタリングできるようにしました.mysqladmin extended-status
の結果から buffer_pool_pages_total
と buffer_pool_pages_free
のメトリクスを取得し,Zabbix の計算機能を使って,buffer_pool_free_percentage
というアイテムを作りました.InnoDB Buffer Pool のサイズ見積もりの参考にしました.
他には SELECT / INSERT などのステートメント件数も取得しました.日々の QPS を把握できるようになったため,負荷対策の参考にしたり,SysBench で負荷テストを行うときのベースラインとしても参考にしました.
mysqldump の結果にポジションを含めた
MySQL の運用に慣れた人であれば当たり前だと思いますが,mysqldump の設定を見たところ,ポジションが含まれていないことに気付きました.後述する Aurora Writer に対するレプリケーション設定のために必要だったため,--master-data=2
オプションを追加して,コメント形式でポジションを含めるようにしました.
「アプリケーションの課題」を改善する
不要なテーブルやデータを削除した
不要なテーブルやデータが大量に残っていたため,データベースのサイズ見積もりがしにくいと感じていました.まず,不要なテーブルを洗い出し,最終的に約20テーブルも消すことができました.さらに,削除したテーブルに関連するソースコードも全て消すことができたため,アプリケーションコードもスリムになったという相乗効果もありました.
次に不要なデータを洗い出しました.具体的には,アプリケーションから参照される可能性がない過去の集計データが大量に残っていることに気付きました.日々多くのバッチを実行していますが,それぞれに過去データを削除するハウスキーピング処理を実装しました.最終的に1000万件以上の不要なレコードを削除することができました.
アプリケーションから積極的にスレーブを参照するようにした
ステートメント件数のメトリクスを可視化したことにより,スレーブに対してほとんどクエリが発行されていないことに気付きました.そこで,影響の少ない機能や,ある程度のラグが許容できる機能で,積極的にスレーブを参照するようにアプリケーションを修正しました.マスターの負荷を下げることができるという効果だけではなく,Aurora 移行のフェーズ1として,Aurora Reader に切り替える予定があったため,その準備にもなりました.
非効率なクエリを減らした
スレーブを参照するだけではなく,一般的なパフォーマンス改善施策も実施しました.具体的には,スロークエリを減らしたり,テーブルスキャンになっているテーブルにインデックスを貼ったり,N + 1 を撲滅したりしました.常にインフラ側でチューニングをするのではなく,アプリケーションの実装を見直した方が抜本的な改善に繋がることも多いと考えています.
「アーキテクチャの課題」を改善するための Aurora 移行
上記にまとめた通り,既存のデータベースを稼働させたままでも,様々な改善ができました.この時点でも十分に運用しやすくなりましたし,負荷を予測可能な状態に近付けることができました.
次は「アーキテクチャの課題」を改善するために,Aurora に移行することを考えました.最初は RDS for MySQL も候補として考えていましたが,高速なフェイルオーバーができること,ディスクが自動的に拡張されること,レプリケーション遅延が限りなくゼロに近いこと,クエリのスループットが高いことを評価し,今回 Aurora を導入することに決めました.なお,今回の記事では Aurora の詳細なアーキテクチャに関しては言及しないため,AWS Black Belt の資料などを参照して頂ければと思います(リンク).
Aurora 移行フェージング
では,今回どのように MySQL on EC2 から Aurora に移行したのかという,フェージング計画を紹介します.
フェーズ1. Aurora Writer にリストアをする
まず,新規に構築した Aurora Writer に対して,MySQL on EC2 で取得している日次のバックアップからリストアを行いました.AWS のドキュメントにも記載がありますが,Percona XtraBackup を使うと,より高速にリストアを行うことができます.ただし,今回は環境面の制約(技術的負債)で使うことができず,mysqldump を使うことにしました.
フェーズ2. Aurora Writer にレプリケーションを設定する
次に MySQL on EC2 (Slave) から Aurora Writer に対してレプリケーションを設定しました.RDS では CHANGE MASTER TO
コマンドを実行することができないため,RDS 側に登録されているストアドプロシージャを使う必要があります.
フェーズ3. Aurora Reader を参照する
ここで,アプリケーション側をリリースして,参照系のデータベースを Aurora Reader に切り替えました.モニタリングをしていましたが,MySQL on EC2 (Master) から Aurora Reader のレプリケーション遅延はほとんど無く,問題はありませんでした.
フェーズ4. メンテナンス中に更新系を切り替える
今回は,今まで別のデータベースで管理していた MySQL on EC2 (Report) を統合する作業が必要だっただけではなく,移行を慎重に進めたいと考えていたため,無停止での切り替えではなく,計画メンテナンスを実施しました.どんな状況でも無停止が良いとは考えていなく,メリデメを考えて,無停止を目指すかどうかを選択するのが良いのではないかと思います.
メンテナンス中は全ての更新が止まるため,その間に MySQL on EC2 (Slave) から Aurora Writer に対するレプリケーションを停止し,MySQL on EC2 (Report) の全データを直接流し込みました.最後にアプリケーション側をリリースして,更新系も含めて全ての接続を Aurora に切り替えました.
フェーズ5. 最終型
最後は,移行が完了した現在の構成図です.特徴は Aurora のスロークエリを Fluentd 経由で Amazon ES に転送している点と,Redash で分析ができるようになった点です.
「アーキテクチャの課題」を改善する
分析用の Aurora Reader を構築した
今までは,分析用のクエリが本番環境のスレーブに投げられて,スレーブが高負荷状態になってしまうことがありました.その度にアラートが鳴るため,SHOW PROCESSLIST
を叩いて,クエリを強制終了することもありました.
今回は分析用の Aurora Reader を用意し,全てをそこに集約させました.また,負荷とコストを考慮して db.t2.medium
にしていますが,CPUCreditBalance のメトリクスを見ると,今のところ問題はありません.また,フェイルオーバー時に昇格しないように,優先度 (Tier) の範囲は下げて設定しています.
また,今回 Aurora 移行に合わせて,Redash の導入も行いました.今まで分析クエリをアドホックに実行していた運用を Redash に統一することにより,データ分析の民主化を推進したいと考えていました.
運用検証も忘れずに
記事も長くなってきたため,今回はザッと紹介するに留めますが,リリースをする前に,運用面で気になることは全て検証しました.
- 負荷検証
- 障害検証
- リストア検証
「負荷検証」では SysBench を使ったベンチマークと本番相当のデータ量を使った検証を行いました.「障害検証」では ALTER SYSTEM CRASH
という擬似的に Aurora の障害をシュミレートすることができる機能があるため(リンク),実際に障害をシュミレートし,どの程度の影響があるのかを見極めました.また「リストア検証」では実際にスナップショットからリストアをして,アプリケーションを復旧させる手順を確認しました.
Aurora に移行して良かったこと
最後に Aurora に移行して良かったことをまとめたいと思います.まず,クエリのパフォーマンスが早くなりました.New Relic で計測している結果を見ると,2倍以上の効果がありました.
次に運用面です.高速なフェイルオーバーや継続的なパッチ適用など,今までできていなかった部分に大きな価値を感じています.また Aurora は db.t2.small
と db.t2.medium
を選択できるため,開発環境のコスト削減にも繋がりました.
また今までは直接データベースインスタンスに ssh をして確認していたスロークエリを Amazon Elasticsearch Service (Kibana) で可視化できるようになったのも便利だなと感じています.スロークエリの閾値を5秒に設定していますが,現在のところ1件も出ていないため,出て欲しくないけど,出て欲しいという,複雑な気持ちです.
まとめ
Aurora 移行をキッカケに,データベース運用,モニタリング,アプリケーションパフォーマンスなど,様々な改善を行うことができました.また MySQL on EC2 から Aurora にキレイに移行することができたと感じています.そして Aurora に移行したことにより,クエリのパフォーマンスやデータベース運用など多くのメリットを感じることができました.Aurora 最高です!