エンジニアリング

無料かつオープンのElastic APMでElasticオブザーバビリティデプロイを拡張する

以前の記事では、Elasticオブザーバビリティの無料かつオープンのプランを導入する方法についてご紹介しました。今回は、デプロイを拡張してアプリケーションパフォーマンス監視(APM)のメトリクス収集、つまりオブザーバビリティクラスター内のデータを"追跡"する機能を無料で導入する方法について説明します。

APMとは?

アプリケーションパフォーマンス監視では、アプリケーションについて、時間のかかっている処理、現在の状況、呼び出されている他のアプリケーションやサービス、発生しているエラーや例外を確認できます。

distributed-trace.png

さらにAPMでは、レイテンシーやスループット、トランザクション、依存関係の情報など、重要なパフォーマンス指標の履歴と傾向も把握できます。

ruby-overview.png

SLA違反アラートの設定や最新リリースのインパクトの測定、次の改善対象箇所の特定などを行う際には、APMを利用して根本原因分析を進めることで、ユーザーエクスペリエンスの向上や平均復旧時間(MTTR)ゼロの実現につなげられるでしょう。

論理アーキテクチャー

Elastic APMはElastic Agentに搭載のAPM統合をベースとしており、このAPM統合によって、各種APM Agentのインストルメント対象のアプリケーションからトレースデータとメトリクスデータがElasticオブザーバビリティに転送されます。Elastic APMは、以下のとおり複数タイプのエージェントに対応しています。

  • ネイティブElastic APM Agent:Java、.NET、Go、Ruby、Python、Node.js、PHP、クライアントサイドJavaScriptなどの複数の言語バージョンあり 
  • OpenTelemetryでインストルメント化したコード
  • OpenTracingでインストルメント化したコード
  • Jaegerでインストルメント化したコード

この記事では、ネイティブElastic APM Python Agentを使用してコードをインストルメント化する方法の例を紹介しますが、他の言語でも手順はほとんど同じです。

Elastic APM AgentElastic Agentには明確な違いがあります。上図で示すように、これらはまったく異なるコンポーネントですので、混同しないように注意してください。

Elastic Agentをインストールする

最初のステップは、Elastic Agentをインストールすることです。Fleetを先にインストールしておく必要があります。これを使用しない場合は、スタンドアローン形式のElastic Agentをインストールしてください。こちらのガイドの手順に従い、Elastic Agentを任意の場所にインストールします。これで、ヒット対象のAPM統合エンドポイントを用意できました。なお、Elastic CloudではAPM Integration統合がホストされているので、この手順は不要です。以下を実行して、Elastic Agentが動作していることを確認します。

curl <ELASTIC_AGENT_HOSTNAME>:8200

Elastic APM Agentでサンプルコードをインストルメント化する

各言語版のエージェントの使用方法はプログラミング言語によって異なりますが、大まかなフローはほぼ共通です。初めに各言語のネイティブ仕様でエージェントの依存関係を追加し、次にエージェントの設定でAPM統合へのアクセス方法を指定します。

任意のバージョンを試していただいてかまいませんが、ここでは私が作成したPythonサンプルを使用して、Python用の手順について説明します。

サンプルコードを取得する(または独自のコードを使用する)

GitHubリポジトリをクローンしてから、クローン先のディレクトリに移動します。

git clone https://github.com/davidgeorgehope/PythonElasticAPMExample
cd PythonElasticAPMExample

依存関係を追加する方法

Elastic APMの依存関係を追加する手順はシンプルです。クローンしたGitHubリポジトリのapp.pyファイルで、以下の部分のコードを参照してください。

import elasticapm
from elasticapm import Client

app = Flask(__name__)
app.config["ELASTIC_APM"] = { "SERVICE_NAME": os.environ.get("APM_SERVICE_NAME", "flask-app"), "SECRET_TOKEN": os.environ.get("APM_SECRET_TOKEN", ""), "SERVER_URL": os.environ.get("APM_SERVER_URL", "http://localhost:8200"),}
elasticapm.instrumentation.control.instrument()
client = Client(app.config["ELASTIC_APM"])

PythonのFlask用ライブラリにはトランザクションの自動検出機能が用意されていますが、以下のようにコード内でトランザクションを開始することも可能です。今回のサンプルでは、後者の方法を採用しています。

@app.route("/")
def hello():
client.begin_transaction('demo-transaction')
client.end_transaction('demo-transaction', 'success')

エージェントを設定する

エージェントからAPM統合にアプリケーションのトレースデータを送信する必要があります。そのためには、エージェントがアクセス可能でなければなりません。今回は、サブネット内からElastic Agentにデータを送信できるように、ローカルホストのIPアドレスをリッスンするようにエージェントを設定しました。以下のコードに示すとおり、docker-compose.ymlを使用し、環境変数により設定を指定しています。各変数は、お使いのElastic環境にあわせて変更してください。

# docker-compose.yml
version: "3.9"
services:
flask_app:
build: .
ports:
- "5001:5001"
environment:
- PORT=5001
- APM_SERVICE_NAME=flask-app
- APM_SECRET_TOKEN=your_secret_token
- APM_SERVER_URL=http://host.docker.internal:8200

上記コードに関する補足は以下のとおりです。

  • APM_SERVICE_NAME:省略した場合はデフォルトでアプリケーション名が設定されます。値を指定するとデフォルト値が上書きされます。
  • APM_SECRET_TOKEN:シークレットトークンを使用すると、APMサーバーに対するリクエストを認証できます。ただし、そのためには、APMサーバーにSSL/TLSを設定し、シークレットトークンを用意する必要があります。今回、エージェントとAPMサーバーとの間の通信にはHTTPSを使用しないため、これはコメントアウトします。
  • APM_SERVER_URL:ここで、Elastic Agent内のAPM統合にエージェントがアクセスする方法を指定します。Elastic Agentが実行されているホストの名前またはIPアドレスに置き換えてください。

これで、Elastic APM側の設定が完了したので、READMEの手順に従い起動してみましょう。

docker-compose up --build -d

ビルドステップには数分かかります。

http://localhost:5001にアクセスして、実行中のサンプルアプリケーションを確認してください。このサンプルはシンプルなものですが、それでもAPMデータは生成されています。負荷に関する情報を生成するために、アプリケーションを数回再読み込みするか、以下の簡単なスクリプトを実行します。

#!/bin/bash
# load_test.sh
url="http://localhost:5001"
for i in {1..1000}
do
curl -s -o /dev/null $url
sleep 1
done

上記のスクリプトは、1秒ごとにページの再読み込みを行います。

Kibanaに戻り、APMアプリを開くと(ハンバーガー型のアイコンを選択してから[APM]を選択)、新しくflask-appサービスが表示されます(下図で履歴が表示されるように、サービスをしばらく実行しました)。

サービス概要ページでは、サービスの状態の概要を集約して確認できます。このページは、開発者やSREのみなさんが以下のような質問の答えを探すうえで役立つでしょう。 

  • 新しいデプロイが、パフォーマンスにどのような影響を与えたか
  • 最も影響を受けたトランザクションはどれか
  • パフォーマンスは、基盤のインフラとどのような相関関係にあるか

このビューには、指定期間(下図の場合は過去15分)においてElastic APMにアプリケーショントレースデータを送信したアプリケーションの一覧が表示されます。また、スパークラインにレイテンシー、スループット、エラー率に関する各ミニグラフも表示されます。[flask-app]をクリックすると[Service Overview](サービス概要)ページが開き、サービス内の各種トランザクションが表示されます([Transactions](トランザクション)セクションに示されているように、今回のスクリプトでは/エンドポイントにアクセスしています)。また、レイテンシースループットエラーエラー率について、先ほどよりも大きなグラフも表示されます。

実際に負荷が発生している状況で本物のアプリケーションをインストルメント化した場合には、もっと多くの接続情報(とエラー)が表示されるでしょう。

[Transactions](トランザクション)ビューのトランザクション(今回はサンプルアプリケーションのdemo-transactionトランザクション)をクリックすると、呼び出された処理を確認できます。

この画面には、データベースクエリなど、外部サービスの呼び出しに関する詳細情報も表示されます。

次のステップへ

これで、Elasticオブザーバビリティのクラスタを立ち上げ、デフォルトのアプリケーショントレースデータを収集できるようになりました。次は、お使いのアプリケーションの言語に対応したパブリックAPIを使用して、幅広いAPMデータを集めてみましょう。こうしたAPIでは、カスタムメタデータの追加や業務トランザクションの定義、カスタムスパンの作成なども行えます。各APMエージェント(JavaRubyPythonなど)のパブリックAPIの仕様については、APMエージェントのドキュメントページを参照してください。 

Elastic APMのついてさらに詳しく知りたい方は、クラウドネイティブへの移行におけるElastic APMの効果についてのウェビナーで、エコシステムにとってのElastic APMの他のメリットをご覧ください。

オブザーバビリティクラスターをマネージドサービスとして運用する場合は、Elastic CloudのElasticsearch Serviceの無料トライアルに登録し、エージェントの参照先を新しいクラスターに変更してください。

2021年5月5日初稿公開、2023年4月6日更新。