エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

運用中サービスのクラウド移行で得た知見(見積もり・テスト・本番移行)

<エムスリー Advent Calendar 2020 まで残り4日となりました。Advent Calendar本編に先んじて新卒1〜2年目メンバーが執筆します。>

「生きてるだけで丸儲け」そんな言葉が身に沁みる今日この頃です。
こんにちは。エンジニアリンググループ、新卒2年目の井上です。
さて、世の中には「動いているだけで丸儲け」なシステムが様々あると思います。
この場合「丸儲け」というと表現が悪いですが、「運用中でお金を生み出しているサービス」は様々なところに存在すると思います。
このような運用中のサービスの一つをAWSへクラウド移行した時の知見を特に下記の3つの項目に分けてここに記します。

* 見積もり  
* テスト  
* 本番移行 

皆様がお手元のサービスをクラウド化する際の糧にしていただければと思います。

f:id:yoshiyuki-inoue:20201126140342j:plain
ダーツにおいて、1本目に投げたダーツに、2本目に投げたダーツが刺さることを「ロビンフッド」と言います。 ※本文には関係ありません

見積もり

運用中のサービスをクラウド移行するとした場合、移行前後で同等の性能を実現するための経費の見積もりが必要です。
この時、「数字の性質を分けて考える」ということを行うと、見積もりの議論がとてもスムーズになると、今回気づきました。
例えばクラウド予算話し合いの際は、下記のような論点があると思います。

* AWSの他の種類のサービスは使えないか、Google Cloudなどの代替案はないか  
* アプリの改修含めて、コスト削減はできないか。  
* どのようなリスクを受け入れ、どのような安定性を担保するか。  

そしてこれらは分けて議論出来ないと、どの対応策をとるべきかわかりづらくなってしまいます。 AWS Fargateを使うと仮定して、議論を分けるために数字の性質を分けて考えるということを見ていきます。

見積もりの数字、3要素

* AWSが設定している値  
* アプリが必要としている値  
* ポリシーで決めることができる値  

AWSが設定している値

AWS Fargateの料金は以下のように決められます(東京リージョン、執筆時点)
(コンテナからインターネットへのデータ転送) * 0.114USD/GB + (CPU数) * 0.05056USD/時 + (必要メモリ) * 0.00553USD/GB
これらは利用者側で設定可能な値ではなく、ルールとしての値です。

アプリが必要としている値

オンプレが出力しているログやコードなどから、アプリからインターネットへのデータ転送量を概算で出してみましょう。
例えば一回の平均レスポンスサイズが10KB、1ヶ月に30万回叩かれるAPIサーバがあれば、これの必要なデータ転送量は 10*300000/1024/1024 ≒ 2.9GB と見積もることができます。

ポリシーで決めることができる値

必要なCPU数、メモリ容量を現在動いている環境を参考に算出しましょう。
この時、アプリの性質を考慮してギリギリの値を攻めるのか、余裕を持った設定にするのかはポリシーに沿って考慮が必要です。
ギリギリを設定した場合はそのリスクを把握すること、余裕を持った場合は何円まで余裕を持った予算であるかを把握しておくべきです。

値の種類を分けて議論する

上記のように項目を分けて一つずつ、対応策を吟味していければ、良い議論になるはずです。
もちろんこれらの値は完全に独立するものではなく、相互作用を及ぼすものもあります。 互いの関係にも注意しながら、議論が進められれば良いと思います。

テスト

さて見積もりが終われば、それに基づいていい感じのTerraformなり、CloudFormationなりでクラウド環境を構築しましょう。 そしてそれが終われば、アプリのテストが待っているはずです。
この時、特にクラウド化において共通的に必要なテストはこのように分けられると思います。

必要なテスト観点の種類

* アプリケーション単体テスト
* 外部通信が必要なテスト  
* 性能テスト  

アプリケーション単体テスト

特にクラウド移行における単体テストで気にしたいことが localeを意識したテスト です。 この記事をこの言語でお読みになっている方の多くは日本語を使い、日本のタイムゾーンに従っているかと思います。
そして多くの場合、サーバの初期設定は日本用にはなっていません。

* アプリで `new DateTime()` している部分、DBで `current_timestamp()` している部分が想定と同じかの確認  
* 日本語文字の入力、出力が正しくできているかの確認  
* 既存DBからデータを移行し、その日本語が正しく出力されるかの確認  
* ログ出力がJSTでみやすくなっているかの確認

これらのテストを行うことで、localeに関して安心してクラウド移行できそうです。

外部通信が必要なテスト

コンテナ内で完結する単体テストは、OS種類が揃っていればそれほど落ちることはないはずです。
外部通信こそ、人力を含めた厚めのテストで品質を担保してあげましょう。
まとめますと、特に下記に注意が必要と感じました。

* API連携が移行前と同じように出来ているか
* 画像やCSS,JSなど静的コンテンツのアクセス可否が引き継がれているか  

事実、全く同じリクエストでも移行前は上手くいっていたのに、移行後で失敗することが多くなったケースがありました。
HTTPをハンドリングするライブラリと、今回のアプリ側のWebサーバのバージョンアップの組み合わせが悪かったようです。
また、ECSをprivate subnetで動かすことによって、本来外から見えるべきものが見えなくなるという問題もありました。
今後、自分も気をつけたい観点です。

性能テスト

これこそ、クラウドに移行したメリットの一つかもしれません。
オンプレでは本番と同じ環境をテスト環境に用意することは難しい場合もありましたが、クラウドでは同じ環境を立ち上げ、終われば片付けることが可能です。
注意点としては

* 実際のリクエストに近い状態で負荷をかける: 負荷の掛け方、負荷を受け止める側の状態を近づける   
* レスポンスタイムが想定時間以内であることを確認する   

例えばDB負荷のテストを入念にする場合は、実際に近いデータ量、データ分布でテストする必要があります。 データ分布を近づけたい理由は、DBのオプティマイザがデータ分布を参照して良い感じの実行計画を作るためです。*1
終わったらterraform destroyなどして、お片付けは忘れないようにしましょう。

クラウド移行特有のテスト観点がある

運用中のサービスだからこそ、デグレは最大限避けたいものです。 コードレビューや移行計画策定をいかに入念に行っても、テストが大事なサービスを守る最後の砦です。 そしてクラウド移行は他の細かい案件に比べて行う頻度も少なく、テスト観点は忘れられがちかと感じたので、ここにまとめました。

本番移行

さてさて、テストまで終わればあとはサービスをクラウドへ持っていくだけです。 今回、自分たちは以下のようにフェーズを分けて、クラウド移行を行いました。
これが多分どのサービスでも取りやすい方法で、良い方法だと思っているので、ここに記します。

段階的に移行する

* クラウドアプリの立ち上げ(DBはオンプレを見ている)  
* オンプレWebサーバからクラウドアプリへリクエストを流す  
* DNSを切り替え、クラウドアプリへ直接リクエストを流す  
* DBの参照先をクラウド版へ切り替える  

クラウドアプリの立ち上げ

まず、全くリクエストが流れてこない状態で、本番環境が立ち上がるかを確認しました。
この時、DNSで本番とは全く違う名前をクラウドアプリにつけます。
そして社内からだけはクラウドアプリを叩けるようにして、テスト環境にて出来ていた簡単な操作が問題なくできるか、できる範囲で確かめてみます。

* Terraformであれば本番用のtfvarsの設定漏れに気付ける  
* 実際の本番データであまりにも遅いGETリクエストに気付ける  

などのチャンスが、ほとんどリスクなしで回ってきます。

オンプレWebサーバからクラウドアプリへリクエストを流す

次に、既存で使用していたオンプレのWebサーバに設定を追加し、オンプレへ来ていたリクエストをクラウドアプリへ流すこととしました。
これの良い点はズバリ、問題があればすぐ元に戻せる ことです。
いきなりDNSを切り替えて外からクラウドアプリのLBにリクエストを流してしまうと、大量リクエストで問題があった時の切り戻しにDNS反映の時間がかかってしまいます。
この方法だと、何かあればすぐ戻ることが可能で、間違いのあった時の損失を減らすことができます。

DNSを切り替え、クラウドアプリへ直接リクエストを流す

上の段階が終わり、問題がなければDNS切り替えで直接クラウドLBにリクエストが来ても、問題が起こることは少なくなると思います。
ここで自信を持って、クラウドアプリへ直接リクエストを流すようにしましょう。

DBの参照先をクラウド版へ切り替える

今回は、最後にDBの移行を行いました。
DBの移行は一度終えてしまったら、不可逆になることが多いと思います。
不可逆である一方、例えばオンプレ側でDBは他サービスと共有DBを使っていたので正確な負荷がわからず、本番移行でDBによって性能が落ちてしまう場合もあります。
その場合、例えばRDSであればAWSオススメ*2のマルチAZ構成にしておきましょう。
こうすると、必要より性能が低いRDSへ移行してしまったとしても、failoverでほとんどダウンタイムなしでインスタンス性能を上げることも可能です。

少しずつ移行のデメリット

ここまで少しずつ移行のメリットを書いてきましたが、一方でデメリットもあります。
それは 通信経路が複雑になることで、移行期間中のアプリ性能が落ちる可能性がある ということです。
当然DBがクラウド移行されるまでは オンプレ <--> クラウド の通信が走るため、性能が想定よりもでない場合があります。
なので、移行期間はなるべく短くすると良いです。
前もって、「何日正しく動いていれば次にステップに進んで良い」 というのを決めておくのが吉かと思います。

まとめ

クラウド化をすることで、サービスは安定することが期待されると思います。
一方、そのクラウド化プロジェクトで、サービスが不安定な期間が続いてしまうことは避けたいとみなさんお考えだと思います。
それぞれのサービスに応じて、この記事を参考にリスクの少ない移行計画を作っていただければ幸いです。

We're hiring!

エムスリーでは様々なプロダクトをクラウド化しています!
新卒でもこの記事のような大きいプロジェクトに関わるチャンスがあります。 「話を聞いてみたい」というだけでも、カジュアル面談を申し込んでいただけば、クラウド以外の分野でもエムスリーのエンジニアリングを知ることができると思います。
ぜひ、お気軽にお申し込みください!

jobs.m3.com