Morisawa Fonts に AWS X-Ray を導入しました
こんにちは、株式会社モリサワ システム開発部門の川村です。
クラウド型フォントライセンスサービスの「Morisawa Fonts」の開発を担当しています。
Morisawa Fonts に AWS X-Ray
を導入したので、簡単に紹介したいと思います。
X-Ray とは?
AWS が提供する分散アプリケーションの分析とデバッグのためのサービスです。
アプリケーションが処理するリクエストの詳細なデータを収集し、アプリケーション全体のパフォーマンスや、アプリケーション内の各ノードの依存関係、レイテンシー、エラー率などを可視化することができます。
そのため、パフォーマンスのボトルネックやエッジケースのエラーなど、アプリケーションが抱える問題について、根本原因を特定することが可能になります。
例えば、DynamoDB や SQS といった AWS サービスに加えて、外部 HTTP API、RDB への SQL 呼び出しなども詳細なデータが収集可能です。
Morisawa Fonts では、
- マイクロサービスアーキテクチャで構築しており、パフォーマンスのボトルネックやエッジケースのエラーの根本原因の特定が難しい
- AWS をベースにインフラを構築しているため、他の類似サービスよりも導入コストを抑えられそう
以上から X-Ray の導入に踏み切りました。
X-Ray の構成
X-Ray は以下の4つの要素で構成されています。
X-Ray SDK
トレースデータを生成し、X-Ray デーモンに送信するためのライブラリです。
Go、Java、Node.js、Python、.NET、Ruby などに対応しています。
トレースしたい処理を X-Ray SDK が提供するクラスやメソッドでラップし、インストルメント化することで、透過的にトレースデータを生成します。
X-Ray API
トレースデータの送信、取得などを行うための API です。
X-Ray SDK はトレースデータを直接 X-Ray API には送信しておらず、後述の X-Ray デーモンに対して送信しています。
そのため X-Ray SDK を使用する際は、X-Ray デーモンの起動も必要になります。
X-Ray デーモン
X-Ray SDK と X-Ray API を中継するエージェントです。
UDP ポート2000をリッスンし、X-Ray SDK から受信したデータを一定時間バッファしたのち、X-Ray API に送信します。
Elastic Beanstalk、EC2、ECS、ローカルで実行可能です。
それぞれ実行方法が異なるため、実行環境に応じた対応が必要になります。
X-Ray コンソール
収集したトレースデータを可視化し、アプリケーションの分析を行うためのツールです。
アプリケーション全体のパフォーマンスを表示する機能や、個々のトレースデータの詳細を表示する機能などがあります。
実装
前項を踏まえると X-Ray を導入するためのポイントは以下の2つです。
- アプリケーションに X-Ray SDK を組み込むこと
- X-Ray デーモンを起動すること
それぞれ対応していきます。
X-Ray SDK の組み込み
Backend に X-Ray SDK を組み込みます。
Morisawa Fonts の Backend は ECS Fargate で運用し、Go で実装しています。
そのため、X-Ray SDK for Go を組み込んでいきます。
いくつかポイントとなる部分を抜粋してお伝えします。
HTTPハンドラー
xray.Handler
でラップし、HTTP リクエストをインストルメント化します。
sn := xray.NewFixedSegmentNamer(segmentName)
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 処理
})
instrumentedHandler := xray.Handler(sn, handler)
セグメント名には任意の値が設定可ですが、Morisawa Fonts では環境単位(ステージング、プロダクションなど)で付けるようにしました。
そうすることで、トレースデータを環境単位でフィルタリングすることが容易になります。
AWS セッション
xray.AWSSession
でラップし、AWS セッションをインストルメント化します。
instrumentedSession := xray.AWSSession(session.Must(session.NewSession()))
RDB
xray.SQLContext
を使用し、SQL 呼び出しをインストルメント化します。
instrumentedDB, err := xray.SQLContext(driver, dsn)
外部 HTTP API
xray.Client
を使用し、外部 HTTP API 呼び出しをインストルメント化します。
instrumentedHttpClient := xray.Client(httpClient)
ユーザー ID
xray.Segment.User
にユーザー ID を記録します。
segment := xray.GetSegment(ctx)
segment.User = userID
トレースデータをユーザー ID でフィルタリングすることが可能になります。
注釈
xray.AddAnnotation
で追加情報を記録します。
err := xray.AddAnnotation(ctx, key, value)
トレースデータを当該情報でフィルタリングすることが可能になります。
ただし、格納できるデータ型やデータ長に制限 [1] があります。
メタデータ
xray.AddMetadataToNamespace
で追加情報を記録します。
err := xray.AddMetadataToNamespace(ctx, namespace, key, value)
メタデータは注釈と異なり、当該情報でフィルタリングすることはできません。
その代わり、構造体やマップなどの複雑なデータを格納することが可能です。
エラー情報
エラーが発生した場合、xray.AddError
でエラー情報を記録します。
err := xray.AddError(ctx, err)
エラーメッセージやスタックトレースなどが記録され、トラブルシューティングに役立ちます。
X-Ray デーモンの起動
インフラに X-Ray デーモンの設定を追加します。
先述の通り、Morisawa Fonts の Backend は ECS Fargate で運用しています。
そのため、1つのタスク定義の中に以下の2つのコンテナを含め、サイドカーパターンとなるように改修します。
- Backend API サーバーコンテナ
- X-Ray デーモンコンテナ
- UDP ポート2000のトラフィックをリッスンし、Backend API サーバーコンテナから送信されたトレースデータを X-Ray API に中継します
また、タスクロールに X-Ray への書き込み権限を追加します。
改修後のタスク定義、タスクロールの概略は以下のようになります。
タスク定義
{
"taskDefinitionArn": XXXXXXXX,
"containerDefinitions": [
{
"name": "ApiContainer",
"image": XXXXXXXX,
"cpu": XXXXXXXX,
"memory": XXXXXXXX
},
{
"name": "XRayDaemonContainer",
"image": "amazon/aws-xray-daemon",
"cpu": 32,
"memoryReservation": 256,
"portMappings": [
{
"containerPort": 2000,
"hostPort": 2000,
"protocol": "udp"
}
]
}
],
"compatibilities": [
"EC2",
"FARGATE"
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": XXXXXXXX,
"memory": XXXXXXXX
}
タスクロール
{
"AttachedPolicies": [
{
"PolicyName": "AWSXRayDaemonWriteAccess",
"PolicyArn": "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess"
}
]
}
注意点として、サイドカーパターンの場合、コンテナの CPU の合計はタスクの CPU より大きくすることはできません。
そのため、
Backend API サーバーコンテナの CPU + X-Ray デーモンコンテナの CPU <= タスクの CPU
となるように設定する必要があります。
トレースデータ確認
X-Ray コンソールからトレースデータを確認します。
サービスマップ
アプリケーションによって生成されたトレースデータを視覚的に表したものです。
リクエストの処理中に使用したサービスの流れや各種メトリクスが可視化されており、アプリケーション全体のパフォーマンスの確認に役立ちます。
ノードを一覧表示することも可能です。
トレース詳細
個々のリクエストの開始から終了までに収集されたデータを可視化したものです。
当該リクエストの処理中に使用したサービスの流れや各種メトリクスを可視化したトレースマップと、個々の処理を時系列で可視化したタイムラインがあります。
タイムラインでは個々の処理で収集された詳細なデータを確認することが可能で、ボトルネックやエラーの根本原因の特定に役立ちます。
おわりに
Morisawa Fonts に X-Ray を導入した件について紹介しました。
X-Ray の導入により、アプリケーション全体のパフォーマンスや個々のリクエストの詳細なデータを可視化できるようになりました。
そして X-Ray を導入したことで、メール送信箇所にボトルネックが存在することが判明しました。
迅速にチューニングを行い、X-Ray が Backend のパフォーマンス改善に早速役立ちました。
注意点として、X-Ray はサンプリングのため、デフォルトでは全リクエストを収集するわけではありません。必要に応じてサンプリングルールをカスタマイズしてください。
引き続き X-Ray を活用し、アプリケーションの分析と改善に取り組み、サービスの品質向上に努めて参ります。
-
注釈に関する制限事項は以下のドキュメントを参照ください。
https://docs.aws.amazon.com/ja_jp/xray/latest/devguide/xray-sdk-go-segment.html ↩︎
Discussion