この投稿は AWS Advent Calendar 2014 の 22日目の記事です。
RDS で MySQL を運用中に、想定外の CPU スパイクに悩まされたことがありましたので纏めておきます。
まずは、CloudWatch のグラフを見てみましょう。
所々で CPU スパイクが発生しているのがわかるかと思います。一見すると法則性がないようにも見えます。一般的には CPU リソースを消費する要因としては、アクセス過多やバッチ処理などで負荷をかけたケースが殆どです。しかし、今回のケースはユーザー側では何も負荷をかけておらず、RDS へのアクセスがゼロのサーバーでも同様の CPU スパイクが発生することがわかりました。
CPU スパイクの原因は?
では、CPU スパイクの原因は何だったのでしょう?その後の調査で「RDS の定期メンテナンスジョブ」が原因であることがわかりました。
以下、メンテナンスジョブの概要となります。 (公式な情報ではありませんので、今後挙動が変わる可能性もあります。ご了承ください。)
- RDS MySQL 5.5/5.6 InnoDB 環境でメンテナンスジョブの存在を確認。
- メンテナンスジョブが走るのは1日1回、メンテナンスウィンドウ外でも発生する。
- 時間帯はRDSインスタンス起動時に任意にスケジューリングされ、変更することはできない。
- MySQL の総テーブル数に比例して負荷は大きくなる。
今回、運用してた MySQL は万単位のテーブル数で運用していたため、大きな影響となっていたようです。数十、数百程度のテーブル数のケースでは、リソースへの影響はほぼなく CloudWatch のグラフでも顕著に現れてくることもないと思います。
対策
このメンテナンスジョブの一番の問題点としては、時間帯をユーザー側でコントールするのが困難なこと。ピークタイムに大きな負荷をかけてしまう可能性も当然あります。また、利用中の RDS のリソースが切迫している場合、CPU スパイクのみに留まらず、Swap が発生し、後にサーバーダウンを引き起こしてしまうこともありますので注意が必要です。
負荷を軽減するための対策について以下のようなものが考えられます。
利用していないデータベースを退避する。
参照する総テーブル数を減らすことにより、一定の効果が得られます。
インスタンスタイプを変更する。
スケールアップにより CPU スパイク時のサービスへの影響、リソースの枯渇を軽減することができます。
MySQL 5.6、innodb_file_per_table=0 で運用する。
テーブル数が多い場合、MySQL 5.6、innodb_file_per_table=0 の組み合わせで運用することにより、メモリの消費を抑えることができるようになります。
http://mysqlmaniac.com/2012/how-having-many-tables-affects-mysql-memory-usage/
まとめ
RDS の運用に限ったことではないのですが、AWS をはじめとするクラウドサービスを活用する場合、オンプレミスでは起こり得なかったことが発生する可能性がある、といったことを念頭において運用することが大切となります。また、サービスイン前の検証によって挙動が明らかになることもありますが、その後の AWS サービスアップデートなどで新たな問題に直面することもあります。(今回のメンテナンスジョブの件についても、RDS 採用時には明らかになっていなかった挙動となりました。)
基本的には一つ一つ向き合って対応していくしかありません。普段から監視システムの強化、リソースのモニタリング、ログの収集などを怠らないようにし、想定外の挙動にも柔軟に対応できるように準備をしておきましょう。