本章では、VB.NET業務システムを本番環境で安定運用するために必要な、 可観測性、監視、ログ設計、メトリクス、トレース、障害解析、SREの考え方を学習します。
Chapter 17では、複数システムを連携させるエンタープライズ統合設計を扱いました。 しかし、システムが分散すると、障害発生時に「どこで」「なぜ」「どの処理が」失敗したのかを把握することが難しくなります。
単体アプリケーションであれば、エラーログを見れば原因が分かることもあります。 しかし、API、DB、Queue、外部サービス、バッチ、クラウド基盤が絡む環境では、 ログだけでは全体像を追いきれません。
そのため、現代の業務システムでは、Logging、Metrics、Tracingを組み合わせて、 システム内部の状態を外部から理解できるようにする「可観測性」が重要になります。
本章のゴールは、VB.NET業務システムにおいて、障害発生後に原因を追跡できるだけでなく、 障害の予兆を検知し、運用品質を数値で管理し、継続的に改善できるSRE的な運用設計を身につけることです。
1. 可観測性とは
可観測性とは、システムの外部から取得できる情報をもとに、 内部で何が起きているかを理解できる状態を指します。
業務システムでは、単に「エラーが出た」だけでは不十分です。 どのユーザーが、どの画面で、どの処理を行い、どのDBアクセスで失敗し、 どの外部API呼び出しが遅かったのかまで追跡できる必要があります。
可観測性の3本柱
| 要素 | 役割 | 例 |
|---|---|---|
| Logs | 何が起きたかを記録する | エラーログ、業務ログ、監査ログ |
| Metrics | 状態を数値で把握する | 応答時間、エラー率、CPU使用率 |
| Traces | 処理の流れを追跡する | API → DB → 外部API → Queue |
ログだけ、メトリクスだけ、トレースだけでは不十分です。 それぞれを組み合わせることで、本番環境の状態を立体的に把握できます。
2. MonitoringとObservabilityの違い
MonitoringとObservabilityは似ていますが、考え方が少し異なります。
| 項目 | Monitoring | Observability |
|---|---|---|
| 目的 | 既知の異常を検知する | 未知の問題を調査できる |
| 主な対象 | CPU、メモリ、死活監視 | 処理全体、依存関係、遅延原因 |
| 問い | 正常か異常か | なぜ異常なのか |
| 利用場面 | アラート検知 | 障害解析、性能分析、改善 |
Monitoringは「異常を知る」ために必要です。 Observabilityは「異常の理由を理解する」ために必要です。
実務では、まず監視によって問題を検知し、 その後、ログ、メトリクス、トレースを使って原因を掘り下げます。
3. ログ設計の基本
ログは、障害調査と運用改善の最も基本的な情報源です。 しかし、ログをただ大量に出せばよいわけではありません。
悪いログの例
エラーが発生しました。
このログだけでは、どの処理で、どのデータを処理中に、なぜ失敗したのか分かりません。
良いログの例
Level=ERROR
Event=OrderRegisterFailed
CorrelationId=9d9228e2-8ef4-4e34-baa7-7adfd6dcb234
UserId=1024
OrderId=55891
Message=注文登録に失敗しました。
Exception=SqlException
ErrorCode=1205
良いログには、障害調査に必要な文脈情報が含まれています。
ログに含めるべき情報
- 日時
- ログレベル
- イベント名
- Correlation ID
- User ID
- 処理対象ID
- 画面名またはAPI名
- 処理結果
- 例外情報
- 処理時間
ログは、未来の自分や運用担当者に向けた調査資料です。 「そのログだけで原因調査を始められるか」を意識して設計します。
4. ログレベル設計
ログには重要度に応じたレベルを設定します。 ログレベルを適切に使い分けることで、調査時に必要な情報を見つけやすくなります。
| レベル | 用途 | 例 |
|---|---|---|
| Trace | 非常に詳細な処理追跡 | メソッド単位の細かい流れ |
| Debug | 開発・検証用の情報 | 変数値、分岐情報 |
| Information | 正常な業務イベント | 注文登録完了、バッチ開始 |
| Warning | 異常の可能性がある状態 | リトライ発生、処理遅延 |
| Error | 処理失敗 | DB更新失敗、API呼び出し失敗 |
| Critical | システム継続に重大な影響 | DB接続不可、基幹処理停止 |
ログレベルの使い分け例
Logger.Info("注文登録を開始しました。OrderId=55891")
Logger.Warn("在庫API呼び出しでリトライが発生しました。OrderId=55891 RetryCount=2")
Logger.Error("注文登録に失敗しました。OrderId=55891", ex)
Logger.Critical("DB接続が全系で失敗しました。", ex)
すべてをErrorにすると、本当に重要な障害が埋もれます。 逆に、重要な異常をInformationで出してしまうと検知できません。
5. 構造化ログ
構造化ログとは、ログを単なる文字列ではなく、検索・集計しやすい項目として記録する方法です。
非構造化ログ
注文登録に失敗しました。OrderId=55891 UserId=1024
構造化ログ
{
"level": "Error",
"event": "OrderRegisterFailed",
"orderId": 55891,
"userId": 1024,
"correlationId": "9d9228e2-8ef4-4e34-baa7-7adfd6dcb234"
}
構造化ログにすると、OrderId、UserId、CorrelationId、Eventなどで検索・集計できます。
VB.NETでログ情報を組み立てる例
Public Class LogContext
Public Property CorrelationId As String
Public Property UserId As Integer?
Public Property ScreenName As String
Public Property ActionName As String
End Class
Public Class ApplicationLogger
Public Sub Error(
eventName As String,
message As String,
context As LogContext,
ex As Exception)
Dim logMessage As String =
"Event=" & eventName &
" CorrelationId=" & context.CorrelationId &
" UserId=" & context.UserId.ToString() &
" Screen=" & context.ScreenName &
" Action=" & context.ActionName &
" Message=" & message &
" Exception=" & ex.GetType().Name
' 実際にはSerilog、NLog、log4netなどへ出力する
Console.WriteLine(logMessage)
End Sub
End Class
実務では、Serilog、NLog、log4netなどのロギングライブラリを利用し、 ファイル、DB、ログ基盤、クラウド監視サービスへ出力します。
6. Correlation ID設計
Correlation IDは、複数システムをまたぐ1つの処理を追跡するためのIDです。
Chapter 17でも扱った通り、分散システムでは1つの業務処理が複数のAPI、DB、Queue、外部サービスを通過します。 各システムが同じCorrelation IDをログへ出力することで、全体の流れを追跡できます。
処理の流れ
WinForms
↓ CorrelationId=A
Order API
↓ CorrelationId=A
Stock API
↓ CorrelationId=A
Payment API
↓ CorrelationId=A
Message Queue
↓ CorrelationId=A
Shipping Worker
VB.NETでCorrelation IDを生成する例
Public Class CorrelationContext
Public Property CorrelationId As String
Public Shared Function CreateNew() As CorrelationContext
Return New CorrelationContext With {
.CorrelationId = Guid.NewGuid().ToString()
}
End Function
End Class
HTTPヘッダーへ付与する例
Public Async Function CallStockApiAsync(
orderId As Integer,
correlationId As String) As Task
Dim request =
New HttpRequestMessage(
HttpMethod.Post,
"/api/stocks/reserve")
request.Headers.Add(
"X-Correlation-ID",
correlationId)
request.Content =
New StringContent(
"{ ""orderId"": " & orderId & " }",
Text.Encoding.UTF8,
"application/json")
Dim response =
Await _httpClient.SendAsync(request)
response.EnsureSuccessStatusCode()
End Function
Correlation IDは、APIだけでなく、Queueメッセージ、バッチログ、エラーログにも引き継ぐことが重要です。
7. 監査ログ
監査ログは、システムの操作履歴を記録するためのログです。 障害調査だけでなく、不正操作の検知、内部統制、セキュリティ監査にも利用されます。
監査ログに記録する項目
- 誰が
- いつ
- どの画面またはAPIで
- 何をしたか
- どのデータを変更したか
- 変更前の値
- 変更後の値
- 結果が成功か失敗か
- アクセス元IP
監査ログテーブル例
AuditLogs
AuditLogId
OccurredAt
UserId
ActionName
TargetType
TargetId
BeforeValue
AfterValue
Result
IpAddress
監査ログ出力例
Public Sub WriteAuditLog(
userId As Integer,
actionName As String,
targetType As String,
targetId As String,
beforeValue As String,
afterValue As String)
Dim auditLog As New AuditLog With {
.OccurredAt = DateTime.Now,
.UserId = userId,
.ActionName = actionName,
.TargetType = targetType,
.TargetId = targetId,
.BeforeValue = beforeValue,
.AfterValue = afterValue,
.Result = "Success"
}
_auditLogRepository.Insert(auditLog)
End Sub
監査ログは、通常ログよりも改ざん耐性や保存期間が重要になる場合があります。 業務要件や法令要件に応じて設計します。
8. 個人情報とログ
ログには、個人情報や機密情報を不用意に出力してはいけません。
ログに出してはいけない情報の例
- パスワード
- アクセストークン
- API Key
- クレジットカード番号
- マイナンバー
- 秘密鍵
- 認証Cookie
危険な例
Logger.Info("Login password=" & password)
マスキング例
Public Function MaskEmail(email As String) As String
If String.IsNullOrWhiteSpace(email) Then
Return ""
End If
Dim parts = email.Split("@"c)
If parts.Length <> 2 Then
Return "***"
End If
Return parts(0).Substring(0, 1) &
"***@" &
parts(1)
End Function
ログは障害調査に便利ですが、長期間保存されることも多いため、 情報漏えい時の影響も考えて設計する必要があります。
9. メトリクス設計
メトリクスは、システムの状態を数値として把握するための情報です。
代表的なメトリクス
| 分類 | メトリクス例 |
|---|---|
| システム | CPU使用率、メモリ使用量、ディスク使用量 |
| アプリケーション | リクエスト数、エラー数、処理時間 |
| DB | 接続数、クエリ時間、ロック待ち |
| Queue | 滞留件数、処理件数、失敗件数 |
| 業務 | 注文数、決済成功率、取込件数 |
メトリクスの例
OrderCreatedCount = 1240
OrderFailedCount = 12
AverageResponseTimeMs = 245
QueuePendingCount = 320
BatchElapsedSeconds = 180
ログは個別事象を調べるために有効です。 メトリクスは全体傾向を把握するために有効です。
10. REDメトリクス
APIやサービスの状態を見るときは、REDメトリクスが有効です。
| 項目 | 意味 | 例 |
|---|---|---|
| Rate | リクエスト数 | 1分あたりのAPI呼び出し数 |
| Errors | エラー数・エラー率 | HTTP 500の割合 |
| Duration | 処理時間 | 平均応答時間、95パーセンタイル |
API監視例
Rate:
/api/orders 1200 requests/min
Errors:
/api/orders 0.8%
Duration:
p50 = 120ms
p95 = 450ms
p99 = 1200ms
平均応答時間だけを見ると、遅い一部のリクエストを見逃すことがあります。 そのため、p95やp99などのパーセンタイルを見ることが重要です。
11. USEメトリクス
サーバーやインフラリソースを見るときは、USEメトリクスが有効です。
| 項目 | 意味 | 例 |
|---|---|---|
| Utilization | 使用率 | CPU使用率、ディスク使用率 |
| Saturation | 飽和度 | 待ち行列、Queue滞留、Thread枯渇 |
| Errors | エラー | ディスクI/Oエラー、接続失敗 |
確認例
CPU Utilization = 85%
DB Connection Pool Saturation = High
Disk Errors = 0
Queue Pending Count = 15000
CPU使用率が低くても、DB接続プールが枯渇していればアプリケーションは遅くなります。 単一の数値だけで判断せず、複数の観点から確認します。
12. 分散トレーシング
分散トレーシングは、1つのリクエストが複数システムを通る流れを可視化する仕組みです。
TraceId = A
Order API
Span: ValidateOrder
Span: InsertOrder
Span: CallStockApi
Span: PublishOrderCreated
Stock API
Span: ReserveStock
Span: UpdateStockTable
Payment API
Span: ExecutePayment
Span: CallExternalPaymentGateway
TraceとSpan
| 用語 | 意味 |
|---|---|
| Trace | 1つの処理全体 |
| Span | Trace内の個別処理 |
分散トレーシングで分かること
- どのサービスを通過したか
- どの処理に時間がかかったか
- どのAPIが失敗したか
- DB処理が遅いのか外部APIが遅いのか
- Queue待ち時間が長いのか
ログだけでは点の情報になりやすいですが、 トレースを使うと処理全体の流れを線として追跡できます。
13. OpenTelemetryの考え方
OpenTelemetryは、ログ、メトリクス、トレースなどの観測データを標準的に収集するための仕組みです。
アプリケーションが直接特定の監視サービスに依存するのではなく、 OpenTelemetryを経由することで、監視基盤を変更しやすくなります。
構成イメージ
Application
↓
OpenTelemetry SDK
↓
OpenTelemetry Collector
↓
Monitoring Backend
例:
Application Insights
Prometheus
Grafana
Jaeger
Datadog
Elastic Stack
メリット
- 観測データの形式を標準化できる
- 複数言語・複数サービスで統一しやすい
- 監視基盤を差し替えやすい
- 分散トレーシングを導入しやすい
既存VB.NETシステムでは、最初から完全なOpenTelemetry対応が難しい場合もあります。 その場合でも、Correlation ID、構造化ログ、処理時間計測から始めるだけで、可観測性は大きく向上します。
14. ヘルスチェック
ヘルスチェックは、システムが正常に動作しているかを確認する仕組みです。
ヘルスチェックの種類
| 種類 | 目的 | 確認内容 |
|---|---|---|
| Liveness | プロセスが生きているか | アプリが応答するか |
| Readiness | 処理を受け付けられるか | DB接続、外部依存 |
| Startup | 起動完了したか | 初期化完了、設定読込 |
簡易ヘルスチェック例
Public Class HealthCheckService
Public Function CheckDatabase() As Boolean
Try
Using connection As New SqlClient.SqlConnection(_connectionString)
connection.Open()
Return True
End Using
Catch
Return False
End Try
End Function
End Class
ヘルスチェックで注意すること
- 重い処理を実行しない
- 外部サービス障害をどう扱うか決める
- 一時的な失敗ですぐ異常扱いしない
- 結果を監視システムから確認できるようにする
ヘルスチェックは単なる死活監視ではありません。 アプリケーションが実際に処理を受け付けられる状態かを判断するための仕組みです。
15. アラート設計
監視で異常を検知したら、運用担当者へ通知する必要があります。 しかし、アラートを出しすぎると、重要な通知が埋もれます。
悪いアラート
- 1回の一時エラーですぐ通知する
- 重要度が分からない
- 何をすればよいか分からない
- 毎日大量に発生する
- 放置されても問題ない
良いアラート
- 利用者影響がある
- 対応が必要である
- 原因調査の入口が分かる
- 重要度が明確である
- ノイズが少ない
アラート例
Alert:
Order API Error Rate High
Condition:
HTTP 5xx rate > 5% for 5 minutes
Impact:
注文登録に失敗している可能性があります。
First Action:
DashboardでOrder APIのp95 latencyとDB connection countを確認してください。
アラートには、何が起きたかだけでなく、 最初に何を確認すべきかを含めると対応が早くなります。
16. ダッシュボード設計
ダッシュボードは、システムの現在状態を把握するための画面です。
ただグラフを並べるのではなく、運用判断に必要な情報を整理して表示します。
業務システム向けダッシュボード項目
- 注文数
- エラー率
- 平均応答時間
- p95応答時間
- DB接続数
- Queue滞留件数
- バッチ成功・失敗状況
- 外部API成功率
- Dead Letter Queue件数
ダッシュボード分類
| 種類 | 対象者 | 内容 |
|---|---|---|
| 経営・業務向け | 業務責任者 | 注文数、処理件数、売上件数 |
| 運用向け | 運用担当者 | ジョブ状態、Queue滞留、エラー件数 |
| 開発向け | 開発者 | 例外、遅延、DBクエリ、Trace |
| インフラ向け | インフラ担当者 | CPU、メモリ、ディスク、ネットワーク |
見る人によって必要な情報は異なります。 1つの巨大ダッシュボードにすべてを詰め込むより、目的別に分ける方が実用的です。
17. SLI / SLO / SLA
SREでは、サービス品質を感覚ではなく数値で管理します。 そのためにSLI、SLO、SLAという考え方を利用します。
| 用語 | 意味 | 例 |
|---|---|---|
| SLI | サービス品質を測る指標 | 成功率、応答時間、可用性 |
| SLO | 内部的な品質目標 | 注文API成功率99.9%以上 |
| SLA | 外部との合意・契約 | 月間稼働率99.5%保証 |
SLI例
- 注文APIの成功率
- 注文登録のp95応答時間
- バッチ成功率
- Queue処理遅延時間
- 外部API連携成功率
SLO例
注文登録APIの99.9%は2秒以内に成功する。
夜間売上集計バッチは99%の日で午前6時までに完了する。
在庫連携Queueの95%は5分以内に処理される。
SLOを定義することで、「何となく安定している」ではなく、 どの程度の品質を目指すのかを明確にできます。
18. Error Budget
Error Budgetは、SLOを満たす範囲で許容される失敗量です。
たとえば、月間成功率99.9%をSLOにする場合、 0.1%までは失敗が許容されるという考え方です。
考え方
SLO = 99.9%
許容失敗率 = 0.1%
月間1,000,000リクエストの場合
許容失敗数 = 1,000件
Error Budgetを使うと、機能開発と安定性のバランスを取りやすくなります。
Error Budgetの使い方
- 余裕がある場合はリリースを進める
- 消費が激しい場合は安定化を優先する
- 障害が多い期間は新機能より改善に集中する
- 感覚ではなく数値で判断する
SREでは、安定性を無限に追求するのではなく、 ビジネスに必要な水準を数値で定め、その範囲内で開発速度とのバランスを取ります。
19. インシデント対応
インシデントとは、サービスに影響を与える障害や異常状態のことです。
インシデント対応の流れ
検知
↓
影響範囲確認
↓
一次対応
↓
原因調査
↓
復旧
↓
再発防止
↓
振り返り
初動で確認すること
- 利用者影響はあるか
- いつから発生しているか
- どの機能が影響を受けているか
- 直近のリリースはあるか
- DB、API、Queue、外部サービスのどこで異常があるか
- 回避策はあるか
インシデント管理表の例
| 項目 | 内容 |
|---|---|
| 発生時刻 | 2026/09/30 02:10 |
| 検知方法 | アラート |
| 影響範囲 | 注文登録APIの一部失敗 |
| 原因 | DB接続プール枯渇 |
| 暫定対応 | アプリケーション再起動 |
| 恒久対応 | 接続解放漏れ修正、監視追加 |
インシデント対応では、原因追及よりも先に利用者影響を抑えることが優先される場合があります。 復旧後に冷静に原因分析を行います。
20. ポストモーテム
ポストモーテムは、障害発生後に原因、影響、対応、再発防止策を整理する振り返りです。
重要なのは、個人を責めることではなく、システムやプロセスを改善することです。
ポストモーテム項目
- 概要
- 発生日時
- 検知日時
- 復旧日時
- 影響範囲
- タイムライン
- 原因
- 検知が遅れた理由
- 対応が遅れた理由
- 再発防止策
- 追加する監視
タイムライン例
02:10 注文APIのエラー率上昇
02:12 アラート発報
02:15 担当者確認開始
02:20 DB接続数上限到達を確認
02:25 アプリケーション再起動
02:30 エラー率回復
10:00 原因調査開始
14:00 接続解放漏れを特定
障害対応で得た学びを、監視、設計、テスト、運用手順へ反映することで、 同じ障害を繰り返さない体制を作ります。
21. 障害解析の進め方
障害解析では、いきなりコードを疑うのではなく、事実を集めて仮説を立てます。
確認順序の例
- いつから発生したか
- どの機能で発生したか
- すべてのユーザーか一部のユーザーか
- 直近でリリースや設定変更があったか
- エラー率は上がっているか
- 応答時間は上がっているか
- DB負荷は上がっているか
- Queueは滞留しているか
- 外部APIは正常か
よくある原因
- DB接続リーク
- SQL性能劣化
- デッドロック
- 外部API障害
- 認証情報期限切れ
- ディスク容量不足
- メモリリーク
- Queue滞留
- 設定ミス
- リリース不具合
障害解析では、感覚ではなく観測データに基づいて原因を絞り込みます。
22. パフォーマンスボトルネック分析
性能問題では、どこが遅いのかを分解して確認します。
分解例
注文登録が5秒かかる
内訳:
入力検証 20ms
DB登録 300ms
在庫API 4200ms
ログ出力 10ms
レスポンス生成 30ms
この場合、最適化すべきなのは在庫API呼び出しです。 入力検証を高速化しても全体への影響は小さいです。
計測コード例
Dim sw As New Diagnostics.Stopwatch()
sw.Start()
ValidateOrder(order)
Logger.Info("ValidateOrder elapsed=" & sw.ElapsedMilliseconds & "ms")
sw.Restart()
SaveOrder(order)
Logger.Info("SaveOrder elapsed=" & sw.ElapsedMilliseconds & "ms")
sw.Restart()
Await CallStockApiAsync(order)
Logger.Info("CallStockApi elapsed=" & sw.ElapsedMilliseconds & "ms")
本格的には分散トレーシングで確認しますが、 既存システムではまずStopwatchによる処理時間ログから始めても効果があります。
23. バッチ監視
業務システムでは、APIだけでなくバッチ処理の監視も重要です。
監視すべき項目
- 予定時刻に開始したか
- 予定時間内に終了したか
- 成功したか失敗したか
- 処理件数が異常に少なくないか
- エラー件数が増えていないか
- 前回から処理時間が急増していないか
- 再実行が必要か
バッチ実行管理テーブル
BatchExecutions
ExecutionId
JobName
StartedAt
EndedAt
Status
ProcessedCount
SuccessCount
ErrorCount
ElapsedSeconds
ErrorMessage
バッチ監視アラート例
DailySalesBatchが午前6時までに完了していません。
ImportCustomerBatchのエラー件数が100件を超えました。
InvoiceBatchの処理時間が過去7日平均の2倍を超えました。
バッチはユーザーが直接見ていない時間帯に動くことが多いため、 失敗しても翌朝まで気づかないという状態を避ける必要があります。
24. Queue監視
非同期処理では、Queueの状態を監視することが重要です。
Queue監視項目
- 滞留件数
- 最古メッセージの滞留時間
- Consumer処理速度
- 失敗件数
- Retry件数
- Dead Letter Queue件数
異常例
Queue Pending Count = 50000
Oldest Message Age = 2 hours
Consumer Error Rate = 20%
Queueの件数だけでなく、最古メッセージがどれくらい滞留しているかを見ることが重要です。 件数が少なくても、古いメッセージが残っている場合は特定データで処理が詰まっている可能性があります。
25. DB監視
VB.NET業務システムでは、DBが最も重要な依存先になることが多いです。 そのため、DB監視は必須です。
DB監視項目
- 接続数
- 接続プール枯渇
- 長時間クエリ
- ロック待ち
- デッドロック
- CPU使用率
- ディスクI/O
- インデックス断片化
- トランザクションログ使用量
アプリケーション側で注意すること
Using connection As New SqlClient.SqlConnection(_connectionString)
connection.Open()
Using command As New SqlClient.SqlCommand(sql, connection)
command.ExecuteNonQuery()
End Using
End Using
Usingを使ってConnection、Command、Readerを確実に破棄することは、 DB接続リークを防ぐ基本です。
26. 外部API監視
外部APIを利用するシステムでは、外部APIの状態も監視対象にします。
監視項目
- 成功率
- 応答時間
- Timeout件数
- HTTPステータスコード
- Rate Limit到達回数
- Retry回数
- Circuit Breaker状態
ログ例
Event=ExternalApiCall
ApiName=PaymentGateway
StatusCode=504
ElapsedMs=10000
RetryCount=3
CorrelationId=9d9228e2...
外部API障害時には、自システムの障害なのか相手システムの障害なのかを切り分ける必要があります。 そのため、外部APIごとのメトリクスとログを分けて記録します。
27. Runbook
Runbookは、障害や運用作業が発生したときに、担当者が何をすればよいかをまとめた手順書です。
Runbookに含める内容
- アラート名
- 想定される原因
- 確認すべきダッシュボード
- 確認すべきログ
- 一次対応手順
- エスカレーション先
- やってはいけない対応
- 復旧確認方法
Runbook例
Alert:
QueuePendingCountHigh
Meaning:
注文イベントQueueの滞留件数が閾値を超えています。
Check:
1. Consumerが起動しているか確認
2. Consumer Error Rateを確認
3. Dead Letter Queue件数を確認
4. 外部API障害が発生していないか確認
Action:
1. Consumerログを確認
2. 失敗メッセージの内容を確認
3. 一時障害であればRetry状況を確認
4. 必要に応じてConsumerを追加起動
Escalation:
アプリ担当、インフラ担当
Runbookがないと、障害時に担当者の経験だけに依存します。 属人化を防ぐためにも、よくある障害ごとに手順を整備します。
28. 実務でありがちな失敗
ログが少なすぎる
エラーが発生しても、対象ID、ユーザーID、処理名、Correlation IDが記録されていないため、 原因調査に時間がかかります。
ログが多すぎる
すべての処理で大量のDebugログを出すと、重要なログが埋もれます。 また、ログ容量や費用の問題も発生します。
個人情報をログに出してしまう
パスワード、トークン、カード番号などをログへ出力すると、重大なセキュリティ事故につながります。
平均値だけで判断する
平均応答時間が正常でも、一部のユーザーだけ極端に遅い可能性があります。 p95やp99も確認します。
アラートが多すぎて無視される
毎日大量のアラートが発生すると、担当者が通知に慣れてしまい、本当に重要な障害を見逃します。
障害後に振り返らない
復旧だけで終わると、同じ障害が再発します。 ポストモーテムを行い、監視、設計、テスト、運用手順へ反映します。
監視がインフラだけ
CPUやメモリだけを監視していても、注文失敗率やQueue滞留、バッチ失敗などの業務影響を検知できません。
29. 演習課題
演習1:ログ設計を行う
注文登録処理について、正常時、業務エラー時、システムエラー時に出力すべきログ項目を設計してください。
演習2:Correlation IDを導入する
WinForms、Order API、Stock API、Payment APIを通る処理にCorrelation IDを付与し、 各ログで同じIDを出力する仕組みを設計してください。
演習3:メトリクスを定義する
受注システムに必要な業務メトリクス、アプリケーションメトリクス、インフラメトリクスを分類してください。
演習4:アラートを設計する
注文APIのエラー率、Queue滞留、夜間バッチ失敗、DB接続枯渇について、 それぞれアラート条件と初動対応を設計してください。
演習5:SLOを定義する
注文登録API、請求バッチ、在庫連携Queueについて、 それぞれSLIとSLOを定義してください。
演習6:障害解析を行う
注文登録の応答時間が突然5倍になった想定で、 ログ、メトリクス、トレースを使って原因を切り分ける手順を作成してください。
演習7:Runbookを作成する
Dead Letter Queue件数が急増した場合のRunbookを作成してください。 確認項目、一次対応、エスカレーション、復旧確認を含めてください。
演習8:ポストモーテムを書く
夜間バッチが失敗し、翌朝の請求処理に影響が出たという想定で、 ポストモーテムを作成してください。
30. まとめ
本章では、VB.NET業務システムにおける可観測性、監視、ログ設計、メトリクス、トレース、障害解析、SREの考え方を学習しました。
システムが単体で完結している場合は、エラーログだけで原因を追えることもあります。 しかし、API、Queue、DB、外部サービス、バッチが連携する分散環境では、 ログ、メトリクス、トレースを組み合わせて状態を把握する必要があります。
ログ設計では、単にエラー内容を出力するだけでなく、 Correlation ID、User ID、処理対象ID、イベント名、例外情報、処理時間など、 調査に必要な文脈を含めることが重要です。
構造化ログを利用すると、ログを検索・集計しやすくなります。 また、個人情報や機密情報をログへ出力しないよう、マスキングや出力ルールも設計する必要があります。
メトリクスでは、CPUやメモリだけでなく、 エラー率、応答時間、Queue滞留、バッチ成功率、外部API成功率など、 アプリケーションと業務の状態を数値で確認します。
APIやサービスの状態を見るときはREDメトリクス、 インフラリソースを見るときはUSEメトリクスが有効です。 平均値だけでなく、p95やp99などのパーセンタイルを確認することで、 一部の遅いリクエストも検知しやすくなります。
分散トレーシングを導入すると、1つの処理が複数サービスを通過する流れを追跡できます。 どのAPI、DB、Queue、外部サービスで時間がかかっているのかを把握できるため、 性能問題や障害原因の特定に役立ちます。
アラート設計では、ノイズを減らし、本当に対応が必要な異常を通知することが重要です。 通知には、影響範囲、確認すべき情報、初動対応の手がかりを含めると、復旧時間を短縮できます。
SREの考え方では、SLI、SLO、SLA、Error Budgetを使い、 システムの信頼性を感覚ではなく数値で管理します。 安定性を無限に追求するのではなく、ビジネスに必要な品質水準を定義し、 開発速度と運用品質のバランスを取ります。
障害が発生した場合は、まず利用者影響を抑え、復旧後にポストモーテムを行います。 個人を責めるのではなく、監視、設計、テスト、運用手順を改善し、 同じ障害を繰り返さない仕組みを作ることが重要です。
本章のゴールは、VB.NET業務システムを「動く状態」から「観測でき、改善でき、安定運用できる状態」へ引き上げることです。 可観測性とSREの考え方を身につけることで、障害に強く、運用しやすいエンタープライズシステムを設計できるようになります。