Chuyển đến nội dung chính

第 26 課:全端可觀察性 — 日誌、指標與追蹤

可觀察性的 3 個支柱:日誌、指標、追蹤。 Node.js/React 的 OpenTelemetry 設定。分散式追蹤:從微前端透過 API 閘道到微服務的追蹤請求。 Grafana 堆疊:Loki、Prometheus、Tempo。

🏗️ 建築 — 第 26 課 第 26 課:全端可觀察性 — 日誌、 指標和蹤跡

微服務與微前端系統設計-從基礎到生產

第 9 部分:可觀察性與生產準備情況

亞洲開發網

簡介

在分散式架構中,偵錯等於 console.log 不可行。当一个请求经过5个服务时,你需要可观察性来知道请求去了哪里,花了多长时间,以及哪里失败了。

可觀察性的 3 個支柱——日誌、指標、跟踪


1. 可觀察性的三大支柱

┌─────────────────────────────────────────────┐
│              Observability                  │
├──────────────┬──────────────┬───────────────┤
│    Logs      │   Metrics    │   Traces      │
│              │              │               │
│ What happened│ How system   │ Request flow  │
│ (events)     │ performs     │ across svcs   │
│              │ (numbers)    │ (journey)     │
│              │              │               │
│ Loki/ELK     │ Prometheus   │ Tempo/Jaeger  │
└──────────────┴──────────────┴───────────────┘

2. 分散式追蹤

2.1 追蹤端對端請求

User clicks "Place Order" trên frontend:

Trace ID: abc-123-def
├── Span 1: Shell App → POST /api/orders (200ms)
│   ├── Span 2: API Gateway → route to Order Service (5ms)
│   │   ├── Span 3: Order Service → validate (10ms)
│   │   ├── Span 4: Order Service → call Product Service (50ms)
│   │   │   └── Span 5: Product Service → DB query (15ms)
│   │   ├── Span 6: Order Service → call Payment Service (100ms)
│   │   │   └── Span 7: Payment Service → Stripe API (80ms)
│   │   └── Span 8: Order Service → publish OrderPlaced event (5ms)
│   └── Span 9: API Gateway → response (5ms)
└── Total: 200ms

→ Bottleneck: Payment Service → Stripe API (80ms) = 40% total

2.2 OpenTelemetry 設定 (Node.js)

// tracing.js - Setup OpenTelemetry
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://otel-collector:4318/v1/traces',
  }),
  instrumentations: [
    getNodeAutoInstrumentations({
      '@opentelemetry/instrumentation-http': { enabled: true },
      '@opentelemetry/instrumentation-express': { enabled: true },
      '@opentelemetry/instrumentation-pg': { enabled: true },
    }),
  ],
  serviceName: 'product-service',
});

sdk.start();

3. 指標(普羅米修斯)

3.1 關鍵指標(RED 方法)

指標什麼警報時間
速率每秒請求數突然下降
錯誤錯誤率 (5xx)> 1%
持续时间延迟(p50、p95、p99)p99 > 2 秒

3.2 自訂指標

const { meter } = require('@opentelemetry/api');

const orderCounter = meter.createCounter('orders_created_total', {
  description: 'Total orders created',
});

const orderDuration = meter.createHistogram('order_processing_duration_ms', {
  description: 'Order processing time',
});

// Usage
orderCounter.add(1, { status: 'success', payment_method: 'stripe' });
orderDuration.record(duration, { service: 'order-service' });

4. 結構化日誌記錄 (Loki)

// Structured JSON logs
const logger = require('pino')({
  level: 'info',
});

app.use((req, res, next) => {
  const traceId = req.headers['x-trace-id'] || generateTraceId();
  req.log = logger.child({
    traceId,
    service: 'product-service',
    requestId: req.id,
  });
  next();
});

// Usage
req.log.info({ productId: '123', action: 'getProduct' }, 'Product fetched');
req.log.error({ error: err.message, stack: err.stack }, 'Product not found');

5.Grafana 堆疊

┌──────────────────────────────────────────┐
│              Grafana UI                  │
│  Dashboards │ Alerts │ Explore │ Traces  │
├──────────┬──────────┬────────────────────┤
│  Loki    │Prometheus│     Tempo          │
│  (Logs)  │(Metrics) │    (Traces)        │
├──────────┴──────────┴────────────────────┤
│         OpenTelemetry Collector          │
│  Receives → Processes → Exports          │
├──────────────────────────────────────────┤
│         Applications                     │
│  Microservices → OTLP → Collector        │
│  MFE → Web Vitals → Collector            │
└──────────────────────────────────────────┘

6.前端可觀察性(微前端)

// Web Vitals tracking
import { onLCP, onFID, onCLS } from 'web-vitals';

onLCP((metric) => {
  sendToCollector('web_vitals_lcp', metric.value, {
    mfe: 'product-mfe',
    page: window.location.pathname,
  });
});

// Error tracking
window.addEventListener('error', (event) => {
  sendToCollector('frontend_error', {
    message: event.message,
    stack: event.error?.stack,
    mfe: detectMFE(event.filename),
  });
});

總結

支柱工具目的
日志洛基+皮诺发生了什么(结构化 JSON)
指标普罗米修斯系统如何执行(RED 方法)
痕迹节奏+OTEL跨服务的请求流
前端网络生命力每个 MFE 的核心 Web Vitals
儀表板格拉法納統一視覺化

下一篇文章: 第 27 課:效能最佳化-前端和後端