はじめに
こんにちは、SRE部の秋田と伊藤です。普段はZOZOTOWNのオンプレミスとクラウドの運用・保守・構築に携わっています。
新春セールはZOZOTOWNの中でも最も力を入れているイベントの1つであり、セール開始直後は毎年最大級のアクセスやトラフィックが発生しています。この新春セールを無事に乗り越えるために2020年度から負荷試験を実施しています。負荷試験のシナリオでは機能ごとの試験ではなく、ユーザー導線に合わせてZOZOTOWNにセール同等のトラフィックを再現します。
本記事は、様々な変化をするZOZOTOWNにおける新春セールを乗り越えるための負荷試験を実施するまでにあった課題とその課題解決に向けた取り組みについてご紹介します。
目的
負荷試験の目的は、ボトルネックとなりうる箇所の特定、新春セールに耐えうるインフラリソースを算出することです。また、新春セールで必要な準備やトラブルが発生してしまった際の迅速な連携・対処の練習も兼ねています。
負荷試験における課題
負荷試験を実施する上で、以下のような課題がありました。
- 一気通貫で負荷試験することが困難
- 限られた試験時間で最も効果を得られる負荷試験の実施
- 2021年に新たにリリースされたマイクロサービスへの理解
- 過去の負荷試験で生じた課題
課題1:一気通貫で負荷試験することが困難
ZOZOTOWNは、パブリッククラウドを活用したマイクロサービス化が着実に進む一方で、まだアーキテクチャの再設計に着手できていないシステムも多く存在します。例えばオンプレミス環境でもWebサーバーや基幹データベースなど多くの重要システムが稼働しています。すさまじい勢いで成長するZOZOTOWNのトラフィックに耐えうるインフラ構成をオンプレミス環境で実現するため、これらのシステムは幾度となくスケールアウト・スケールアップを繰り返してきました。オンプレミス環境で負荷試験のために本番同等のインフラ環境を用意するのはコスト的にも難しい現状があります。
課題2:限られた試験時間で最も効果を得られる負荷試験の実施
ZOZOTOWNではアクセス数以外にも日々の施策によってWebサーバやAPIサーバの負荷状況が大幅に変化します。新春セールでは毎年多くの施策が実施されるため、負荷試験のシナリオ以外にも高負荷の要因となる状況を再現する必要がありました。
課題3:2021年に新たにリリースされたマイクロサービスへの理解
2021年には以下のリプレイスを実施しました。
「2021年ZOZO開発組織の進捗」でリプレイスの進捗についても紹介されています。
1年間で多くのマイクロサービスのリリースが行われました。多くはバックエンド機能のリプレイスです。これらはユーザー側から見たリクエスト先のURLは変えずに実現するケースが多いです。つまりバックエンド処理をモノリシックな構成から各APIを呼び出すマイクロサービス化を進めています。そのため、各マイクロサービスへ負荷が適切にかかるエンドポイントをリプレイス状況に合わせて精査、必要に応じて前年度利用した負荷試験のシナリオ改修が必要です。
課題4:過去の負荷試験で生じた課題
新春セールのような大規模な負荷を想定した場合、負荷をかける側がボトルネックとならないように負荷試験の環境を用意する必要があります。試験中にスムーズにスケールアウトを行うために2020年頃から分散負荷試験を採用するようになりました。
負荷試験の準備
前述した課題を解決するために負荷試験を実施するメンバーで様々な準備を1か月に渡って行いました。
- 負荷試験の実施に向けた準備
- シナリオの準備
- 負荷試験の実施環境の作成
負荷試験の実施に向けた準備
課題1で挙げた問題は、すぐに解決できなかったため本番環境を利用して負荷試験を実施しました。本番環境では通常のユーザーのトラフィックを受けるため、いくつかのことを考慮して負荷試験を行う必要がありました。
- ユーザーのトラフィックが少ない時間を選定
- 万が一の障害が起きた場合の対処準備
- 各部署への周知連絡
負荷試験の実施日と時間の選定は課題2で挙げた施策数が多い日を数日含めるように調整しました。負荷試験を実施する回数は4回で、施策数が多い日を2日間、シナリオ調整を含めた施策数の少ない2日間を選定しました。この施策数が多い日はビジネスサイドに相談した上で決定しています。
リモート環境でのコミュニケーション方法はGoogle MeetとSlackを活用しました。Google Meetは負荷試験の実施者の画面共有、各チームと会話するために利用します。Slackは負荷試験の実行前の簡易連絡や負荷試験の実施中の簡易メモなどで利用します。負荷試験の実施中の実行結果は記録用スプレッドシートを事前に共有して、なるべく負荷試験中に今何やっているかすぐにわかるように準備しました。
障害が起きた場合の対処に関しては、シナリオを迅速に停止できるよう準備をしていました。各チームにはメトリクスを常に監視してもらい何かエラーが増えた時点ですぐコミュニケーションをとるようにお願いしていました。また、周知に関しては各チームに関連部署へ連携をお願いしました。
シナリオの準備
シナリオ作成にはアクセスログを活用しました。過去のアクセスログからアクセス数や各URLごとのリクエスト数などの分析をし、なるべくユーザーの導線に近いものを再現できるようにします。ZOZOTOWNのWebサーバーのアクセスログの分析にはSplunkを用いています。
テックブログやQiitaでもTipsなどを紹介しているので興味のある方はご覧になってください。
Splunkによる分析
Splunkを用いてアクセスログから以下の情報を抽出し、シナリオ作成に役立てました。
- 総リクエスト数
- 各機能ごとのリクエスト割合
- 秒間・分間リクエスト数の平均値
- 各エンドポイントに対応するParameter毎の統計情報
また、課題3で挙げた各マイクロサービスへの負荷がかかるエンドポイントの調査にもSplunkを利用しています。Splunk App for Streamを使ってWebサーバーやAPIサーバーから出ていくHTTP Requestを分析し、各マイクロサービスのエンドポイントに対しどのようなParameter、Bodyでリクエストを実行するか精査しました。不透明だった各マイクロサービスの呼び出しを正確に分析することで、シナリオの精度をあげられました。
以下はStreamを使ったSPLの実行例になります。
index=main host=XXX sourcetype="stream:http" site=XXX
負荷試験の実施環境の作成
本負荷試験は以下の構成で実施しました。
構築するにあたって考慮したポイントを紹介します。
Gatling Operatorの利用
課題4を回避するために開発されたのがGatling Operatorとなります。
Gatling Operatorを利用する主なメリットは次の通りです。
- 一連の分散負荷試験のタスクが自動化された
- Gatling用Podに柔軟にノードリソースの配分ができるようになった
- 分散負荷試験がマニフェストで宣言的に定義できるようになった
Gatling Operatorについては詳しく川崎・巣立のテックブログにて、分散負荷試験環境の必要性や詳細な利用方法など紹介しているのでご覧ください。
1つのAZにNatGateway及びElasticIPを複数用意する
2020年の負荷試験時に、負荷をかける側で発生した問題として、Nat GatewayのErrorPortAllocationエラーが発生していました。
NatGateWayには次の制限があり、最大55,000の同時接続数を超えてしまうとErrorPortAllocationエラーが発生してしまいます。
A NAT gateway can support up to 55,000 simultaneous connections to each unique destination. This limit also applies if you create approximately 900 connections per second to a single destination (about 55,000 connections per minute).
回避のためにはNatGatewayを複数台用意し、コネクションを分散させることが有効となります。
今回の負荷試験のおいては同様の事象を起こさないよう、十分な数のNatGatewayを準備し、拡張可能な構成で用意しました。
AWSへの負荷試験の申請
AWSが関連した負荷試験で秒間1Gbpsを越えるトラフィックが1分間以上、継続する場合には申請が必要です。
申請を怠った場合には不正利用者として検出され、本番ワークロードに影響する可能性もあります。本試験は秒間1Gbpsを超えるトラフィック量を見込んでおり、フォームにて申請しました。
負荷試験の実施結果
関係各部署との協力体制のもとアクセスの少ない時間帯で負荷試験を実施させていただきました。負荷試験を通して新春セール前に2つの問題を見つけ、解決することに成功しました。また、社内開発OSSのGatling Operatorの大規模な利用時のユースケースを作ることできました。Gatling Operatorを利用することで限られた時間の中での負荷試験の実施の効率化は非常に喜ばしいものとなりました。
IP枯渇問題の検出と対策
ZOZOTOWNでは現行のシステム基盤のリプレイスとしてAmazon Elastic Kubernetes Serviceを利用したマイクロサービス化が進められています。今回の負荷試験の実施において環境増強のためpodのスケールアウトをしている際にノードの割り当てが失敗し、podがpending状態から進まなくなる事象が発生しました。原因はAmazon VPC CNIのdaemonsetのaws-nodeのパラメータ WARM_ENI_TARGET
にありました。パラメータが初期設定であったことで必要以上のIPアドレスがノードごとに確保されてしまっていました。
詳しくはアドベントカレンダーの記事をご覧ください。
試験において問題の検出及び対策ができたことで、セール本番時にオートスケールで増強しようとしても増強ができないといった予期せぬ事態を回避することにつながりました。
効果的な箇所へのコンテンツカットによるパフォーマンス対策
負荷試験でボトルネックが検出されたサービスに対してパフォーマンスチューニングが必要です。しかし、簡単に対応できるもののみとは限りません。例えば、ウェブページにおいて全てのユーザーが閲覧するコンテンツで同一のSQLが実行されてデータベースの負荷となっているのであれば、静的コンテンツへの置き換えやキャッシュ化などが考えられます。しかし「○○という商品を見た××さんに向けた情報」のようにユーザーや商品の組み合わせ毎に結果が異なるコンテンツに対してのキャッシュ化はあまり効果的ではなく、取得ロジックに手を入れる必要があります。
セールの開始が迫っている中での大掛かりな修正は工数面と品質面、どちらにおいてもリスクとなります。そのため対応困難な箇所に関してはセールを期日とした根本的な修正は行わず、セール中はその項目を表示しない、部分的なコンテンツカットを実施しました。
コンテンツカットはエンジニア的側面よりもビジネス的な側面が必要な対応となります。各方面のエンジニアを巻き込んでいることと、会社自体がBizDevOpsを掲げ、ビジネス部門とも距離が近く連携できました。結果として、ビジネス的なリスクは小さいがパフォーマンス影響が大きい箇所に対してのコンテンツカットを検討から実現まで円滑に進められました。
2022年度新春セールの結果について
ZOZOTOWNの新春セールは0:00から始まり、トラフィックが徐々に増えていき最大トラフィックに到達します。2021年の新春セールでは初動でかなりのエラーが発生し、ユーザーはZOZOTOWNにアクセスしづらい状況が発生していました。
上記のグラフは、新春セール初動の2021年と2022年のエラー数を比較したグラフです。明らかに2022年はエラー数がかなり減っていることがわかります。この成果は負荷試験を通して、事前に問題が発生する箇所の解決、予測トラフィックを処理するために必要なインフラリソースを用意できたことが要因だと考えられます。
まとめ
ZOZOTOWNの最大級のイベントである新春セールを乗り越えるための負荷試験に関する取り組みを紹介しました。負荷試験を実施したことによって新春セールを安心して迎えられました。コストやリソースの問題で本番と同等のサイジングの試験環境を用意できなかったという課題は残りましたが、更なるサイトの信頼性向上のため、より簡易的に試験を行える状態を目指し引き続き取り組んでいきます。
改めてこの場を借りて負荷試験に関わってくださったみなさまに感謝の言葉を述べさせていただければと思います。関係各部署のみなさま、新春セールの準備でお忙しい中、負荷試験にご協力いただきありがとうございました。
最後に
ZOZOTOWNのシステムは現在リプレイス真っ只中です。秋田とフロントエンドリプレイスへ取り組んでいただける方、伊藤とカートリプレイスに取り組んでいただける方、興味がある方は以下のリンクから是非ご応募ください。
また、カジュアル面談も随時実施中です。「話を聞いてみたい」のような気軽な感じで大丈夫です。是非ご応募ください。