下载工作台
Django Web 开发

Prometheus、OpenTelemetry 与 APM

试读上半部分 · 解锁后可读全文

第 18 章 · Prometheus、OpenTelemetry 与 APM

本章目标:使用 django-prometheusprometheus_clientshop-demo 暴露 /metrics(请求计数、延迟直方图);理解 RED 指标Grafana 告警概念;入门 OpenTelemetry Django instrumentation,让 trace_id 贯穿 ORM、Redis 与 Celery;将结构化日志metrics 通过 request_id 关联(衔接 ch09);了解 APM(Datadog / New Relic 类工具)概念;建立生产可观测性 checklist

学时建议:5~6 小时(含 2 小时 Prometheus + Grafana 跟练)

前置:本模块 ch09 请求 ID 与结构化日志;ch10 Redis 与 Celery;ch11 Gunicorn;ch17 ORM 慢查询与连接池。监控概念可对照 ops-deployxiaozi-cloud 告警章节。


18.1 可观测性三大支柱

         Metrics              Logs               Traces
    Prometheus/Grafana    JSON → ELK/Loki    OpenTelemetry → Jaeger
    「系统是否异常?」     「发生了什么?」      「慢在哪里?」
支柱shop-demo 示例
Metrics/metrics 暴露 django_http_requests_total_by_view_transport_method
Logsrequest_id=abc123 关联访问与审计日志
Tracestrace_id 串联 ORM 查询、Redis 缓存与 Celery 任务
统一使用虚构 shop-demoapi.example.com严禁写入真实监控地址、API Key 或租户 ID。

RED 方法(请求型服务):Rate 每秒请求、Errors 错误率、Duration 延迟分布。Django 后台与 DRF API 均适用。


18.2 django-prometheus 集成

方案 A:django-prometheus(推荐,开箱即用)

pip install django-prometheus

shopdemo/settings.py

INSTALLED_APPS = [
  "django_prometheus",
  # ... 其他应用
]

MIDDLEWARE = [
  "django_prometheus.middleware.PrometheusBeforeMiddleware",
  "django.middleware.security.SecurityMiddleware",
  # ... 原有中间件(含 ch09 RequestLogMiddleware)
  "django_prometheus.middleware.PrometheusAfterMiddleware",
]

# 数据库、缓存也可被采集
DATABASES = {
  "default": {
    "ENGINE": "django_prometheus.db.backends.postgresql",
    # ...
  }
}

CACHES = {
  "default": {
    "BACKEND": "django_prometheus.cache.backends.redis.RedisCache",
    "LOCATION": "redis://127.0.0.1:6379/0",
  }
}

shopdemo/urls.py

urlpatterns = [
    path("", include("django_prometheus.urls")),  # 暴露 /metrics
    # ... 业务路由
]

默认指标含 HTTP 请求计数、延迟直方图、数据库连接、缓存命中等。

方案 B:prometheus_client(自定义指标更灵活):在 core/middleware.pyCounter/Histogram 记录 methodviewstatus,通过 generate_latest() 暴露 /metrics(仅内网)。适合需要精细控制 label 或不想改 DB ENGINE 的场景。

方案适用
django-prometheus快速接入、DB/Cache 指标齐全
prometheus_client自定义业务 Counter、细粒度控制

自定义业务 Counter

from prometheus_client import Counter

order_created_total = Counter(
    "shopdemo_order_created_total", "订单创建次数", ["source"]
)
# 视图中:order_created_total.labels(source="api").inc()

保护 /metrics(生产必做):

# Nginx 限制内网 IP,或 Bearer Token 校验 METRICS_TOKEN
# urls.py 中不要将 /metrics 暴露给公网

18.3 本地 Prometheus + Grafana 跟练

shop-demo/deploy/prometheus.yml

global:
  scrape_interval: 15s

scrape_configs:
  - job_name: shop-demo
    metrics_path: /metrics
    static_configs:
      - targets: [host.docker.internal:8000]
        labels: {env: staging, service: shop-demo}

shop-demo/deploy/docker-compose.monitoring.yml

services:
  prometheus:
    image: prom/prometheus:v2.51.0
    volumes: [./prometheus.yml:/etc/prometheus/prometheus.yml:ro]
    ports: ["9090:9090"]
  grafana:
    image: grafana/grafana:10.4.0
    ports: ["3000:3000"]
    environment:
      GF_SECURITY_ADMIN_PASSWORD: changeme-local-only

常用 PromQL(django-prometheus 指标名)

Panel表达式
QPSrate(django_http_requests_total_by_view_transport_method[1m])
P95histogram_quantile(0.95, rate(django_http_requests_latency_seconds_by_view_method_bucket[5m]))
5xx 比sum(rate(django_http_responses_total_by_status{status=~"5.."}[5m])) / sum(rate(django_http_responses_total_by_status[5m]))
DB 连接django_db_new_connections_total

若使用自定义 shopdemo_* 指标,将表达式中的前缀替换即可。


18.4 Grafana 告警规则(虚构示例)

shop-demo/deploy/alerts/shop-demo.yml

groups:
  - name: shop-demo-staging
    rules:
      - alert: ShopDemoHighErrorRate
        expr: |
          sum(rate(django_http_responses_total_by_status{status=~"5.."}[5m]))
          / sum(rate(django_http_responses_total_by_status[5m])) > 0.05
        for: 5m
        labels: {severity: critical, service: shop-demo}
        annotations:
          summary: "shop-demo 5xx 错误率超过 5%"

      - alert: ShopDemoHighLatencyP99
        expr: |
          histogram_quantile(0.99,
            sum(rate(django_http_requests_latency_seconds_by_view_method_bucket[5m])) by (le)
          ) > 2
        for: 10m
        labels: {severity: warning}
        annotations:
          summary: "P99 延迟超过 2 秒"

      - alert: ShopDemoMetricsTargetDown
        expr: up{job="shop-demo"} == 0
        for: 2m
        labels: {severity: critical}
字段说明
exprPromQL 触发条件
for持续时长,防抖动
annotationsRunbook 链接(用占位 URL)

通知渠道用占位 Webhook,不写真实密钥。


18.5 OpenTelemetry Django instrumentation

OpenTelemetry(OTel) 统一 Traces/Metrics/Logs 的 CNCF 标准,展示单次请求完整路径:

trace_id: 7a3f9c2e...
├─ span: GET /api/v1/products/     [120ms]
│   ├─ span: django.db SELECT      [85ms]
│   └─ span: redis GET cache:key   [3ms]
└─ span: celery send_task          [2ms]  (异步任务投递)
pip install opentelemetry-api opentelemetry-sdk \
  opentelemetry-instrumentation-django \
  opentelemetry-instrumentation-psycopg2 \
  opentelemetry-instrumentation-redis \
  opentelemetry-instrumentation-celery \
  opentelemetry-exporter-otlp

shopdemo/telemetry.py

import os

以下内容需解锁后阅读

试读已结束。解锁本章 ¥5.00,或开通年度会员畅读全部教程。
年度会员 ¥199.00/年; 小紫 AI 工作台有效会员 ¥99.00/年

正文仅在服务端鉴权后下发,未付费无法获取下半部分内容。