こんにちは、エンジニアの id:tsub511 です。
最近頭痛がするのでヨガを始めましたが、効果が出ているのかよく分かりません。
今回は m3.medium のインスタンスの CPU 負荷が高かったため t2.medium へ移行したら解決した話をします。
m3.medium のインスタンスの CPU 負荷が高かった
年始あたりから、週に数回ほど決まった時間に Mackerel でアラートが出ていました。
CPU の Steal 値が異常に高く、全体としての使用率が 90 % を超えていました。
ずっと原因が分からず、最初は Meltdown と Spectre のパッチを適用した関係で性能が低下したんじゃないか、などを疑っていました。
しかし、ある時全く別の作業をしていたときに別のロールのインスタンスで同様に CPU 負荷が上がり、どちらも m3.medium
というインスタンスタイプが共通していたことからなんとなくググってみたところ、以下の記事に辿り着きました。
どうやら、m3.medium
というインスタンスタイプのみ CPU の Steal が発生しやすいようです。
他にも同様の報告をしている記事をいくつか見つけました。
- https://forums.aws.amazon.com/thread.jspa?threadID=146585
- High CPU steal on EC2 m3.medium – Bonobos Tech Blog
情報が 2014 年と古いですが、現に同様の事象が発生しているため、当時と変わっていない可能性が高いです。
そのため、インスタンスタイプを変更することを検討しました。
他のインスタンスタイプを検討
m3.medium
から別のインスタンスタイプに変更するに辺り、どのインスタンスタイプを選択するか、まずはコスト面で比較しました。
順当に行けば m4
ファミリーが妥当なところですが、m4
ファミリーは medium サイズは提供していないため、費用がそれなりに増えてしまいます。
この中で、m3.medium
よりも安い t2.medium
に目を付けました。
t2.medium
は m3.medium
に比べると、 vCPU が 1 コア増え、メモリも 0.25 GB 増える上に料金が安くなるというかなりお得なインスタンスタイプです。
m3.medium
インスタンスファミリー インスタンスタイプ プロセッサアーキテクチャ vCPU メモリ (GiB) インスタンスストレージ(GB) EBS 最適化利用 ネットワークパフォーマンス 汎用 m3.medium 64 ビット 1 3.75 1 x 4 - 中
t2.medium
モデル vCPU CPU クレジット/時 メモリ (GiB) ストレージ t2.medium 2 24 4 EBS のみ
ただ、ここで安易に t2.medium
を選択してはいけません。
t2
ファミリーは「バースト可能パフォーマンスインスタンス」という特別な性質があります。
T2 インスタンスについて
T2 インスタンスについて、今までふわっとした理解しかなかったため、この機会に AWS のドキュメントをちゃんと読んでみました。
結論から言うと、弊社のサービスの性質上、決まった時間に Sidekiq のジョブがまとまって大量に実行されるため、普段は CPU 使用率は低く、ある時間だけ CPU 使用率が高くなるというまさに T2 インスタンスがピッタリなケースでした。
CPU クレジット
T2 インスタンスには CPU クレジットという概念があります。
1 CPU クレジットは 100 % の CPU 使用率を 1 分間稼働させることができます。
t2.medium
は CPU クレジットが 1 時間あたり 24 なので、100 % の CPU 使用率を 24 分間、あるいは 50 % の CPU 使用率を 48 分間、40 % の CPU 使用率なら 60 分間稼稼働させることができることになります。(ただし、t2.medium
は vCPU が 2 コアなので、実際には 20 % の CPU 使用率で 60 分間の稼働)
実際の CPU 使用率は平均で 20 % 以下に収まっていることが多い (たまにスパイクはする) ので、CPU クレジットが 24 ならまず問題ないです。
この 40 % (20 %) という値をベースラインパフォーマンスと呼び、これを超えて CPU を使用することを「バースト」と呼びます。
また、ベースラインパフォーマンスよりも CPU 使用率が下回っていた場合、クレジットバランスというものに余分な CPU クレジットが保存されます。 クレジットバランスに保存された CPU クレジットは、CPU 負荷がベースラインパフォーマンスを上回った時に消費されます。
つまり、余分な CPU クレジットは蓄積されて後で使うことができるということになります (ただし t2.medium
の最大クレジットバランスは 576)。
注意点としてはインスタンスを停止するとクレジットバランスに貯まった CPU クレジットは破棄されるというところでしょうか。
T2 Unlimited
ただ、T2 インスタンスを使う以上、気にしなければいけないのは CPU クレジットがなくなった場合は CPU のバーストができなくなるということです。
CPU のバーストができないということはつまり、ベースラインパフォーマンス (t2.medium
の場合は 20 %) 以上の CPU が使えなくなるということになります。
ただし、去年の Re:Invent にて発表された T2 Unlimited という機能を有効にすることで CPU クレジットがなくなった場合でも自動的に CPU クレジットを追加され、CPU 使用に制限がかからなくなります。
具体的には、T2 Unlimited を有効にすると、CPU クレジット及びクレジットバランスがなくなった場合、余剰クレジットというものから消費されるようになります。
最初の余剰クレジットは 24 時間で獲得できるクレジットの合計値となります。
例えば t2.medium
の場合、1 時間辺りの獲得クレジットは 24 なので 24 時間で 576 のクレジットが余剰クレジットになります。
この 24 時間分の余剰クレジットは前借りのようなもので、消費した分だけ次のクレジット獲得時に余剰クレジットの支払いに使用されます。
24 時間分の余剰クレジットまで全て使い切ってしまった場合でも、その後に消費した余剰クレジット分は追加で課金され、CPU のバーストは継続することが可能です。
つまり、T2 Unlimited を有効にすれば T2 インスタンス特有の CPU クレジットの枯渇による CPU 使用制限の問題が解決されることになります。
ただし、常にバーストし続けて追加でお金が発生し続けるような場合は、T2 インスタンスでなく普通にインスタンスタイプを利用したほうが懸命ですね。
CPU クレジットの監視
T2 Standard (非 T2 Unlimited) であっても、T2 Unlimited であっても、普段からどの程度 CPU がバーストしているかは監視しておいたほうが良いです。
そのために、CloudWatch で CPUCreditUsage
, CPUCreditBalance
, CPUSurplusCreditBalance
, CPUSurplusCreditsCharged
という 4 つのメトリクスが提供されています。
個人的には T2 Unlimited の場合、基本的には CPUSurplusCreditBalance
と CPUSurplusCreditsCharged
を監視しておけば良いと思います。
CPUSurplusCreditBalance
は消費された 24 時間分の余剰クレジット数CPUSurplusCreditsCharged
は 24 時間分の余剰クレジットを使い切った後で更に消費される余剰クレジット数
実際の監視には Datadog を利用しました (現在監視ツールを Datadog へ移行途中なため)。
閾値はまだ感覚を掴めていないため、とりあえず厳しめにしてあります。
m3.medium
から t2.medium
へインスタンスタイプを変更する
弊社のサービスのインフラでは、Blue Green Deployment が可能な体制が整っているため、インスタンスタイプの変更は非常に簡単です。
新しい環境のインスタンスは t2.medium
で作成し、ELB からコネクションが流れるようになったら、古い環境のインスタンスを削除するだけです。
ただ、EC2 の Launch Configuration + Auto Scaling Group を使っていたため、少し工夫が必要でした。
T2 Unlimited の有効化は Launch Configuration ではサポートされていませんでした。
Auto Scaling グループで T2 インスタンスを無制限に設定して起動するには起動テンプレートを使用する必要があります。起動設定では、T2 インスタンスを無制限として起動することがサポートされていません。
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/t2-unlimited.html#t2-auto-scaling-grp
Launch Template ならサポートされているものの、今から移行するのも大変ですし、何より Terraform がまだ Launch Template をサポートしていませんでした (2018/03/02 時点)。
どうしようと困っていたところ、以下の記事に助けられました。
EC2 User Data を使って、インスタンス起動時に自身に対して T2 Unlimited を有効化する、という方法です。
自分では全く思いつきませんでしたが、User Data も Terraform を使って管理できるのでかなりシンプルに実現できました。
実際には以下の User Data を利用しました (CentOS を使っているため $ yum install aws-cli
ができない)。
#!/bin/bash set -x # Install aws-cli curl -L https://bootstrap.pypa.io/get-pip.py | python pip install awscli --upgrade # Enable T2 Unlimited INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id) REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//') aws --region "${REGION}" ec2 describe-instance-credit-specifications --instance-id "${INSTANCE_ID}" aws --region "${REGION}" ec2 modify-instance-credit-specification --instance-credit-specification InstanceId="${INSTANCE_ID}",CpuCredits=unlimited aws --region "${REGION}" ec2 describe-instance-credit-specifications --instance-id "${INSTANCE_ID}"
これで、Auto Scaling Group によって起動したインスタンスに対して自動的に T2 Unlimited が有効になりました。
インスタンスタイプを t2.medium
に変更した結果
実際に t2.medium
のインスタンスを稼働させた結果、同程度の負荷がかかった際の CPU の Steal 値はほぼ 0 になりました。
ちなみに t2.medium
は vCPU が 2 つあるため、グラフの最大値は 200 % になっています。
user 値が 90 % 程度なので、実質 CPU 使用率は 45 % 程度で、m3.medium
の頃とほとんど性能は変わっていません。
また、その他にも 5 分間のロードアベレージも全体的に下がっていました。
まとめ
m3.medium
のインスタンスを使っていて CPU 負荷に悩まされている場合はインスタンスタイプを変更すると解決するかも- T2 インスタンスは適材適所で使えば費用を安く抑えられて非常に良い
- T2 Unlimited によって CPU クレジットがなくなる問題が解決されて安心して T2 インスタンスを使用できるようになった
- T2 Unlimited を Launch Configuration で有効化したい場合は User Data を使うと良い
m3.medium
が原因だったようで、解決して良かったです。日々のアラートに悩まされなくて良くなりました。