はじめに:その障害、全ユーザーの問題?それとも「ある一社」の問題?
マルチテナントSaaSを運用するエンジニアにとって、深夜のアラートほど心臓に悪いものはありません。そして、そのアラートが示す問題が、プラットフォーム全体の障害なのか、それとも特定の「一社」のテナントだけに起きている問題なのかを切り分ける作業は、まさに「干し草の山から針を探す」ような困難を伴います。
従来の監視手法では、この切り分けは困難でした。しかし、現代のオブザーバビリティ(可観測性)プラクティスは、この悪夢を終わらせるための明確な答えを持っています。それは、オブザーバビリティの三本柱(ログ、メトリクス、トレース)のすべてに、「テナントコンテキスト(tenantId)」を一貫して注入することです。
この記事では、AWSの主要な監視サービスであるCloudWatchとX-Rayを使い、複雑なマルチテナント環境をテナント単位で完全に可視化し、問題を瞬時に特定するための具体的な実装テクニックを徹底解説します。
【ログ】CloudWatch Logs Insights:特定のテナントのエラーだけを瞬時に抽出する
SaaSのトラブルシューティングにおいて、特定のテナントに関連するログだけを効率的に見つけ出す能力は不可欠です。
大原則:ログは必ずJSON形式で出力し、全ログにtenantId
を含める
まず、全てのLambda関数やコンテナから出力されるログを、以下のような構造化されたJSON形式に統一します。そして、リクエストの処理開始時に取得したtenantId
を、すべてのログに含めることを徹底します。
{
"level": "ERROR",
"tenantId": "tenant-a-12345",
"userId": "user-xyz-789",
"requestId": "d8f3a2c1-4b5a-4b1f-8a2e-1b9c8f2a1b9c",
"module": "PaymentService",
"message": "Credit card processing failed: Insufficient funds"
}
実践クエリ
この構造化ログを前提とすれば、CloudWatch Logs Insightsを使って、驚くほど簡単かつ強力な分析が可能になります。
1. 特定テナントのエラーログを抽出
fields @timestamp, message, tenantId
| filter level = "ERROR" and tenantId = "tenant-a-12345"
| sort @timestamp desc
| limit 50
2. テナントごとのエラー発生件数を集計
stats count(*) as errorCount by tenantId, bin(1h) as hour
| filter level = "ERROR"
| sort hour desc, errorCount desc
【メトリクス】CloudWatchカスタムメトリクス:テナントを「ディメンション」で切り分ける
システム全体の平均パフォーマンスを見るだけでは、SaaSの運用はできません。特定のテナントだけに発生している性能劣化を検知する必要があります。
核心:TenantId
を「ディメンション」として発行する
CloudWatchカスタムメトリクスを発行する際、TenantId
をディメンションとして追加します。これにより、同じメトリクス名(例: ApiLatency
)を、テナントごとに切り分けてグラフ化したり、アラームを設定したりできるようになります。
実装例(Python Boto3):
cloudwatch.put_metric_data(
MetricData=[
{
'MetricName': 'ApiLatency',
'Dimensions': [
{
'Name': 'TenantId',
'Value': 'tenant-a-12345'
},
{
'Name': 'ApiEndpoint',
'Value': '/v1/invoices'
}
],
'Unit': 'Milliseconds',
'Value': 250.5
},
],
Namespace='MySaaSApplication'
)
応用:「うるさい隣人」の特定
CloudWatch Contributor Insightsを使えば、ログデータを分析し、リクエスト数、エラー数、レイテンシーなどのメトリクスに最も寄与している(=影響を与えている)テナントを自動で特定できます。これにより、「うるさい隣人」問題をプロアクティブに検知し、対策を講じることが可能になります。
【トレース】AWS X-Ray:「アノテーション」でテナントのリクエストを追跡する
マイクロサービスアーキテクチャでは、一つのリクエストが複数のサービスを横断します。特定テナントのリクエストが、どのサービスで、なぜ遅延しているのかを追跡するのは非常に困難です。
核心:tenant_id
を「アノテーション」として記録する
AWS X-Rayには、トレースに情報を付加する方法として「アノテーション」と「メタデータ」の2種類がありますが、必ずアノテーションを使います。
- アノテーション: インデックス化され、検索・フィルタリングが可能。
- メタデータ: インデックス化されず、検索できない。(デバッグ用の詳細情報などを格納する)
実装例(Python X-Ray SDK):
from aws_xray_sdk.core import xray_recorder
xray_recorder.put_annotation('tenantId', 'tenant-a-12345')
効果
X-Rayコンソールのフィルタ式に annotation.tenantId = "tenant-a-12345"
と入力するだけで、そのテナントに関連するリクエストのトレースだけが表示されます。API GatewayからLambda、DynamoDBへと、リクエストがどのサービスでどれだけ時間を要したかを一気通貫で可視化し、ボトルネックを瞬時に特定できます。
まとめ:テナントコンテキストが、SaaS運用の常識を変える
マルチテナントSaaSのオブザーバビリティ戦略は、突き詰めれば非常にシンプルです。
「すべてのログ、メトリクス、トレースに、tenantId
という共通のコンテキストを付与する」
この原則を徹底するだけで、これまで「干し草の山」だった監視データは、「テナント」という軸で整理された宝の山に変わります。そして、それは迅速な障害対応、プロアクティブな性能改善、さらにはテナントごとの利用状況に基づいたビジネス判断までも可能にする、強力な武器となるのです。
コメント