DBaaS(MySQL)で構成ドリフト問題と戦っている話

Loading...

はじめに

はじめまして! KCS部DSREチームの rom です。

KCS部は,KADOKAWAグループ向けプライベートクラウド(以下KCS)を提供しており,主な利用者は株式会社ドワンゴがサービスを提供している「niconico」です。 私の所属しているDSREチームでは,MySQLやRedis,Elasticsearch/KibanaといったDatastore関連のミドルウェアをマネージドサービスとして,KADOKAWAのグループ会社に提供しています。

今回は,DBaaS(MySQL)の運用で発生している構成ドリフト問題と戦っていることについて紹介します。

DBaaS(MySQL)とは

KCSがKADOKAWAグループ向けに提供しているMySQLの基盤サービスです。 構成は以下の通りです。

  • バージョン:MySQL 5.7系
  • MySQL数(概算):450
  • masterの総データ量:3TB

DSREチームによって全て構築・運用されています。 詳細は,がんばらないDBaaSの作り方 を参照ください。

構成ドリフト問題

一時的な変更がそのままに

DBaaS(MySQL)では,VMの構成はオートメーションツールのAnsibleで管理しています。 ただし,障害発生で緊急性があるときは,一次対応として定形のAnsible Playbook以外で設定を変更する場合があります。

実際に,特殊なワークロードで使用されるVMで監視エージェント自体がパフォーマンスに影響を及ぼすことが発覚し該当監視エージェントを止めたり, バックアップジョブがパフォーマンスに影響を及ぼしていたためジョブの設定を変更した,などがありました。

これらの一時的な変更は,根本解決を行い元の設定に戻すか,変更した設定をAnsibleに追加してコード管理する必要があります。 しかし,解決後の経過観察期間が長くなってしまったり,緊急で対応を行なったため変更した部分が曖昧となり,そのままの状態で放置されてしまうことがあります。

一時的な変更を運用者間で完全に共有されていれば良いのですが,チームにジョインしたばかりの私が何も知らずに普段の更新作業を行い,設定が元に戻り障害が再発してしまうということもありました。

Playbookを全体に流さなくなって1年が経過した...

Ansibleは全体のPlaybookを定期的に流すことで,コードと実際の構成が同期されます。 しかし,以下の理由から,Ansibleを変更した時は,全体のPlaybookを流さずに変更部分のパッチをあてる運用が行なわれていました。

リソース不足から全体のPlaybookを流すとVMからの応答がなくなる

監視エージェントの追加やカーネルアップデートなどの日々の機能追加により,MySQL以外の部分で消費するリソースが増加していきました。 また,年単位で長期間運用していく中で,buffer pool をスケールアップなどして,MySQLが使用するメモリも増えてきています。

f:id:kdx_writer:20201013183128p:plain
リソースの空き容量の変化

空きリソースに余裕がなくなっていき,全体のPlaybookを流すと必ずいくつかのVMでAnsibleが応答しなくなることが発生していました。 毎回の更新でいくつかのVMで応答がなくなるため,更新作業は慎重に行う必要があり,かなりストレスの伴う作業となっていました。

大規模となり全VMに全体のPlaybookを流すのに数時間かかる

DBaaS(MySQL)は,現在400台の規模となっています。400台全てのAnsibleを流すと,10並列で数十時間ほどかかってしまいます。 リソース不足の問題から更新作業中はVM応答がなくなる場合があるため,注意深く更新を見守る必要があります。 数十時間の間注意を払うのはかなり辛いものがあります。

変更と時間が経過するたびに恐怖が増していった

日々の更新によりPlaybookは変化します。全体のPlaybookを流さない期間が長くなるにつれて,最新のPlaybookとVMの構成の差は大きくなり,全体のPlaybookを流すことに対する恐怖は徐々に増えていきました。

このようにして,構成ドリフトからオートメーション恐怖症という教科書どおりの状態に陥ってしまいました。

解決方法

ホストごとのステートは外部DB/Ansibleのhost_varsで管理する

一時的な変更内容を忘れないために,VMごとに異なる設定値(CPU数やディスクサイズなど)は,外部DBで管理します。 ただし,ごく少数のVMだけで異なる設定値は,Ansibleのhost_varsで管理してしまいます。 host_varsを使う理由は,

  • 管理用の外部DBのスキーママイグレーションの必要なく比較的楽に追加できる
  • 対象VMの個数が少ないのでそこまでAnsibleコードが複雑にならない
  • 対象のVMが削除された場合にDBから削除するよりコードから削除する方が比較的容易

があげられます。 上記であげた監視エージェントの負荷の問題の件だと,host_varsの変数をフラグとして用意し,一部のVMだけは利用者との同意のもと,監視エージェントが起動しないように制御しています。

全体のPlaybookを定期的に流す

全体のPlaybookを定期的に流すことで,コードと構成の乖離を防ぐという根本対応も行いました。 これを行うためには,全体のPlaybookを流してもリソース不足に陥らない保証が必要です。 そのため,後述のようにリソース制限とプロセス単位のリソース監視を行いました。

リソース制限

運用が問題なく行える分のリソースを確保することを目的として,リソース制限を行い,MySQLが使うリソース,OSが使うリソース,DBaaS(MySQL)が運用として使うリソースを分離します。

f:id:kdx_writer:20201013183234p:plain
リソース分離

systemdでメモリ制限を行い,xfs_quotaでディスクの容量制限を行います。 制限を行う対象は,mysqld, 監視エージェントに対して行なっています。

systemdによるメモリ制限

systemd によるメモリ制限を行うためには,対象のサービスに対して,MemoryAccounting を有効にする必要があります。 DBaaS(MySQL)では,/etc/systemd/system.conf に,

DefaultMemoryAccounting=yes
DefaultCPUAccounting=yes
DefaultBlockIOAccounting=yes 

を記述しておき,全てのサービスについてデフォルトでリソース制限を可能にしました。1 メモリ制限は以下のように MemoryLimit を設定します。

systemctl set-property mysqld MemoryLimit=4G

制限値は,同様に systemctl set-property より,ダイナミックに変更が可能です。 これにより,スケールアップ/ダウン時にも適切にリソース制限値を変更することができます。

ただし,注意する点があります。 MemoryAccountingが無効時に起動したサービスに対して,無停止でMemoryLimitを設定した場合は,有効にした時点から使用されるリソースが制限されました2。 つまり,すでに使用されているメモリ分は制限されないため,意味のある制御を行うには,サービスのrestartが必要であり,サービス停止が伴います。

xfs quotaによる容量制限

xfs_quotaによる容量制限を行うためには,対象のパーティションに対していくつかマウントオプションを有効化する必要があります。

  1. 今回制限は / に対して行うため,/etc/default/grubGRUB_CMDLINE_LINUX の行に, rootflags=uquota,gquota,pquota を記述します3
  2. grub2-mkconfig を用いて /boot/grub2/grub.cfg に反映させます。
  3. VMのrebootを行い,オプションを有効化します。

mysql プロジェクトを作成し,mysqlプロジェクトにMySQLデータディレクトリを紐付け,mysqlプロジェクトに容量制限値を設定します。

  1. /etc/projid に mysqlプロジェクトとそのIDを記述します。今回は mysql:10 としました。
  2. /etc/projects にプロジェクトIDとプロジェクトに含めるディレクトリパスを記述します。今回は,10:/var/lib/mysql としました。
  3. xfs_quota -x -c 'project -s mysql' / を実行し,プロジェクトを作成します。
  4. xfs_quota -x -c 'limit -p bsoft=4g bhard=4g mysql' / を実行し,制限値を適用させます。

制限値は,ダイナミックに変更が可能です。これにより,スケールアップ/ダウン時にも適切にリソース制限値を変更することができます。

注意する点として,VMのrebootが必要になるため,サービス停止が必要なことがあげられます。

プロセス単位のリソース監視

DBaaS(MySQL)では,監視SaaSのDatadogのライブプロセスを用いて,各プロセスが使用しているリソース値を可視化しています。これにより,リソース制限の閾値を適切に設定し,その動作をモニタリングし,リソース制限を管理することができています。

f:id:kdx_writer:20201013182219p:plain
プロセスごとのメモリ使用量

以上を行うことにより,全体のPlaybookを,心理的な負担なく,定期的に流すことができるようになりました。

まとめ

VM固有の違いをコードとして管理し,リソース制限とプロセス単位のリソース監視を行うことで,統一的にAnsibleで管理を行い問題なく全体のPlaybookを流すことが可能になり,Ansibleを流すことへの恐怖も解消しました。 構成ドリフト問題解決への道が見えています。

リソース制限にはサービス停止が必要なため,現状,全てのVMに対してリソース制限は適用できていません。そのため,構成ドリフト問題は完全解決はしていません。

今後は,利用者と連携し地道に少しずつリソース制限を行なっていき,完全解決へ向けて戦い続けていきます。

KADOKAWA Connected では,Private Cloud で運用効率化を意識しながら基盤提供する仲間を募集しています。


  1. 今後別のリソースの制限する可能性があるため,Memory以外にCPU, BlockIOについても設定しています。

  2. こちら仕様についてドキュメントから把握できておらず,そのため,動作検証を行いました。

  3. 実際に使うのは,pquota ですが,今後利用する可能性があるため,他のオプションもつけています。