一休.comではオンプレミスで動かしていたサーバー群をAWSに移行する作業を2016年末から2年がかりで進めてきました(以下、クラウド移行と呼びます)。2017年7月にまず全サービスのアプリケーションサーバー移行が完了、2018年2月にデータベースであるSQL Serverの移行が終わり、クラウド移行が完了しました。
一休のシステムは予約や決済などのミッションクリティカルな基幹業務を担ってるため、大規模なシステム移行は難易度が高い仕事でした。また、一休のサービスは予約を取り扱うECの一種であるため、トランザクション機能をはじめとする、DBに対する品質要求水準や機能要件も比較的厳しい環境です。
本記事ではこのクラウド移行の中でも特に難易度が高いDBの移行を牽引したkudoyに、移行計画の設計や勘所についてインタビューします。
- インタビュイー
- kudoy デジタルマーケティング部エンジニア(写真右)
- インタビュワー
- ninjinkun レストラン事業部エンジニア(写真左)
- akasakas 宿泊事業部エンジニア(撮影のため写真なし🙏)
ninjinkun:
私は今回のDB移行やSQL Serverについてほぼ何も知らないので、今日は私のような素人にもわかるようにお願いします。
kudoy:
わかりました(笑)
今回のAWS移行で解決したかった問題は3つあって、
- ハードウェアを属人的な運用で管理している
- ハードウェアの調達に時間がかかる
- ハードウェア製品のライフサイクル(製品寿命)に合わせて都度移行作業が発生する
という感じです。
ninjinkun:
クラウド移行前はハードウェア調達にどれくらい時間がかかっていたのでしょうか。
kudoy:
ハードウェアの調達は選定から始まって急いでも一ヶ月、セットアップから投入まででトータル二ヶ月くらい時間がかかっていました。
DB移行の時期がアプリケーションサーバより遅れた理由
ninjinkun:
2017年の夏にはアプリケーションサーバーの移行は完了していたわけですが、DB移行が後になったのはどういった理由だったのでしょうか?
kudoy:
一休のサービスに必要な機能がSQL Server 2017でないと使えなかったためです。具体的には、一休ではホテルやレストランの予約の際に宿泊データのDBとユーザーデータのDBで異なるDBをまたいだトランザクションを使用しているのですが、このための機能がSQL Server 2016にはありませんでした。
ninjinkun:
でも一休のサービスはこれまでも同じように異なるDBにまたがるトランザクションを利用して動いていたわけですよね。なぜ今回のクラウド移行で新たな機能が必要になったのでしょうか?
kudoy:
これまでは、DBサーバの冗長化をftServerと呼ばれる全ての部品が2重化されているハードウェア側で行っていました。このハードウェアは、OSやSQLServerからは1台のサーバとして扱えることで、複数DB間のトランザクションに関する制約に該当しなかったんです。しかしクラウド環境でも同じ可用性を確保するためには、 AlwaysOnという複数のインスタンスでMaster DBを冗長化する機能を使う必要がありました。その結果、インスタンスを超えてトランザクションを使う分散トランザクション*1が必要になったのです。
ninjinkun:
なるほど、クラウド移行でハードウェアではなくサーバー構成で冗長化する必要が出てきて、そのためにインスタンスを分けたから分散トランザクションが必要になったんですね。
kudoy:
SQL Server 2017でAlwaysOnでのDBまたぎの分散トランザクションがサポートされることがわかっていたので、アプリサーバーの移行を先に行い、SQL Server 2017のリリースを待っていました。 この時期は、AWS Direct ConnectでAWSに移行したのアプリケーションサーバとオンプレのDBサーバを専用線で繋いでいました。
ninjinkun:
他にスケジュールに影響を与えた要因はあるのでしょうか?
kudoy:
実は現在のハードウェアのキャパシティでは2018年中にはトラフィックを支えきれなくなる見込みで、かつ2017年の時点でデータセンターも2018年3月で解約することになっていたので、もうこの時期にやるしかなかったんです。
DB移行の準備がスタート
kudoy:
2017年の10月にSQL Server 2017が出てきたので、そこからようやく本当のスタートでした。まずSQL Server 2017でできるようになったことを調べて、それから環境を作るためにAWS側のネットワークの設計や構築、DBの設定、セキュリティ、Microsoft ADの設定、運用周りの設計だとかを並行してやっていきました。
ninjinkun:
実際に動かして試したりもしたんですか?
kudoy:
動かしていましたね。でもテスト環境なので、最小構成で作ってしまっていて、いざ本番構成を作るときに見えていなかった考慮すべき点が出てきてしまったんです。
ninjinkun:
具体的にはどんな問題があったんでしょうか。
kudoy:
ネットワーク構成の問題ですね。
Multi-AZで、それぞれのAZにデータベース用のサブネットを用意して、AlwaysOnを4台構成(+1台ファイル共有マジョリティ用ノード)にして、2台+2台で配置する想定でいましたが、2台構成だと上手くいくけど、4台構成にするとうまくいかない。事例を調べても2台構成はあるけど、4台構成の情報が見当たらなくて。。。。
ninjinkun:
MySQLでの事例はあったんでしょうか?
kudoy:
選択する仕組み自体が違ってくると思いますが、MySQLだとレプリケーションを使用するかと思うので、EC2起動時に割り当てられたマスター/スレーブの1つのIPを指定するのではないでしょうか。
EC2でAlwaysOnを構成する場合、まずWSFCというWindowsクラスタが組まれていることが前提条件になります。構築するに当たり1つのENIに
- EC2(OS)用
- WSFC用
- SQLServer用
の3つのIPを指定する必要があるのですが、想定していた2つのサブネットにそれぞれ2台づつ配置する4台構成にしてAlwaysOnを構築するとWSFC用IPとSQLServer用IPが上手く認識できなくてWindowsクラスタが正しく動作していませんでした。
どうにも解決策が見当たらなくて、AWSサポートと相談してたところ、WSFCで1 つのサブネットに複数のクラスターノードを配置する方法は、 AWS ではサポートされていないことがわかったんです。そこで、以下の図のようにサブネットを分ければ解決することがわかりました。
この構成がオープンになっている事例は探してみたところ見当たらないので、図だけでも面白いかもしれません。そもそもAWSでSQL Serverを運用している事例自体が少ないですが。
ninjinkun:
元々は2つのサブネットで行けるはずが、4つのサブネットが誕生してしまったんですね
機能検証
kudoy:
その後、まずは機能検証用に今のアプリケーションをSQL Server 2017に変えただけで動くのかを検証しました。小さな環境を作って、E2Eテストや直接アクセスしてもらって検証したのですが、その時点でアプリケーションはほとんど問題無く動いていました。
それが終わった後に負荷試験用に本番と同じくらいのサイズのインスタンスを立ててパフォーマンスの検証をやってもらった感じです。
機能検証、パフォーマンス検証がクリア出来たところで、DB移行のリハーサルを始めました。 データ転送の時間や、AlwaysOnを構築したあとのプライマリインスタンスからレプリカインスタンスへのDB同期させる時間はすごく長くかつブレがありました。サイトのメンテナンス時間をユーザーやパートナーに告知しないといけないので、短くする方法を模索していました。
24:30から8:00で止めると告知しました。まあ告知した時点ではリハーサル時間は全然収まりそうもなかったんですが(笑)
一同:
(苦笑)
ninjinkun:
でもビジネス的にはそれ以上止められないということで、時間が決まったんですよね。
kudoy:
10時間超えるとか言ったらさすがに…となりますからね(笑)
akasakas:
でも最初のリハーサル12時間とかじゃなかったでしたっけ?
kudoy:
最初はそんな感じでしたね。でも色々、検討&検証してみたら何とかなりました。
ninjinkun:
それは事前にできるところをやっておくとかでしょうか。
kudoy:
そこも含めて、手順を簡略化したりとか、順番を入れ替えたりして。
EC2インスタンスタイプの選択も重要でした。当初R4系を使おうと思っていましたが、最終的にはI3系を選択しました。選択した大きな理由としては、I3系には永続的なデータの保存には使えませんが、インスタンスストレージとして、NVMeのストレージが付いていることでした。
インスタンスストレージは、インスタンスを完全に停止してしまうとデータが消えてしまいますが、起動している間は追加料金なしで使用できるすごく高速なストレージです。移行時には、データ転送やDB再構成、移行後もスナップショット的なDBバックアップなど、一時的な作業で且つ出来るだけ処理時間を短くしたいという用途に向いていました。このNVMeのストレージを上手く活用することで、AlwaysOnを構築する際に必要なDBバックアップとリストアの処理時間を短縮することができました。
あとはストレージ(EBS)のパフォーマンスを調整できるので、IOPS(ストレージのパフォーマンス)を一時的に上げて、そこでパフォーマンスが出たので机上の計算よりは速く収まりました。
ninjinkun:
結局一番効いたのは何でしたか?
kudoy:
NVMeストレージの活用と、IOPSの調整は効いてる思います。
ninjinkun:
環境構築してリハーサルも行って、見積もりも出ましたと。後は…
kudoy:
それと並行して開発系DBの移行の準備も進めていました。
移行に関しては丸々サイト止めてバックアップ取ってからデータをそのまま持っていくとすごく時間がかかるので、事前にフルバックアップを前日に取ってそれを先に送って、当日は差分のログだけを流すようにしました。できるところは事前にと言うのは、そういうところですね。
ninjinkun:
移行が11月からスタートして2月の中旬でしたっけ、実質4ヶ月弱でここまで来ているわけですね。
akasakas:
結構調整が大変でしたよね、移行当日のスケジューリングとか。
kudoy:
(ユーザー向けの)キャンペーンがちょくちょくあって実施可能な日が割と少なかったりとか…。
準備で一番時間がかかったところ
ninjinkun:
ちなみに、一番準備段階で時間がかかったのはどこですか?
kudoy:
負荷試験じゃないですかね。負荷試験の環境を作るのもそうだし、さっき言った通り最小構成でテスト環境作っていたので、ネットワーク環境の作り方を調べるのに時間がかかって。
あとはすぐにインスタンスが確保できなかったという問題がありました。AWSの制約上、大きいインスタンスだと最初は2個しか確保できず、4台使いたいと思って制限解除の申請したら2日3日掛かって、IOPSの上限を上げるのも申請制でした。
ninjinkun:
それは間違って契約するのを防ぐためなんですかね。
kudoy:
たぶん意図しない課金を防ぐためと、あと制限なしにいきなり大きなリソースを沢山のアカウントから確保されるとAWS側もリソース供給出来なくなってしまいますよね。EBS(io1)のIOPS上限の緩和は時間が掛かるケースもあって一週間くらいかかったりすることもありました。
ninjinkun:
クラウドとは…という気持ちになりますね。
kudoy:
本番用のインスタンスも料金節約のため直前に用意するつもりだったのですが、AWS側のリソース提供状況によってはインスタンスが起動できないことがあることがわかったので、早いけど一週間前にはインスタンスを確保する為に起動しておこうと。
クラウドの怖いところを直前になって思い知らされました。
ninjinkun:
直前だと意外と調達できないという…