動画配信サービスにNew Relicを使った監視


こんにちは、streampack の Tana です。
今回は動画配信サービス に [New Relic(APM)](https://newrelic.com/products/application-monitoring) を導入したお話になります。

## 背景

Webアプリケーションを本番運用していくと、リリースの不具合によりエラーが発生したり、またはレコードが増えることでパフォーマンスの低下が顕在化します。一般的にはログを見て原因を調査しますが、膨大なログから原因を特定するのは時間を要します。そこで原因が特定できればいいのですが、再現性がない場合は、一時的な要因と片付けることがあります。がしかし、そのような場合はまた発生します。さらに、そのような事象は開発環境では再現するのが困難です。そこで `New Relic` の登場です。

[New Relic](https://newrelic.com/) は AWS, Google Cloud, Azure などのクラウドプロパイダーのリソースやアプリケーションを監視してくれるサービスの一つです。APM(Application Performance Monitory)を導入することで、アプリケーションのパフォーマンスからエンドユーザーのエクスペリエンスを可視化されリアルタイムに分析することができます。

## 導入した経緯は？

アプリケーション(言語)によって多少実装方法は異なりますが、既存のサービスに影響が少なく簡易に導入できることがまず一つです。具体的に必要な実装は、パッケージをインストールし、ライセンスキーをセットすることで適用されます。(一部の言語は必要な箇所に組み込む必要あり)

また、Datadogを使ってクラウド関連の監視も行っておりますが、不十分なケースがあります。何かアラートなどを検知した場合は結局アプリケーション側の調査が必要になり、膨大なログから原因の特定が必要です。APMの導入することによって、エラーのトレースログを出力してくれたり、ボトルネックとなっているリクエストや処理をリストアップしてくれたりと、効率的に調査が可能になります。

## 導入方法

弊社の streampack は主に Rails と Golang のアプリケーションで構築してますので、そちらの言語での導入について、説明します。

### Rails のアプリケーションの導入

他の記事でも多く記載されていますが、Railsの場合の APM の導入は簡単でかつ多くのメトリックス情報を取得することができます。
払い出された `config/rewrelic.yml` を読み込むことも可能ですが、Dockerを使用してますので、envファイルに必要な情報を定義します。
https://docs.newrelic.com/docs/agents/ruby-agent/configuration/ruby-agent-configuration/#Options

``` ruby:Gemfile

gem 'newrelic_rpm'
```

開発環境、本番環境とそれぞれ、 `NEW_RELIC_APP_NAME` を変えることで、環境に応じたAPMとして出力されます。

``` ruby:.env.example
NEW_RELIC_LICENSE_KEY=ライセンスキー
NEW_RELIC_APP_NAME=service-app-env
```

Railsの場合は以上です。リリースしてアクセスすると、ニアリアルタイムでページに反映されます。

### Golang アプリケーションに導入

Goの場合は、必要な箇所の処理前後に入れてあげる必要があります。
gin というフレームワークを使ってますので、middleware として設定することで、最小限のコードでAPIの処理時間の計測が可能になります。 Gorilla のフレームワークも同様に組み込むことも可能です。

``` go:.env.example
NEW_RELIC_LICENSE_KEY=ライセンスキー
NEW_RELIC_APP_NAME=service-app-env
```

``` go:main.go

func main() {
    r := gin.Default()
    r.Use(NewrelicMiddleware(os.Getenv("NEW_RELIC_APP_NAME"), os.Getenv("NEW_RELIC_LICENSE_KEY")))
    ...
}

func NewrelicMiddleware(appName string, licenseKey string) gin.HandlerFunc {
    config := newrelic.NewConfig(appName, licenseKey)
    app, _ := newrelic.NewApplication(config)
    return func(c *gin.Context) {
        txn := app.StartTransaction(c.Request.URL.Path, c.Writer, c.Request)
        defer txn.End()
        c.Next()
    }
}
```

## 具体的にどのような情報が取れるの？

### サマリーページ - Summary

全体的にパフォーマンスに問題ないか、またはエラーが出てないかをサマリーとして確認できます。
通常と異なる傾向であれば、スパイクのようなグラフになったり、Error Rate が上がる傾向があるかと思います。
[Apdex Score](https://www.apdex.org/overview.html) というのは、アプリケーションパフォーマンスの指標で、
Satisfied / Tolerating / Frustrated の基準があり、スコアが 1 に近ければ近いほど、ユーザーの満足度がいい結果になります。
また、ライブ配信などはピークイベントで急にトラフィックが増えます。その際はこのサマリーページ(Summary)ページで監視できます。

![newrelic-summary-w300.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232803/ded62ada-5f08-d68f-3275-d70d4f51a33a.png)


### 不具合やエラーを特定する - EVENTS(Errors)

下記は Railsのエラーの場合のスタックトレースログです。ぼやかしているので、わかりづらいですが、ログを漁ることなく、原因の特定につながります。

![newrelic-error-trace-w240-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232803/8aa0c9fd-4059-6ca1-7166-3c392981b5c1.png)

### 視聴ユーザーの顧客体験可視化する - REPORTS(SLA)

デイリーの SLA(Service Level Agreement) のレポートです。
視聴者(ユーザー)に満足のいくWebのレスポンスが返せているかの指標になります。
もし、クライアント・サーバーサイドのレスポンスが悪いのであれば、Frustratedのパーセンテージが上がり離脱の原因の一つになるでしょう。

![newrelic-sla-w-400.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232803/4e1a10ea-29e2-295b-5e86-505d31fd0c7b.png)

### 遅い処理はどれ？ - Monitor(Transactions / Databases)

何かサービスに影響しそうなリクエストはないかなど、調査確認する際は、Monitor にて確認できます。
下記のように、 Sort by "Showest average response time" で絞り込むことで最も遅い処理がリストされます。

![newrelic-transaction-slowest-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232803/010028ca-fcd5-92ae-6d7f-28bd75c4db0e.png)

上記の 8.51s は集計系の処理なので、時間がかかるものだと認識済みですが将来的には改善すべき、ということなどがわかります。

### 外部サービスとの連携 - Service Map

外部との連携しているAPIやサービスの連携部分の可視化などもされます。

## まとめ

New Relic の APM を導入することでアプリケーションのパフォーマンスが容易に確認でき、サービスの安定運用、運用の効率化に繋がるのではないかと思ってます。また、クラウド系の監視とインシデント時のアラートを組み合わせをすることでより網羅的に安定運用かつ迅速な対応ができるのではないかと思ってます。