MySQLサーバのMulti Instance化によるコスト最適化方法

by Naoya Ishikawa | December 01, 2019
infrastructure | #infrastructure #linux #mysql

IT 基盤部の石川です。

IT 基盤部ではオンプレ、パブリッククラウド問わず多くのインスタンスを管理していますが、その中で “Multi Instance” と呼んでいる独自のインスタンス管理方法があります。今回は、その Multi Instance とは何か、Multi Instance を使った MySQL サーバのコスト最適化方法を話します。ちなみに、この原稿は re:Invent 2019 へ行く飛行機の中で書いています。

Multi Instance とは

Multi Instance とは、1 つのインスタンスに複数の IP アドレスを紐付け、あたかも複数のインスタンスのように振る舞うインスタンスのことを部内ではそう呼んでいます。Multi Instance の起源はオンプレ時代にさかのぼります。オンプレをメインで使用していた頃は、用途ごとに適切なスペックの機材をその都度調達するのではなく、あらかじめ何種類かにパターン化した固定スペックのサーバを、大量に調達するという戦略を取っていました。そのため、クラウドのようにサーバリソースの選択が柔軟ではなく、そのまま使用すると用途によっては過剰なスペックとなってしまう場合がありました。DeNA のインフラ設計思想の 1 つに、リソースを極限まで効率化するというものがあり、それを実現するための 1 つの方法が Multi Instance でした。

MySQL や memcached のミドルウェアを 1 台のインスタンスの上で複数稼働させる場合、闇雲にあいのりさせると構成が煩雑になり、運用時に意図しない障害の原因となりえます。そこで、Linux に仮想 NIC を追加し、その追加した NIC 毎に別のホスト名・用途を割り当てることにより、1 インスタンスに複数のインスタンスを仮想的に構成したものが Multi Instance です。

KVM を使った仮想化も行っていましたが、よりオーバーヘッドの少ない仮想的なインスタンスの管理方法として Multi Instance は重宝していました。仮想 NIC を追加し、その NIC にホスト名を割り当てるなどの処理は、以前の Blog で紹介した gi にて共通化されているため、とても簡単に、誰がやってもミスをすることなく実施できるようになっています。

Multi Instance の実現方法

各種環境では、それぞれの方法で Multi Instance を実現しています。実際には、インフラ担当者が直接 API を叩くことはなく、gi のスクリプトを経由して実行することで Multi Instance を作成しています。オンプレや各種クラウドなど、どのような環境でも同様の仕組みを提供し、インフラ層を抽象化して利用できるのも gi の優れたメリットだと言えます。

クラウド時代の Multi Instance

AWS や GCP を利用すると、必要なキャパシティにフィットする最適なインスタンスを選べるため、Multi Instance のメリットはなくなったように思われますが、100% クラウドで運用している私のチームでも Multi Instance は活躍しています。

全世界に向けて一斉リリースされるゲームにおいて、ローンチ直後の Database への負荷は、通常運用時の10倍以上が見込まれます。そのため、ユーザデータなどを格納する MySQL は、数百以上に水平分割を行ってリリースに挑みます。つまり MySQL の Master DB が数百個ある状態になります。リリース後に負荷が一定の状態に収束した場合は、コスト最適化を行うため MySQL の Multi Istance 化を行うことで Database 用 インスタンスの集約をしていきます。

2 Shard を 1 つのインスタンスで稼働させた Slave DB を追加し、内製ソフトウェアである MHA for MySQL を利用してフェイルオーバーを行うことで Shard 数は一定のまま、稼働させるインスタンス数を無停止で半分に減らすことが出来ます。Multi Instance 化せずとも、インスタンススペックを下げればいいのではないかと思われますが、例えば AWS において Database 用インスタンスとして利用している i3en はサイズによって、パフォーマンス・安定性が違うため、あえて一定以下のスペックは選択しないためです。

例として 4 Shard ある MySQL の系統を集約していく流れを説明します。以後の図では、一番左側の MySQL が Master、その他を Slave として模しています。

まず初期状態では、1 系統 3 台の EC2 インスタンスが 4 Shard あるので、12 台の EC2 インスタンスで 12 個の MySQL が稼働しています。赤い MySQL が Master で、青い MySQL はレプリケーションしている Slave です。

リリース後、負荷が落ち着いてきたタイミングを見計らって、Slave を Multi Instance に置き換えて行きます。日次で取得した mysqlbackup から新たな slave を作成するのも、gi にってスクリプト化されているため、コマンドを 1 つ実行するだけで、レプリケーションに組み込まれまで自動化されています。下の図では 2 個 MySQL が 1 台の EC2 インスタンスで稼働している Slave に置き換わっています。この時点で、MySQL の数は変わらずに、12 台あった EC2 インスタンスは 8 台に削減できています。

続いて、新 Master となる緑色の Slave を一時的に追加します。そして MHA for MySQL でフェイルオーバーを実施して、Master も Multi Instance に切り替えます。ちなみに、MHA for MySQL はサービスへの影響は無く、MySQL のマネージドサービスを利用するよりも高速にフェイルオーバーが可能です。

フェイルオーバー後、EC2 インスタンスは、初期状態の半分の 6 台に削減できています。

さらに負荷が減った場合には、同様の手順で 4 つの MySQL が 1 台 の EC2 インスタンスで稼働している Slave に置き換えることで、さらに半分の台数に削減できます。

MySQL のようなステートフルなサーバはなかなかコスト最適化することが難しいですが、上記のような方法を行うことで、停止メンテンスをすることなくコストを下げることを実現しています。また、サービスが堅調に推移した場合は、上記の手順の逆を行うことでスペックアップをすることも可能となります。

以上 Multi Instance の紹介と、それを利用した MySQL サーバのコスト最適化方法の説明でした。