APMベストプラクティス:実践者向けの行うべきことと回避すべきこと

アプリケーションパフォーマンス管理(APM)は、ソフトウェアアプリケーションのパフォーマンスと可用性を定期的に追跡、測定、分析する方法です。APMは、サイト信頼性エンジニアリング(SRE)チームを圧倒する可能性のある複雑なマイクロサービス環境を可視化するのに役立ちます。生成された洞察は、最適なユーザーエクスペリエンスを生み出し、望ましいビジネス成果を達成します。これは複雑なプロセスですが、目標は単純で、アプリケーションがスムーズに動作し、ユーザーや企業の期待に応えられるようにすることです。
アプリケーションの動作を明確に理解し、プロアクティブなAPMを実践することが、高性能なソフトウェアアプリケーションを保守するために不可欠です。APMは後で考慮するものではなく、最初から考慮すべきです。積極的に実装することで、監視コンポーネントをアプリケーションに直接組み込むことにより、ソフトウェアの実行方法に組み込むことができます。
アプリケーションパフォーマンス管理とは?
アプリケーションパフォーマンス管理は、アプリケーションのバックエンドとフロントエンドのパフォーマンスを継続的に監視、分析、管理することを含みます。アプリケーション監視は拡大し進化していますが、APM戦略はサイロ化されるべきではありません。複数のステークホルダー、ビジネスエキスパート、アプリケーション開発者、運用チームを巻き込むことが不可欠です。成功するAPM戦略は、アップタイムやサーバーの健全性を超えて、サービスレベル目標(SLO)に焦点を当て、ユーザーに問題が発生する前に対処します。
最新のAPMの実装では、アプリケーションを計測して、次の3種類のテレメトリーデータを収集します。トレース(リクエストフロー)、メトリクス(集計された測定値)、およびログ(個別のイベント)。課題は単にデータを収集することではなく、パフォーマンスに影響を与えずに適切なデータを収集することです。
オブザーバビリティメトリクスについて。
インストルメンテーションにはさまざまなアプローチがありますが、最も効果的な戦略は、自動インストルメンテーション(フレームワークとライブラリ用)と手動インストルメンテーション(ビジネスロジック用)を組み合わせることです。OpenTelemetryエージェントを使用した自動インストルメンテーションにより、最小限のコード変更でオブザーバビリティのニーズの80%をカバーできます。
# Auto-instrumentation handles this automatically
@app.route('/api/orders')
def create_order():
# Add manual span only for critical business logic
with tracer.start_as_current_span("order.validation") as span:
span.set_attribute("order.value", order_total)
if not validate_order(order_data):
span.set_status(Status(StatusCode.ERROR))
return 400行うべきこと:まず自動インストルメンテーションを使用し、その後、ビジネスクリティカルな操作のために手動スパンを追加します。
回避すべきこと:すべての関数呼び出しを手動でインストルメント化すると、パフォーマンスのオーバーヘッドとノイズが発生します。
落とし穴:過剰なインストルメンテーションは15%–20%のレイテンシを増加させる可能性があります。ベースラインパフォーマンス比較で監視を行ってください。
組織や企業がAPM戦略を策定する際、考慮すべき要素は次のとおりです。
レイテンシ、サービスレベル目標、応答時間、スループット、リクエスト量の評価などのパフォーマンス監視
例外、クラッシュ、失敗したAPI呼び出しなどのエラー追跡
アプリケーションをサポートするサーバー、コンテナ、クラウド環境の健全性とリソース使用率などのインフラストラクチャ監視
- 読み込み時間、セッションパフォーマンス、クリックパス、およびブラウザーまたはデバイスの詳細(システムメトリクスが適切に見えても、ユーザーがパフォーマンスの問題に遭遇する可能性があると留意することが重要です)などのユーザーエクスペリエンスメトリクス
効果的なAPMの主要原則
効果的なアプリケーションパフォーマンス管理の主要原則は、エンドツーエンドの可視性(ユーザーのブラウザからデータベースまで)、リアルタイムの監視と洞察、そしてユーザーとビジネス目標に重点を置いたコンテキストに基づく洞察です。APMは、継続的な改善とパフォーマンスの向上を実現することで、アプリケーションの拡張性を向上させます。
行うべきこと:任意のしきい値ではなく、SLOベースのアラートを備えたリアルタイムダッシュボードを実装します。
回避すべきこと:定期的なパフォーマンスレビューやCPU/メモリアラートのみに頼らず、ユーザー・エクスペリエンスメトリクスを計測してください。
落とし穴:低レベルのシステムメトリクスによるアラート疲労。実際の問題を示すユーザー向けのSLOに焦点を当てましょう。
APM戦略を作成する際に考慮すべき主要原則をいくつかご紹介します。
1. プロアクティブな監視: アラートを設定し、異常に迅速に対応することで、ユーザーに影響が及ぶ前に問題を防御します。ただし、アラート疲労は避けてください。自動アラートと人間による監視のバランスを取り、重要な問題を見逃さないようにし、システムメトリクスではなく結果に焦点を当ててください。
2. リアルタイムの洞察:ログの問題を超えて、ライブデータとリアルタイムダッシュボードに基づいて迅速な意思決定を可能にし、最も重要なビジネストランザクションを優先します。テレメトリーデータ(ログ、メトリクス、トレース)を使用して、パフォーマンス洞察を解析します。
3. エンドツーエンドの可視性:フロントエンドからバックエンドまで、環境全体、ユーザーフロー全体、すべてのレイヤーにわたってアプリケーションを監視します。
4. ユーザー中心のアプローチ:エンドユーザーの視点からパフォーマンスとエクスペリエンスを優先しつつ、主要なビジネス目標を考慮します。
5. リアルユーザー監視:ユーザーの手に渡ったからといって、作業が終わるわけではありません。ユーザーエクスペリエンスを監視することで、フィードバックに基づいて改善を繰り返すことができます。
6. 継続的な改善:洞察を使用して時間をかけて最適化し、報告されていない問題を定期的に発見して対処します。定期的なパフォーマンスレビューで問題を発見するのではなく、問題を動的に対処する必要があります。
7. コンテキストの伝達:トレースコンテキストがリクエストパス全体、特にサービスの境界を越えて流れるようにします。
# Outgoing request - inject context
headers = {}
propagate.inject(headers)
response = requests.post('http://service-b/process', headers=headers)
8. サンプリング戦略:インテリジェントなサンプリングを使用して、可視性とパフォーマンスのバランスを取ります。
1%–10%の高トラフィックサービス向けのヘッドベースサンプリング
テールベースのサンプリングを使用したエラーと遅いリクエストの100%サンプリング
計測オーバーヘッドを監視し、パフォーマンスへの影響を5%未満に抑えることを目指します
APM実装のベストプラクティス
適切なAPMソリューションは、最小限のインストルメンテーション作業で技術スタックをサポートする必要があります。OpenTelemetryは、ベンダーに依存しないインストルメンテーションを提供し、言語を超えて機能する業界標準となっています。
@RestController
public class OrderController {
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
// Auto-instrumentation captures this endpoint automatically
// Add custom business context
Span.current().setAttributes(Attributes.of(
stringKey("order.value"), String.valueOf(request.getTotal()),
stringKey("user.tier"), request.getUserTier()
));
return ResponseEntity.ok(processOrder(request));
}
}行うべきこと:サンプリング戦略を実装し、本番環境での計測オーバーヘッドを監視します。
回避すべきこと:トラフィック量の多いサービスに100%のサンプリングを使用すると、パフォーマンスに影響を与え、ストレージコストが急増します。
落とし穴:ヘッドベースのサンプリングでは、重大なエラートレースを見逃す可能性があります。テールベースのサンプリングを使用して、ボリュームを減らしながらすべてのエラーをキャプチャしてください。
正しく行う方法は次のとおりです。
# Good - bounded cardinality
span.set_attribute("user.tier", user.subscription_tier) # 3-5 values
span.set_attribute("http.status_code", response.status_code) # ~10 values
# Bad - unbounded cardinality
span.set_attribute("user.id", user.id) # Millions of values
span.set_attribute("request.timestamp", now()) # Infinite values
- 任意のしきい値ではなく、SLOに基づいてインテリジェントなアラートを設定します。エラーバジェットを活かし、、誰かにページングするタイミングを決定します。
slos:
- name: checkout_availability
target: 99.9%
window: 7d
- name: checkout_latency
target: 95% # 95% of requests under 500ms
window: 7d
チームを訓練し、協力を促進します。APM戦略は、開発者だけでなく、幅広いステークホルダーに影響を与えます。ITチームやその他のビジネスステークホルダーを部門横断的なコラボレーションに参加させるようにします。APMを組織体制に導入することで、協力を強化しましょう。ビジネスニーズに合致し、ユーザーエクスペリエンスを考慮した明確な目標とKPIを設定することが重要です。
- レビューして評価します。APM戦略は、アプリケーションおよびビジネスのニーズに応じて進化し、変化し続けます。
APMにおけるモニタリング戦略
アプリケーションパフォーマンス管理戦略を成功させるための重要な側面は、さまざまな監視アプローチをいつ、どのように活用するかを検討することです。ユーザーエクスペリエンスやインフラストラクチャなど、アプリケーションのさまざまなコンポーネントでは、問題を効果的に検出して解決するためにカスタマイズされたアプローチが必要になるため、監視戦略の組み合わせを検討することが重要です。多様な戦略により、包括的なカバレッジ、より迅速な分析、中断のないアプリケーションパフォーマンス、エンドユーザーの満足度が保証されます。
考慮すべきさまざまな監視アプローチがあります。
- リアルタイム監視:ライブシステムのパフォーマンスをサブセカンドの粒度で継続的に追跡します。ビジネスロジックのカスタムメトリクスを技術的なメトリクスと共に実装します。
order_processing_duration = Histogram(
"order_processing_seconds",
"Time to process orders",
["payment_method", "order_size"]
)
with order_processing_duration.labels(
payment_method=payment.method,
order_size=get_size_bucket(order.total)
).time():
process_order(order)
- シンセティック監視:ユーザーのインタラクションをシミュレートして、実際のユーザーに影響が出る前に問題を検出します。外部依存関係にとって重要です。
// Synthetic check for critical user flow
const syntheticCheck = async () => {
const span = tracer.startSpan('synthetic.checkout_flow');
try {
await loginUser();
await addItemToCart();
await completePurchase();
span.setStatus({code: SpanStatusCode.OK});
} catch (error) {
span.recordException(error);
span.setStatus({code: SpanStatusCode.ERROR});
throw error;
} finally {
span.end();
}
};
詳細な診断とプロファイリング:複雑なパフォーマンスのボトルネック、例えばサードパーティのプラグインやツールのトラブルシューティングに役立ちます。アプリケーションプロファイリングを通じて、データをより深く掘り下げ、その機能に応じてデータのパフォーマンスを分析できます。
- 分散トレーシング:マイクロサービスアーキテクチャには不可欠です。非同期境界を越えてコンテキストの伝播を注意深く処理します。
# Event-driven systems - propagate context through messages
def publish_order_event(order_data):
headers = {}
propagate.inject(headers)
message = {
'data': order_data,
'trace_headers': headers # Preserve trace context
}
kafka_producer.send('order-events', message)
APMデータ分析と洞察
データの監視と収集は始まりに過ぎません。企業は、チューニングや意思決定のために、アプリケーションパフォーマンス管理データをどのように解釈するかを理解する必要があります。
傾向とパターンを特定することで、チームは問題を積極的に検出できます。相関分析を使用して、ユーザーの苦情とバックエンドのパフォーマンスを関連付けます。こちらのES|QL(Elasticのクエリ言語)を使用した例をご覧ください。
FROM traces-apm*
| WHERE user.id == "user_12345"
AND @timestamp >= "2024-06-06T09:00:00"
AND @timestamp <= "2024-06-06T10:00:00"
| EVAL duration_ms = transaction.duration.us / 1000
| KEEP trace.id, duration_ms, transaction.name, service.name, transaction.result
| WHERE duration_ms > 2000
| SORT duration_ms DESC
| LIMIT 10
ボトルネックの検出:APMは、以下のコードに見られるn+1問題などの一般的なパフォーマンスのアンチパターンを明らかにします。APMを使用してコードを最適化します。
# N+1 query problem detected by APM
def get_user_orders_slow(user_id):
user = User.query.get(user_id)
orders = []
for order_id in user.order_ids: # Each iteration = 1 DB query
orders.append(Order.query.get(order_id))
return orders
# Optimized after APM analysis
def get_user_orders_fast(user_id):
return Order.query.filter(Order.user_id == user_id).all() # Single query
メトリクスを相関させ、ユーザーの苦情をバックエンドのパフォーマンスデータ(履歴データを含む)とリンクさせることにより、システムのさまざまな部分がどのように相互作用しているかが明らかになります。これにより、チームは根本原因を正確に診断し、パフォーマンスの問題の影響を完全に理解できるようになります。
根本原因分析を自動化し、AIOpsのようなAI/機械学習ベースのツールを使用することで、問題の原因を特定し、ダウンタイムを短縮し、リソースを解放し、診断と解決を加速します。
将来の意思決定に役立てるためには、データの全体像を把握することが重要です。データが多ければ多いほど、その活用度もより高くなります。
行うべきこと:分散トレーシングを使用して、速度低下を引き起こしている特定のサービスと操作を特定します。
回避すべきこと:相関関係が因果関係を意味するとは限りません。コードレベルのプロファイリングデータで検証してください。
落とし穴:レガシーシステムは、トレースにブラックボックスとして表示されることがよくあります。可視性を保つために、ログの相関と合成スパンを使用してください。
高度な実装パターン
複雑な本番環境には、高度な実装戦略を必要とする特有の課題が伴います。このセクションでは、多言語アーキテクチャ、レガシーシステム統合、そして高度な相関分析への対応に関する実践的なアプローチを解説します。
多言語環境におけるコンテキスト伝播:異なる言語やフレームワーク間でトレースコンテキストを維持するには、伝播メカニズムに明確な注意を払う必要があります。
// Java - Auto-propagation with Spring Cloud
@PostMapping("/orders")
public ResponseEntity<Order> createOrder(@RequestBody OrderRequest request) {
Span.current().setAttributes(Attributes.of(
stringKey("order.type"), request.getOrderType(),
longKey("order.value"), request.getTotalValue()));
// OpenFeign automatically propagates context to downstream services
return paymentClient.processPayment(request.getPaymentData());}
// Go - Manual context extraction and propagation
func processHandler(w http.ResponseWriter, r *http.Request) {
ctx := otel.GetTextMapPropagator().Extract(r.Context(),
propagation.HeaderCarrier(r.Header))
ctx, span := tracer.Start(ctx, "process_payment")
defer span.End()
// Continue with trace context maintained}レガシーシステム統合:直接計測できないシステム用のオブザーバビリティブリッジを作成します。
# Synthetic spans with correlation IDs for mainframe calls
with tracer.start_as_current_span("mainframe.account_lookup") as span:
correlation_id = format(span.get_span_context().trace_id, '032x')
logger.info("CICS call started", extra={
"correlation_id": correlation_id,
"trace_id": span.get_span_context().trace_id
})
result = call_mainframe_service(account_data, correlation_id)
span.set_attribute("account.status", result.status)
ES|QLによる高度なトレース分析:ユーザーの苦情をバックエンドのパフォーマンスにリンクするためにElasticのクエリ言語を使用します。
-- Find slow requests during complaint timeframe
FROM traces-apm*
| WHERE user.id == "user_12345" AND @timestamp >= "2024-06-06T09:00:00"
| EVAL duration_ms = transaction.duration.us / 1000
| WHERE duration_ms > 2000
| STATS avg_duration = AVG(duration_ms) BY service.name, transaction.name
| SORT avg_duration DESC
-- Correlate errors across service boundaries
FROM traces-apm*
| WHERE trace.id == "44b3c2c06e15d444a770b87daab45c0a"
| EVAL is_error = CASE(transaction.result == "error", 1, 0)
| STATS error_rate = SUM(is_error) / COUNT(*) * 100 BY service.name
| WHERE error_rate > 0
イベント駆動型アーキテクチャパターン:非同期処理のためにメッセージヘッダーを通じてコンテキストを明示的に伝播します。
# Producer - inject context into message
headers = {}
propagate.inject(headers)
message = {
'data': order_data,
'trace_headers': headers # Preserve trace context
}
await kafka_producer.send('order-events', message)
# Consumer - extract and continue trace
trace_headers = message.get('trace_headers', {})
context = propagate.extract(trace_headers)
with tracer.start_as_current_span("order.process", context=context):
await process_order(message['data'])
行うべきこと:従来のダッシュボードでは処理できない複雑なトレース分析にはES|QLを使用します。
回避すべきこと:レガシーシステムを直接計測しないでください。相関IDと合成スパンを使用します。
落とし穴:メッセージキューと非同期処理は、ヘッダーを介して明示的に伝播されない限り、トレースコンテキストを破壊します。
- 重要な洞察:完璧なインストルメンテーションが常に可能とは限りません。相関ID、合成スパン、インテリジェントクエリを戦略的に使用することで、複雑なハイブリッド環境でも包括的なオブザーバビリティを提供します。
Elasticオブザーバビリティを使用したパフォーマンス最適化のためのAPM
Elasticオブザーバビリティは、アプリケーションパフォーマンス管理戦略のシームレスな実装を可能にします。これは、アプリケーションパフォーマンスデータをログ、メトリクス、トレースと共に単一の強力なプラットフォームで統合することにより、統合オブザーバビリティを提供するからです。OpenTelemetryのElasticディストリビューション(EDOT)を使用してデータを収集することで、APMデータの収集を迅速かつ簡単に開始できます。
開発者は異常に関するアラートを設定し、分散トレーシングを使用して特定のサービスやトランザクションを最適化し、レイテンシを削減し、負荷分散とキャッシュを通じてElasticを使用してパフォーマンスの安定性を向上させることができます。
コードプロファイリングを通じて、チームはパフォーマンスのホットスポット、非効率的なコードパス、メモリリーク、またはアプリケーションの速度を低下させるリソース集約型の操作を特定できます。企業はカスタムダッシュボードを作成してKPIを追跡し、最終的にはビジネス成果の向上をサポートできます。
より技術的なオブザーバビリティコンテンツについては、Elastic Observability Labsをご覧ください。
APM参考資料
本記事に記述されているあらゆる機能ないし性能のリリースおよびタイミングは、Elasticの単独裁量に委ねられます。現時点で提供されていないあらゆる機能ないし性能は、すみやかに提供されない可能性、または一切の提供が行われない可能性があります。