コラム

アクセススパイクに耐えるため、aws-cliでScheduled Actionを設定する

2017-01-04

荻田 魁

WRITER:

荻田 魁

HAIR-WEBの開発を行っている16年新卒の荻田です。
最近チームにフロントエンドの人が増えて嬉しいです。

#HAIRについて

iOS, Android,Webでサービスを展開しており、Webは大まかにLaravel5.1 + AWS(Docker)を使って構築されています。
また、3ヶ月で約300%成長をしているサービスで11月に100万UUを突破することができました?
今回は、あまり似たような環境はないかと思いますが、HAIRで実際に起こった課題とその対応策のアプローチを紹介します。何かしら参考にしていただけると幸いです。

[課題]予想されている突発的なアクセススパイクに耐える。

HAIRでは、LINE公式アカウントを作成しており、友だち数が90万人強います。
そしてそのユーザーに向けて記事を配信し、提携媒体にも記事を提供しています。
よって、記事を配信する夜の21:30くらいから22:30にアクセスが集中する傾向にあります。

#リクエスト数

普段では5分間のリクエスト数(ELBのcloudWatchのモニタリング)は3000reqですが、
毎日21:50から22:10くらいまでの5分間のリクエスト数が少ない時に15,000req、多い時には80,000reqまで増加します。

#当初考えていたアプローチ

AutoScalingのScalingPolicyにCPU使用率などに閾値を設けてインスタンス数を追加するという方法が一般的(?)でしたが、
アクセス増加時間が短いためインスタンスが起動して繋がるまでにSOSを発しているインスタンスが接続不可になることがわかりました。

[対応策]時間でautoscaleして対応

なので予測されているアクセススパイクに対しては、scheduleを組んでインスタンスを増やす方向で対応することになりました。
スケジュールの設定をするコードが以下のものになります。
aws-cliの初期設定についてはこちらを参考にしてください。

大きく分けてこのようになっています。(記事の見え方のため改行しています)

Step1 : 本番ELBに所属しているinstance-idの取得します。

#!/bin/bash

ELBName="###ELB-NAME###"

#接続されているinstance-idの取得
ConnectingInstanceId=$(\
aws elb describe-instance-health \
--load-balancer-name $ELBName | \
jq -r '.InstanceStates[].InstanceId')

echo "connecting instance-id is : "$ConnectingInstanceId

Step2 :そのinstance-idが所属してるscaling groupを取得します。

#instance-idから接続されているauto scaling groupを出す。

AutoScalingGroupName=$( \
aws ec2 describe-instances \
--instance-ids $ConnectingInstanceId | \
jq -r '.Reservations[].Instances[].Tags[] | \
select(.Key =="aws:autoscaling:groupName").Value')

echo $ConnectingInstanceId" connected to auto scaling group is "$AutoScalingGroupName

Step3 : スケジュールの設定と削除を行います。

#Prodに接続されている方にスケジュールを追加、されてない方は削除する
if [ "$AutoScalingGroupName" = "###Scale-group-name-B###" ]; then
    setScheduleAutoScalingGroup="###Scale-group-name-B###"
    removeScheduleAutoScalingGroup="###Scale-group-name-A###"
else
    setScheduleAutoScalingGroup="###Scale-group-name-A###"
    removeScheduleAutoScalingGroup="###Scale-group-name-B###"
fi

#スケジュール用に
date=$(date +%Y-%m-%d)

startScheduleName="###schedule-name###"
stopScheduleName="###schedule-name###"

#毎日21:00~23:00まで最大5台最小5台希望5台で設定する。それ以外は1台で

aws autoscaling put-scheduled-update-group-action \
--auto-scaling-group-name $setScheduleAutoScalingGroup \
--scheduled-action-name $startScheduleName \
--recurrence "0 12 * * *" \
--min-size 5 \
--max-size 5 \
--desired-capacity 5 \
--time $date"T12:00:00Z"

aws autoscaling put-scheduled-update-group-action \
--auto-scaling-group-name $setScheduleAutoScalingGroup \
--scheduled-action-name $stopScheduleName \
--recurrence "0 14 * * *" \
--min-size 1 \
--max-size 1 \
--desired-capacity 1 \
--time $date"T14:00:00Z"


#delete schedule

aws autoscaling delete-scheduled-action \
--auto-scaling-group-name $removeScheduleAutoScalingGroup \
--scheduled-action-name $startScheduleName

aws autoscaling delete-scheduled-action \
--auto-scaling-group-name $removeScheduleAutoScalingGroup \
--scheduled-action-name $stopScheduleName

※2つのScaling groupに対して行っているのはHAIRではBG deployの手法を取っており2つのscaling groupを切り替えているからです。

予想以上に長くなってしまったのでもっと賢いやり方があると思って模索しています。Step1-Step2を省略できそうな感じがするのですが・・・

またお金がかかっているので、スケーリングする台数やそのスペックなどしっかりとあったものを選んで無駄を省いていきたいですね。

最後に

HAIRチームで一緒に働いていただける方を絶賛募集中です。

▷ iOSエンジニアの募集はこちら