AWS 環境下においての NewRelic APM 導入構成の紹介

本記事は[サムザップ #1 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/sumzap1)の3日目の記事です。


# はじめに
弊社で運用しているゲームアプリは、サーバ言語として PHP を使用しています。

PHP のパフォーマンスを確認する際に、弊社では APM (Application Performance Monitoring) として [New Relic APM](https://newrelic.co.jp/products/application-monitoring/) を使用しております。
New Relic APM では Transaction Traces により PHP のトレース単位でのパフォーマンスも確認可能なので、弊社では以前より重宝しております。

しかし、NewRelic のエージェントを PHP が稼働する API サーバの全台に導入すると、コストがかかってしまいます。
今回は、弊社で使用している New Relic をコストを気にした上でどのような構成で導入しているかを紹介します。


# 前提
弊社で運用しているタイトルは、主に AWS のサービスを用いたアーキテクチャ上で稼働していることが多いです。
なかでも API サーバは、

* EC2 インスタンス
* ECS + Fargate

のどちらかで構築しています。
その両方においてどのように New Relic APM を導入しているか紹介します。

#導入
## EC2 インスタンスへの導入
API サーバとなる EC2 インスタンスに New Relic APM を導入する場合の構成は単純です。
ロードバランサに登録されているインスタンスの中のごく一部インスタンスにのみ New Relic のエージェントをインストールしておき、そのインスタンスに振り分けられたリクエストでのみ New Relic へのデータ送信を行います。
![NewRelic on EC2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30892/c321e5c2-0d4f-1c5b-1fb3-3c6aa5bef95a.png)

エージェントが稼働するインスタンスがほぼ固定となるため、料金体系としてもサーバホスト数での契約で最低限で済ますことができます。


## ECS + Fargate への導入
コンテナを前提とし、かつサーバレスで構築可能な ECS + Fargate への導入の場合は少し複雑になります。
さらに、弊社のように Blue/Green Deployment を採用していると、立ち上がるコンテナ群の中の一部だけに、New Relic エージェントを入れるといったことができないのでなおさらです。

#### ECS サービスレベルでの差別化
とった対策としては、通常の API 用の ECS サービス、さらに New Relic エージェントが導入された ECS サービスの2種類に分けることでした。
ECS サービスが分かれていれば、適用するタスク定義も分けることができ、それによって取得するコンテナイメージも分かれるので、片方に New Relic を導入することは容易です。
さらに、それぞれでスケールの設定を行えるので、New Relic が導入されている方の ECS サービスのみタスク数を最小構成で構築することも可能になります。


#### リクエストの振り分け
タスク数が最小構成となる ECS サービスには、もちろんそれで捌けるのに適した分だけのリクエスト量のみを振り分けなければいけません。

リクエストの振り分けは、ALB のリスナールールでの weight の比率による振り分けを想定して構築したのですが、CodeDeploy で Blue/Green Deployment を行う際に以下のようなエラーが発生しました。

```
The ELB could not be updated due to the following error: Only target group in ECS deployment group (arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXX:xxxxx, arn:aws:elasticloadbalancing:ap-northeast-1:YYYYYYY:yyyyy) can be set on listener arn:aws:elasticloadbalancing:ap-northeast-1:ZZZZZZZ:listener-rule/app/zzzzzzzz.
```
どうやら CodeDeploy は、デプロイ対象のターゲットグループが含まれる ForwardActionConfig プロパティに異なるターゲットグループが存在する場合、上記のエラーが発生してしまうようです。
つまり、ALB リスナールールにおいて、通常 API 用のターゲットグループと New Relic 用のターゲットグループで共存させることはできず、 weight での振り分けはできないことになります。

そこで、ALB のリスナーグループでの振り分けをやめ、Route53 の[加重ルーティング](https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/routing-policy.html#routing-policy-weighted)のルーティングポリシーでの振り分けを採用しました。
構成図で表すと以下のようになります。

![ECS on NewRelic.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30892/55cd1a07-99ee-d4d5-283a-6009c7d81ab8.png)



まず、通常 API の方と New Relic が導入された方の ECS サービスのそれぞれに対してロードバランサを作成します。
そして、Route53　で同じ名称とタイプの DNS レコードを2つ用意し、一つは重量を MAXの 255 に設定し、ルーティング先は通常の API 用のロードバランサへ、
![スクリーンショット 2020-12-02 13.04.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30892/b41c5602-0185-43f7-55a7-7fe13845b5bf.png)

もう一つは重量を最低値の 1 に設定し、ルーティング先を New Relic 用のロードバランサへと設定します。
![スクリーンショット 2020-12-02 13.04.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30892/a36a57e0-cbab-d580-9300-6946569fdf7b.png)

そうすることで、総リクエスト数の1/256の比率でNew Relic側の ECS サービスにリクエストが届くように抑えることができます。

# まとめ
今回は、弊社で利用している New Relic APM を EC2、ECS + Fargate の２つの構成においてどのようにコストを抑えて導入しているかを紹介しました。
実は現時点では、ECS + Fargate の構成の方はまだ本番導入までの検証途中ではあるのですが、New Relic 側の ECS サービスへのリクエスト量の抑制は加重ルーティングを用いて実現できています。

あとは、弊社はかねてより New Relic との契約を行っており、今年の8月頃に行われた[大幅な価格改正のプラン](https://blog.newrelic.co.jp/new-relic-news/new-product-and-pricing/)ではまだ適用していません。

今後としては、紹介した ECS + Fargate の構成での負荷検証も行い、さらに新しい価格プランで他のどういったことができるの検討も行っていきたいと考えています。