✌️

APMサービスを作ったからアーキテクチャを晒す

2023/08/29に公開

この記事について

APMを作りました。

「どんなSQLを実行したか」とか、「どれくらい時間がかかったか」とかを記録できる、アレです。
DatadogやNewRelicが有名ですね。

それを、OpenTelemetry用に作りました。

Vaxilaといいます。問題の解決と安さに重点を置いたサービスです。
https://vaxila-labs.com/
自分のサイトだけではなく、他社でもちゃんと動いているで、多くの人に使って貰えれば、と思います。

この記事では、Vaxilaのアーキテクチャや工夫を紹介します。
アーキテクチャの画像

出来ること

Vaxilaは問題を解決することに焦点を当てたサービスです。
今まで何度も何度もエラーや遅延の調査をしてきたので、こういう作業をルーティンに感じています。
なので、自動化するサービスを作りました。

そのために、分散トレーシングを集めるために、OpenTelemetryを利用しています。
https://opentelemetry.io/

つまり、

  • トレースからエラーを発見し、スタックトレースなどの情報を基にエラーをまとめる
  • エラーになったトレースと、エラーでないトレースを比較してエラー原因を推測して解決法を提案する

ということをしています。

ついでにトレースのデータをS3で保存するようにしたので、コストを抑えることもできました。

アーキテクチャ全体像

さて、Vaxilaの内部の話をするために、まずは全体像について書きます。

アーキテクチャの画像

Vaxilaには大きく分けて2種類のアクセスがあります。

  1. ユーザーが操作する画面からのアクセス
  2. OpenTelemtryのデータを取り込む(受け取る)時のアクセス

この2つは別の特性を持っています。
ユーザー画面では同期的処理が大部分を占めますが、データの取り込みは非同期です。
これは、OpenTelemyを取り込む頻度やデータ量が利用者のサービスに依存するため、Vaxilaでは制御・予測できないからです。

また、データをS3に置いてAthenaで検索しているのも、一般的なWebサービスとは違う点です。

S3 & Athena

詳細に入ります。

最初に見るのは、OpenTelemetryのデータを保存している、ストレージについてです。

OpenTelemetryのトレーシングを保存するにはスペースが必要です。
データ量はリクエスト数に比例して増大します。
小さなサービスであってもギガを超え、大きなサービスではテラを優に超えます。
しかも、サービス数自体も契約社数に従って増えるわけです。

それを支えるために、大きなDBを用意したり、クラスタを組んで分散させたり、ということも可能ですが、VaxilaではデータをS3に保存することを選びました。
S3を使えば、データサイズが大きくなることを気にする必要が少なくなります。
また、ストレージコストも大幅に下がります。

これはGrafanaのTempoやOpenObserveでも見られる仕組みですね。
https://github.com/grafana/tempo

クエリエンジンまで自作しているOSSもありますが、それは大変なのでAmazon Athenaを利用しています。

Vaxilaでは、それに加えて、トレースのIDと保存先のパスをRDBに保存しています。
データをS3にだけ保存すると、「IDを指定してデータを取得したい (例: トレースの詳細ページ)」という要求と「時間の範囲を限定して検索したい (例: トレースの検索ページ)」という要求両方を効率的に満たすことができません。
なので、検索の効率化のためにS3上では時間ごとにディレクトリを作り、IDを指定する場合はS3のファイルを直接ダウンロードするようにしています。

ちなみに、ファイルのフォーマットは列志向のParquetを使っています。また、検索を効率化するためにOpenTelemetryのフォーマットを逆転させ、1行1Spanで保存することもしています。

取り込み部分

次に、データの取り込み部分について。

取り込み部分のアーキテクチャ

図のように、直接データを受け取るのはAWS Lambdaです。
キューを挟むことで非同期にしています。
Lambdaを使っているのは、ユーザーのシステムに合わせて取りこぼさないようにスケーリングするのが大変そうだったからです。
同じ理由で、負荷に潰されないようにキューを挟んでいます。

具体的には、データを数秒貯めたあとに一括処理しています。
一括処理することでS3上のファイル数が少なくなり、Athenaの処理が効率的になるというメリットもあります。

また、キューに入っている間の一時データを貯める場所にはRedisを使っています。
SQSやS3に貯めるという方法もありますが、SQSには256KBしかデータを持たせられないという制限がついているため使いませんでした。
OpenTelemetryのデータの1つ1つはそれほど大きくないので、256KBあれば十分な量にも思えるのですが、バッチでまとめたときには256KBを超えるのではないかと懸念しました。
逆にS3を使って、都度一時ファイルとしてS3に貯めるようにすると、PUTの料金が高くなるのではと懸念しました。
なので、それらを一時データの保存先としての選択肢から除いた結果、Redisを使っています。

Web部分

最後に、Web部分について。

Web部分のアーキテクチャ

フロントではGraphQLとSvelteを使いたいということだったので、使っています。
また、エラー原因の推測と解決方法の提案をするのはユーザーが画面を使っているときなので、GraphQLを受けてAthenaを動かしてもいます。

最後に

以上、Vaxilaの内側についてでした。

これからも機能を追加し続けるつもりで、SLO管理の機能や、エラーの原因推測を充実させるための機能など、色々やりたいことがあります。

既存のAPMが高くて困っていたり、OpenTelemetryを使いたくなったら、Vaxilaを使ってみてください。
https://vaxila-labs.com/

Vaxila

Discussion