Observability Fundamentals(可觀測性基礎)

是什麼?

Observability(可觀測性) 是指從系統的外部輸出(Logs、Metrics、Traces)來理解系統內部狀態的能力。它不只是「監控」,而是能回答你事先沒有預想到的問題

ℹ️Monitoring vs Observability

Monitoring(監控)回答「系統是否正常」— 預先定義好的指標和告警。Observability(可觀測性)回答「系統為什麼不正常」— 能夠根據輸出追溯任何問題的根因。Observability 包含 Monitoring,但範圍更廣。

核心觀念

三支柱比較

| 支柱 | 資料型態 | 問什麼問題 | 典型工具 | |------|----------|-----------|---------| | Logs | 離散事件文字 | 「發生了什麼?」 | ELK、Loki、CloudWatch | | Metrics | 時間序列數值 | 「趨勢如何?有沒有異常?」 | Prometheus、Datadog、CloudWatch | | Traces | 請求的完整路徑 | 「這個請求經過了哪些服務?慢在哪裡?」 | Jaeger、Zipkin、Tempo |

Logs — 事件紀錄

Metrics — 數值指標

Traces — 分散式追蹤

常見誤區

⚠️常犯錯誤

  • 只有 Logs 沒有 Metrics(無法快速發現趨勢和異常)
  • 只有 Metrics 沒有 Logs(知道有問題但找不到根因)
  • Log 等級全用 INFO(失去了等級區分的意義,無法過濾重要資訊)
  • Trace 取樣率設為 100%(在高流量系統中會產生巨大的儲存和效能負擔)

執行流程

1

定義 SLI/SLO

先定義什麼是「正常」— 延遲、錯誤率、可用性的目標值

2

埋設 Instrumentation

在程式碼中加入 Log、Metrics、Tracing 的埋點

3

收集與儲存

用 Agent/Collector 收集資料,送到對應的儲存後端

4

視覺化

建立 Dashboard 展示關鍵指標和趨勢

5

告警與回應

設定告警規則,異常時自動通知 on-call 人員

流程解讀:可觀測性的建立從定義「正常」開始。SLI(Service Level Indicator)定義量測什麼,SLO(Service Level Objective)定義目標值。有了標準才知道什麼時候該告警。Instrumentation 是在程式碼中埋入「感測器」,收集三種信號。資料經過 Collector 送到各自的儲存後端,透過 Dashboard 視覺化,最終設定告警在異常時通知團隊。

程式碼範例

C# 版本

csharp
// OpenTelemetry — 統一的 Instrumentation 框架
using OpenTelemetry.Trace;
using OpenTelemetry.Metrics;
using OpenTelemetry.Logs;
 
var builder = WebApplication.CreateBuilder(args);
 
// Tracing
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddOtlpExporter())
    .WithMetrics(metrics => metrics
        .AddAspNetCoreInstrumentation()
        .AddRuntimeInstrumentation()
        .AddOtlpExporter());
 
// Logging(Serilog 結構化日誌)
builder.Host.UseSerilog((ctx, config) => config
    .WriteTo.Console(new JsonFormatter())
    .Enrich.FromLogContext()
    .Enrich.WithProperty("ServiceName", "order-service"));
 
// 自訂 Metrics
var orderCounter = Meter.CreateCounter<int>("orders.placed.total");
var orderDuration = Meter.CreateHistogram<double>("orders.processing.duration.ms");
 
app.MapPost("/api/orders", async (OrderRequest req) =>
{
    using var activity = ActivitySource.StartActivity("PlaceOrder");
    activity?.SetTag("customer.id", req.CustomerId);
 
    var sw = Stopwatch.StartNew();
    var order = await ProcessOrder(req);
    sw.Stop();
 
    orderCounter.Add(1, new("status", "success"));
    orderDuration.Record(sw.ElapsedMilliseconds);
    logger.LogInformation("Order {OrderId} placed for {CustomerId}",
        order.Id, req.CustomerId);
 
    return Results.Ok(order);
});

TypeScript 版本

typescript
import { NodeSDK } from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import pino from "pino";
 
// OpenTelemetry 初始化
const sdk = new NodeSDK({
  serviceName: "order-service",
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();
 
// 結構化日誌
const logger = pino({
  level: "info",
  formatters: {
    level: (label) => ({ level: label }),
  },
});
 
// 自訂 Metrics
import { metrics } from "@opentelemetry/api";
const meter = metrics.getMeter("order-service");
const orderCounter = meter.createCounter("orders.placed.total");
const orderDuration = meter.createHistogram("orders.processing.duration.ms");
 
app.post("/api/orders", async (req, res) => {
  const start = Date.now();
  try {
    const order = await processOrder(req.body);
    orderCounter.add(1, { status: "success" });
    logger.info({ orderId: order.id, customerId: req.body.customerId },
      "Order placed successfully");
    res.json(order);
  } catch (error) {
    orderCounter.add(1, { status: "error" });
    logger.error({ error: error.message }, "Order placement failed");
    res.status(500).json({ error: "Failed to place order" });
  } finally {
    orderDuration.record(Date.now() - start);
  }
});

Python 版本

python
import structlog
from opentelemetry import trace, metrics
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.metrics import MeterProvider
import time
 
# 結構化日誌
logger = structlog.get_logger()
 
# Tracing
tracer = trace.get_tracer("order-service")
 
# Metrics
meter = metrics.get_meter("order-service")
order_counter = meter.create_counter("orders.placed.total")
order_duration = meter.create_histogram("orders.processing.duration.ms")
 
@app.post("/api/orders")
async def place_order(request: OrderRequest):
    with tracer.start_as_current_span("place_order") as span:
        span.set_attribute("customer.id", request.customer_id)
        start = time.time()
 
        try:
            order = await process_order(request)
            order_counter.add(1, {"status": "success"})
            logger.info("order_placed",
                order_id=order.id,
                customer_id=request.customer_id)
            return order
        except Exception as e:
            order_counter.add(1, {"status": "error"})
            span.record_exception(e)
            logger.error("order_failed", error=str(e))
            raise
        finally:
            duration = (time.time() - start) * 1000
            order_duration.record(duration)

結構圖

Application
OTLP
OpenTelemetry Collector
logs
Log Storage (Loki/ELK)
visualize
Metrics Storage (Prometheus)
visualize
Trace Storage (Jaeger)
visualize
Grafana Dashboard
Alertmanager

圖中 Application 透過 OTLP 協定將三種信號送到 OpenTelemetry Collector。Collector 將資料分發到各自的儲存後端:Loki 存 Logs、Prometheus 存 Metrics、Jaeger 存 Traces。Grafana 作為統一的 Dashboard 從三個後端讀取資料進行視覺化。Alertmanager 根據 Metrics 的告警規則觸發通知。

面試常見問題

Q: Logs、Metrics、Traces 各自最適合回答什麼問題?

A: Logs 回答「發生了什麼」— 具體的事件細節和上下文。Metrics 回答「趨勢如何」— 錯誤率是否上升、延遲分布是否異常。Traces 回答「問題在哪裡」— 一個慢請求到底卡在哪個服務的哪個操作。三者結合才能完整回答「為什麼系統不正常」。

Q: 什麼是 OpenTelemetry?為什麼它重要?

A: OpenTelemetry(OTel)是 CNCF 的開源 observability 框架,提供統一的 API 和 SDK 來產生 Logs、Metrics、Traces。它是 vendor-neutral 的,程式碼中只用 OTel API,底層可以切換任何 backend(Jaeger、Datadog、New Relic)。避免了 vendor lock-in。

Q: SLI、SLO、SLA 的差別?

A: SLI(Service Level Indicator)是量測指標本身,例如「P99 延遲」。SLO(Service Level Objective)是內部的目標,例如「P99 延遲小於 200ms」。SLA(Service Level Agreement)是和客戶的合約承諾,例如「月可用性 99.9%,未達到退費 10%」。SLI 量測 → SLO 設目標 → SLA 簽合約。

理解測驗

🤔 以下哪個最適合用來追蹤一個請求在多個微服務間的完整路徑?

🤔 Metrics 的三種主要類型是什麼?

🤔 Monitoring 和 Observability 的核心差異是什麼?

重點整理

💡一句話記住

Observability = Logs + Metrics + Traces,讓系統變透明。 口訣:「Log 記事件,Metrics 看趨勢,Trace 追鏈路」

| 概念 | 說明 | |------|------| | Logs | 離散事件紀錄,回答「發生了什麼」 | | Metrics | 時間序列數值,回答「趨勢如何」 | | Traces | 請求路徑追蹤,回答「慢在哪裡」 | | OpenTelemetry | 統一的 observability 框架(vendor-neutral) | | 核心目的 | 能從外部輸出理解系統內部狀態 |

你可能也想看

Structured Logging

按 ← → 鍵切換課程