ネットストアのセールに向けて行った負荷対策について
こんにちは、井上です。
東急ハンズでは8月26日〜9/2にハンズメッセというセールを開催しました。今日はそれに向けて行った、ネットストアの負荷対策の内容を紹介したいと思います。
システムの負荷対策の取り組みとしては、長期にわたるシステムの改善と、直前の対応があるのですが、今回は直前の対応について紹介します。
(1)負荷試験準備
まずは負荷試験をするための準備を行いました。
ELBのPre-Warming申請
負荷試験を実施するにあたり、まずは負荷試験を実施する環境のELBの暖機運転(Pre-Warming)の申請を行いました。
ELBは急激なスパイクアクセス時にスケールするのに時間がかかるため、予めアクセス増加が分かっている場合には事前に申請しておきます。
下記のような内容をまとめて、AWSのサポートセンターより申請を行います。
・ 予測されるピーク時のリクエスト数 (requests/秒)
・ 予想されるピーク時の1リクエストあたりの平均リクエストサイズ+レスポンスサイズ(bytes), または想定スループット(bit/秒)
・ Pre-warmingが必要となる期間(開始時刻および終了時刻)
・ HTTPSの利用有無、利用する場合にはHTTPとHTTPSの割合
・ バックエンドインスタンスでのKeep-aliveの設定可否
・ イベント日までにバックエンドEC2インスタンス数を増やしますか。(増やす場合はいつ、どのくらい増やしますか)
ELBはKeep-Aliveが有効になっていた方がスループットが出るとのことで、有効にすることをおすすめされました。
参考: [AWSマイスターシリーズ]Amazon Elastic Load Balancing (ELB)
インスタンスタイプの変更
長期的なシステム改善により、ほとんどのリクエストはElasticBeanstalkで動作しオートスケールするシステムで処理するようになっているのですが、一部、スケールできない構造のシステムが残ってしまっています。
そのシステムについては、スケールアップの対応を行いました。
まず、仮想化方式が、PV(paravirtual)でインスタンスタイプの選択肢にも制限があったため、HVMに変換を行いました。
システムの構築方法が明文化されていれば、変換せずに新インスタンスを立ち上げてそちらに構築しなおせば良いのですが、構築方法が不明で秘伝のタレのようなインスタンスになってしまっているため、諦めて変換を行いました。
実施については下記を参考にしました。(3〜4時間くらいかかりました)
AWSで仮想化方式 PV(paravirtual) の既存 CentOS AMIを HVMにする – Qiita
その他負荷試験環境の構築
通常の開発環境とは別で負荷試験用の環境を用意し、各種準備を行いました。
- 負荷試験用Beanstalk環境の作成
- 負荷試験用のElastiCacheの作成
- 負荷試験用のDynamoDBのスループット調整
負荷試験のシナリオの作成
事前に昨年のセール時のアクセスログを集計し、テストシナリオを調整しました。
(2)負荷試験の実施
チームラボさん の協力のもと、Jmeterを用いた負荷試験を実施しました。
負荷をかける側も分散しないと十分な負荷がかけられないため、最終的には、48台のインスタンスでそれぞれ 80スレッド、合計3840スレッドでの試験まで実施しました。
(3)負荷試験を結果で明らかになったボトルネックの解消
発生した問題点のほとんど(80%以上)が、スケールできないシステムに起因する問題でした。
起きた問題を分析、対応を行い、再テストを繰り返しました。
一部ですが、下記のような対応を行いました。
awsコマンドのリアルタイム処理での使用を削減
リアルタイム処理中に aws コマンドでs3に接続している部分がネックとなり、大量のaws コマンドが立ち上がりプロセス過多になる現象が発生しました。
awsコマンドはPythonで記述されていて起動自体が重く、リアルタム処理には耐えられないと判断し、非同期で処理を行うように改修しました。
(goなどで書かれた起動の軽い実装があればと思い探したのですが、使えそうなものが見つかりませんでした)
タイムアウト問題への対応
処理中にタイムアウトしてエラー画面になってしまう現象が多発しました。
システムのレイヤーが多段に重なりあっているため、どのシステムでタイムアウトエラーを出しているのかの調査を行い、タイムアウト時間の調整を行いました。
各レイヤー毎に、ELB、apache(mod_proxy)、mod_php、mod_cgiなど各所にタイムアウト設定があるためどこの設定が効いてタイムアウトになっているのか、調査に時間がかかってしまいました。
キャッシュを使ったリクエストの削減
同時リクエスト数が増えると負荷に耐えられないため、可能な限りキャッシュを使うように改修しました。
例えば、ネットストアのポイントについては、商品を発送しないとポイントが付与されないため、出荷作業を行わないセール当日については
ポイント情報を事前にキャッシュに乗せて処理するように改修を行いました。
(4)本番環境の準備
負荷試験を乗り切った各種システムの設定値などをまとめ、本番環境に適用しました。
また、チェックリストを作成し、きちんと本番に反映されているかどうかの確認を行いました。
- 本番環境のELBの Pre-Warming
- DynamoDBのスループットの設定
- ElasticBeanstalkのインスタンスタイプ、オートスケール設定
- ElastiCache/redisのインスタンスタイプ、台数の設定
- ElastiCache/memcachedのインスタンスタイプ、台数の設定
セールの結果
結果としては、準備の甲斐もあり、大きなトラブルもなくセールを終えることができ、ネットストア売上としては過去最高の売上を上げることができました。
※ セール開始直後に人が押し寄せている状態
また、これは負荷対策とは別なのですが、昨年は深夜00:00だったセール開始時間を今年は18:00に変更しました。
昨年は 00:00開始とともに、アクセスが集中し、つながりにくい状況になるとみんな諦めて寝てしまうという状況になってしまっていたのですが、今年は 18:00開始で、つながりにくい状況も発生しなかったため、開始後のピークを過ぎても長い時間お買い物していただける状況を維持することができました。
この辺りも売上アップへつながった要因ではないかと思います。
※ オレンジの線が2014年、青の線が2015年です。ピークのアクセス数は昨年より落ちましたが、ピークを過ぎた後も継続的にアクセスされました。
まとめ
大掛かりなセールなどの、急激なアクセス増加に対応するには、事前に実際の状況に近いテストがどこまで実施できるかがポイントだと感じました。
AWSを使っていると、簡単に台数を増やしたり、減らしたり、柔軟にテストが実施できるので良いですね。
ただし、AWSにもいろいろな所に上限が設けられているので、予めその上限を知るためにも事前にテストしておく事が重要です。
たとえば下記のようなものです。
- 大量にインスタンスを立ち上げようとしたら、インスタンス数の上限にひかかって立ちあげられなかった。
- c3.large のような一般的なインスタンスタイプは上限が多めに設定されていますが、マイナーなインスタンスタイプの場合、かなり少なく設定されていることがあります。
- ElasticBeanstalkでデプロイしようとしたら作れるセキュリティグループ数の上限にかかってデプロイに失敗した
- オートスケールでスケールできると思っていたが、サブネットのIPアドレスが枯渇した
- インスタンスを誰かが大量に買い占めていて立ち上がらなかった
- DynamoDBのスループットを上げようとしたが、上限の20,000に達していて上げられなかった。
- Elasticache/memcachedに5つ以上のノードを一度に追加したらエラーになることがあった。
大抵のものは、事前に試して経験していれば、上限緩和申請やその他回避策を講じて対応することができます。
また、AWSの不具合に遭遇することもありますが、事前に経験していれば、その機能を使わないなど、回避することが出来ます。
番外編
何かあった場合に備えて、下記の本を読みました。必要にならずに良かったです。
Amazon.co.jp: ITエンジニアのためのハイプレッシャー下での対応術: 鳥山 康見: 本