Prometheus 与 Grafana 监控

Prometheus 的数据模型由四个部分组成: 完整表示形式: Prometheus 采用主动拉取(pull)模型,区别于大多数监控系统的推送模型: 1. 被监控目标暴露 HTTP /metrics 端点,返回 Prometheus 文本格式数据 2. Prometheus Server 按照配置的 scrape_interval 定期访问该端点 3. 抓取到的数据存入本地 TSDB(时序数据库) 4. 通过 evaluation_interval 周期性执行告警规则 优势:Prometheus 侧控制采集频率,目标无需知道 Prometheus 存在

分享

官方文档:https://prometheus.io/docs/ | https://grafana.com/docs/grafana/latest/
适用版本:Prometheus 2.x / Grafana 10.x(2026-05-07 核实)

核心概念

数据模型

Prometheus 的数据模型由四个部分组成:

  • Metric name:指标名称,描述被测量的事物(如 http_requests_total
  • Labels:键值对标签,用于区分同一指标的不同维度(如 {method="GET", status="200"}
  • Timestamp:时间戳,毫秒精度的 Unix 时间戳
  • Value:浮点数值

完整表示形式:

http_requests_total{method="GET", handler="/api/users", status="200"} 1234 1712800000000

Metric 类型

类型 描述 适用场景 特点
Counter 单调递增计数器,只增不减 请求总数、错误总数、已处理字节数 重启后归零,配合 rate() 使用
Gauge 可任意增减的当前值 内存用量、连接数、队列长度、温度 反映当前状态
Histogram 将观测值分桶统计,带累积计数 请求延迟分布、响应体大小分布 服务端计算分位数,精度固定
Summary 客户端计算分位数 需要精确分位数但样本量小的场景 客户端计算,无法跨实例聚合

Scrape 原理(Pull 模型)

Prometheus 采用主动拉取(pull)模型,区别于大多数监控系统的推送模型:

  1. 被监控目标暴露 HTTP /metrics 端点,返回 Prometheus 文本格式数据
  2. Prometheus Server 按照配置的 scrape_interval 定期访问该端点
  3. 抓取到的数据存入本地 TSDB(时序数据库)
  4. 通过 evaluation_interval 周期性执行告警规则

优势:Prometheus 侧控制采集频率,目标无需知道 Prometheus 存在,便于服务发现和状态追踪。


prometheus.yml 配置

global 配置

global:
  # 默认抓取间隔,可被 scrape_configs 中的配置覆盖
  scrape_interval: 15s
  # 告警规则评估间隔
  evaluation_interval: 15s
  # 抓取超时时间,必须小于 scrape_interval
  scrape_timeout: 10s
  # 附加到所有时序数据的外部标签,用于联邦或远程写入时区分来源
  external_labels:
    env: production
    region: cn-beijing
配置项 类型 默认值 说明
scrape_interval duration 1m 全局抓取间隔
evaluation_interval duration 1m 规则评估间隔
scrape_timeout duration 10s 单次抓取超时,不能超过 scrape_interval
external_labels map - 附加到所有数据的外部标签

scrape_configs 结构

scrape_configs:
  - job_name: "fastapi-app"
    # 覆盖全局 scrape_interval
    scrape_interval: 10s
    metrics_path: /metrics
    scheme: http

    static_configs:
      - targets:
          - "192.168.1.10:8000"
          - "192.168.1.11:8000"
        labels:
          app: fastapi
          env: production

    # 重打标签:在抓取前修改目标的标签
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: "blackbox-exporter:9115"

  - job_name: "node-exporter"
    static_configs:
      - targets:
          - "192.168.1.10:9100"
          - "192.168.1.11:9100"

scrape_configs 核心字段:

字段 说明
job_name 任务名称,自动添加为 job 标签
static_configs 静态目标列表
file_sd_configs 基于文件的服务发现
kubernetes_sd_configs Kubernetes 服务发现
relabel_configs 抓取前对目标标签进行转换,可过滤/修改/删除标签
metrics_path 指标路径,默认 /metrics
scrape_interval 覆盖全局间隔

alerting 配置

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - "alertmanager:9093"
      # 超时设置
      timeout: 10s
      # API 版本
      api_version: v2

rule_files 告警规则

rule_files:
  - "rules/alert_rules.yml"
  - "rules/recording_rules.yml"
  # 支持通配符
  - "rules/*.yml"

PromQL 查询语言

即时查询 vs 范围查询

类型 语法 返回值 用途
即时查询 metric_name{label="value"} 即时向量 当前值、仪表盘数值
范围查询 metric_name{label="value"}[5m] 范围向量 配合函数计算速率

范围向量不能直接在 Grafana 中绘图,必须用函数(如 rate())将其转换为即时向量。

选择器语法

# 精确匹配
http_requests_total{method="GET", status="200"}

# 正则匹配
http_requests_total{method=~"GET|POST"}

# 排除匹配
http_requests_total{status!="500"}

# 排除正则
http_requests_total{method!~"OPTIONS|HEAD"}

# 范围向量(过去 5 分钟的样本)
http_requests_total{method="GET"}[5m]

# 偏移量(1 小时前的值)
http_requests_total offset 1h

常用函数

rate — 平均速率

# 过去 5 分钟 HTTP 请求的平均每秒速率(适合 Counter)
rate(http_requests_total[5m])

irate — 瞬时速率

# 基于最后两个样本计算瞬时速率,对突刺更敏感
irate(http_requests_total[5m])

increase — 增量

# 过去 1 小时内请求总增量
increase(http_requests_total[1h])

sum by — 聚合

# 按 job 标签聚合请求总速率
sum by(job) (rate(http_requests_total[5m]))

# 去掉某个标签,保留其余标签
sum without(instance) (rate(http_requests_total[5m]))

histogram_quantile — 分位数

# 计算过去 5 分钟请求延迟的 P99
histogram_quantile(0.99,
  sum by(le) (rate(http_request_duration_seconds_bucket[5m]))
)

# P50 / P95
histogram_quantile(0.50, sum by(le) (rate(http_request_duration_seconds_bucket[5m])))
histogram_quantile(0.95, sum by(le) (rate(http_request_duration_seconds_bucket[5m])))

topk / bottomk

# 请求速率最高的 5 个实例
topk(5, rate(http_requests_total[5m]))

# 内存占用最低的 3 个节点
bottomk(3, node_memory_MemAvailable_bytes)

其他常用函数

# 过去 5 分钟的最大值
max_over_time(process_resident_memory_bytes[5m])

# 预测 4 小时后磁盘是否耗尽(线性预测)
predict_linear(node_filesystem_avail_bytes[1h], 4 * 3600)

# 时序存在时间(秒)
time() - process_start_time_seconds

# 绝对值、向上取整、向下取整
abs(delta(cpu_temp_celsius[10m]))
ceil(rate(http_requests_total[5m]))
floor(rate(http_requests_total[5m]))

运算符

算术运算符

# 将字节转换为 GB
node_memory_MemTotal_bytes / 1024 / 1024 / 1024

# 计算内存使用率(百分比)
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
  / node_memory_MemTotal_bytes * 100

比较运算符

# 过滤出错误率超过 1% 的服务(返回匹配的时序)
rate(http_requests_total{status=~"5.."}[5m])
  / rate(http_requests_total[5m]) > 0.01

# bool 修饰符:返回 0/1 而非过滤
rate(http_requests_total[5m]) > bool 100
运算符 说明
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

逻辑运算符

# and:两侧都有匹配才保留
vector_a and vector_b

# or:两侧任意一个有值即保留
vector_a or vector_b

# unless:保留左侧在右侧中没有匹配的部分
vector_a unless vector_b

向量匹配

# 一对一匹配(标签完全相同)
method_code:http_errors:rate5m / ignoring(code) method:http_requests:rate5m

# 多对一匹配
sum by(app, env) (cpu_usage) / on(app) group_left(env) app_info

Python 应用接入

安装

pip install prometheus-client

Counter

from prometheus_client import Counter

# 创建 Counter
REQUEST_COUNT = Counter(
    name="http_requests_total",           # 指标名
    documentation="Total HTTP requests",  # 描述
    labelnames=["method", "endpoint", "status_code"],  # 标签维度
)

# 使用
REQUEST_COUNT.labels(method="GET", endpoint="/api/users", status_code="200").inc()
REQUEST_COUNT.labels(method="POST", endpoint="/api/login", status_code="401").inc(1)

Counter 参数:

参数 类型 说明
name str 指标名称,建议以 _total 结尾
documentation str 指标描述,出现在 /metrics 页面
labelnames list[str] 标签名列表
namespace str 前缀,最终名称为 namespace_name
subsystem str 子系统前缀
registry Registry 注册表,默认 REGISTRY

Gauge

from prometheus_client import Gauge

ACTIVE_CONNECTIONS = Gauge(
    "active_connections",
    "Current active database connections",
    ["db_host"],
)

# 设置绝对值
ACTIVE_CONNECTIONS.labels(db_host="db-01").set(42)

# 增减
ACTIVE_CONNECTIONS.labels(db_host="db-01").inc()
ACTIVE_CONNECTIONS.labels(db_host="db-01").dec(5)

# 追踪进行中的任务数
IN_PROGRESS = Gauge("in_progress_requests", "In-progress requests")

with IN_PROGRESS.track_inprogress():
    # 进入时 +1,退出时 -1
    process_request()

Histogram

from prometheus_client import Histogram

REQUEST_LATENCY = Histogram(
    "http_request_duration_seconds",
    "HTTP request duration in seconds",
    ["method", "endpoint"],
    # 自定义 bucket 边界(秒)
    buckets=[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0],
)

# 手动记录
REQUEST_LATENCY.labels(method="GET", endpoint="/api").observe(0.032)

# 使用计时器上下文管理器
with REQUEST_LATENCY.labels(method="GET", endpoint="/api").time():
    result = expensive_operation()

Histogram 参数:

参数 类型 默认值 说明
buckets list[float] DEFAULT_BUCKETS(0.005 到 10) 分桶边界,Prometheus 自动添加 +Inf

Summary

from prometheus_client import Summary

PROCESSING_TIME = Summary(
    "request_processing_seconds",
    "Time spent processing request",
)

@PROCESSING_TIME.time()
def process_request():
    pass

Summary 与 Histogram 对比:

对比项 Histogram Summary
分位数计算位置 查询时服务端计算 采集时客户端计算
跨实例聚合 支持 不支持(分位数无法聚合)
分位数配置 灵活,查询时指定 需提前配置
内存开销 固定(bucket 数量决定) 较高(维护滑动窗口)
推荐场景 分布式、需跨实例聚合 单实例、需高精度固定分位数

FastAPI 集成

详细的 FastAPI 路由和中间件用法见 FastAPI完全指南

import time
from fastapi import FastAPI, Request, Response
from prometheus_client import (
    Counter, Histogram, generate_latest, CONTENT_TYPE_LATEST
)

app = FastAPI()

# 定义指标
REQUEST_COUNT = Counter(
    "http_requests_total",
    "Total HTTP requests",
    ["method", "endpoint", "status_code"],
)
REQUEST_LATENCY = Histogram(
    "http_request_duration_seconds",
    "HTTP request latency",
    ["method", "endpoint"],
    buckets=[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5],
)


@app.middleware("http")
async def prometheus_middleware(request: Request, call_next):
    start = time.time()
    response = await call_next(request)
    duration = time.time() - start

    endpoint = request.url.path
    method = request.method
    status = str(response.status_code)

    REQUEST_COUNT.labels(method=method, endpoint=endpoint, status_code=status).inc()
    REQUEST_LATENCY.labels(method=method, endpoint=endpoint).observe(duration)

    return response


@app.get("/metrics")
def metrics():
    # 返回 Prometheus 文本格式
    return Response(
        content=generate_latest(),
        media_type=CONTENT_TYPE_LATEST,
    )

推送模式(PushGateway)

适用于批处理任务、短生命周期进程等无法被 pull 的场景:

from prometheus_client import CollectorRegistry, Counter, push_to_gateway

# 使用独立 registry 避免污染全局
registry = CollectorRegistry()

job_duration = Counter(
    "batch_job_duration_seconds_total",
    "Total duration of batch jobs",
    registry=registry,
)

job_duration.inc(42.5)

# 推送到 PushGateway
push_to_gateway(
    gateway="pushgateway:9091",
    job="batch_import",          # job 标签值
    registry=registry,
    grouping_key={"instance": "worker-01"},  # 额外分组键
)

push_to_gateway 参数:

参数 说明
gateway PushGateway 地址
job 任务名称,作为标签附加
registry 使用的 Registry
grouping_key 额外的分组键,用于区分同一 job 的不同实例

Grafana

数据源配置

  1. 进入 Configuration -> Data Sources -> Add data source
  2. 选择 Prometheus
  3. 填写 URL(如 http://prometheus:9090
  4. 根据需要配置认证信息

核心配置项:

配置项 说明
URL Prometheus 服务地址
Scrape interval 告知 Grafana 数据点的最小间隔,影响 $__rate_interval
Query timeout 查询超时
HTTP Method GET 或 POST,大查询建议用 POST

Dashboard 基础操作

  • 创建 Dashboard:点击左侧 + 图标 -> New Dashboard
  • 添加 Panel:Add panel -> Add new panel
  • 编辑查询:在 Panel 编辑页输入 PromQL,选择可视化类型
  • 保存:Ctrl+S 或点击 Save dashboard
  • 导入已有 Dashboard:Dashboards -> Import,粘贴 JSON 或输入 Grafana.com 的 Dashboard ID

常用面板类型

面板类型 适用场景 特点
Time Series 随时间变化的趋势(请求速率、延迟) 最常用,支持多条折线
Gauge 展示当前值占最大值的比例(CPU、内存) 直观的仪表盘样式
Stat 单一数值展示,支持颜色阈值 适合展示总数、当前状态
Table 多维度对比数据 支持列排序、着色
Bar Chart 分类对比 适合 topk 类查询
Heatmap 分布可视化(Histogram bucket 数据) 直观展示延迟热力图

变量(Variables)

变量用于在 Dashboard 顶部创建下拉筛选,动态过滤数据。

配置路径:Dashboard Settings -> Variables -> New variable

变量类型 说明 示例
Query 从 Prometheus 查询标签值 label_values(up, job)
Custom 手动指定选项列表 production, staging, development
Interval 时间间隔选项 1m, 5m, 10m, 30m, 1h
Datasource 动态切换数据源 -

在查询中使用变量:

# $job 和 $instance 为变量名
rate(http_requests_total{job="$job", instance="$instance"}[5m])

# 多值变量(开启 Multi-value 后)
http_requests_total{job=~"$job"}

告警规则配置

  1. 进入 Alerting -> Alert rules -> New alert rule
  2. 填写规则名称和 PromQL 表达式
  3. 设置触发条件(Threshold:IS ABOVE 0.05
  4. 设置 Pending period(持续多久触发,防抖)
  5. 配置 Labels 和 Annotations(通知内容模板)
  6. 关联 Notification policy 和 Contact point

告警状态说明:

状态 说明
Normal 条件未满足
Pending 条件满足但未超过 Pending period
Firing 条件持续满足,告警已触发
NoData 查询无返回数据
Error 查询执行出错

实用 Dashboard 推荐

Dashboard 名称 Grafana ID 说明
Node Exporter Full 1860 节点 CPU/内存/磁盘/网络全面监控
Prometheus 2.0 Overview 3662 Prometheus 自身性能监控
FastAPI Observability 17175 FastAPI 应用请求、延迟、错误率
MySQL Overview 7362 MySQL 性能监控
Redis Dashboard 11835 Redis 内存、命令、连接数监控

AlertManager 告警

告警规则 YAML 语法

# rules/alert_rules.yml
groups:
  - name: application_alerts
    # 规则评估间隔(覆盖全局)
    interval: 30s
    rules:
      - alert: HighErrorRate
        # PromQL 表达式,结果非空时触发告警
        expr: |
          sum by(job) (rate(http_requests_total{status=~"5.."}[5m]))
          / sum by(job) (rate(http_requests_total[5m])) > 0.05
        # 持续时间:条件满足持续 5m 后才真正触发
        for: 5m
        labels:
          severity: critical
          team: backend
        annotations:
          summary: "服务 {{ $labels.job }} 错误率过高"
          description: "错误率为 {{ $value | humanizePercentage }},超过 5% 阈值"
          runbook_url: "https://wiki.example.com/runbooks/high-error-rate"

      - alert: HighMemoryUsage
        expr: |
          (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)
          / node_memory_MemTotal_bytes > 0.9
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "节点 {{ $labels.instance }} 内存使用率超过 90%"

      - alert: DiskWillFillIn4Hours
        expr: predict_linear(node_filesystem_avail_bytes[1h], 4 * 3600) < 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "节点 {{ $labels.instance }} 磁盘预计 4 小时内耗尽"

告警规则字段说明:

字段 说明
alert 告警规则名称
expr PromQL 表达式,非空时进入 Pending 或 Firing 状态
for 持续时间,防止瞬时抖动触发误告警
labels 附加标签,用于路由和分组
annotations 告警描述,支持 Go template 语法({{ $labels.xxx }}

AlertManager 配置

# alertmanager.yml
global:
  # 默认重复发送间隔
  repeat_interval: 4h
  # SMTP 全局配置
  smtp_smarthost: "smtp.example.com:587"
  smtp_from: "[email protected]"
  smtp_auth_username: "[email protected]"
  smtp_auth_password: "password"

# 通知路由树
route:
  # 默认路由分组(所有未匹配的告警走这里)
  receiver: "default-receiver"
  # 分组等待时间(积攒同组告警一起发送)
  group_wait: 30s
  # 同组后续通知间隔
  group_interval: 5m
  # 重复通知间隔
  repeat_interval: 4h
  # 按哪些标签分组
  group_by: [alertname, job]

  # 子路由
  routes:
    - match:
        severity: critical
      receiver: "pagerduty-critical"
      continue: false

    - match_re:
        team: "backend|frontend"
      receiver: "dingtalk-webhook"
      group_by: [alertname, team]

# 接收器定义
receivers:
  - name: "default-receiver"
    email_configs:
      - to: "[email protected]"
        send_resolved: true
        headers:
          Subject: "[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}"

  - name: "dingtalk-webhook"
    webhook_configs:
      - url: "http://dingtalk-webhook:8060/dingtalk/webhook1/send"
        send_resolved: true
        http_config:
          bearer_token: "your-token"

  - name: "pagerduty-critical"
    pagerduty_configs:
      - routing_key: "your-pagerduty-routing-key"
        severity: critical

# 静默规则(运维窗口期使用)
inhibit_rules:
  - source_match:
      severity: critical
    target_match:
      severity: warning
    # 同一 job 和 instance 的 warning 会被 critical 抑制
    equal: [alertname, job, instance]

route 字段说明:

字段 说明
receiver 默认接收器名称
group_by 分组标签,相同标签组合的告警聚合为一条通知
group_wait 初次发送前等待时间,收集同组告警
group_interval 同一组有新告警时等待多久再发送
repeat_interval 告警持续未解决时重复通知间隔
continue 匹配此路由后是否继续匹配后续路由

最佳实践

指标命名规范

规则 正确示例 错误示例
使用基础单位(秒、字节) http_request_duration_seconds http_request_duration_ms
Counter 以 _total 结尾 http_requests_total http_requests_count
Gauge 不加 _total active_connections active_connections_total
应用名作前缀 myapp_cache_hits_total cache_hits_total
使用小写和下划线 node_memory_bytes nodeMemoryBytes
比例用 ratio(0–1) error_ratio error_percent

命名格式:[namespace_][subsystem_]name[_unit][_total]

标签(Label)设计原则

  • 低基数原则:单个 Label 的唯一值不超过 100,全部标签组合不超过 10,000 个时序
  • 不在 Label 中放:用户 ID、订单 ID、请求 ID、IP 地址、邮箱等高基数值
  • 可以放的 Labelmethodstatusendpoint(固定路由,非含参 URL)、regionenv
  • URL 参数路由(如 /users/123)需在接入层归一化为 /users/{id} 再作 Label

Recording Rules:预计算昂贵查询

频繁使用的复杂 PromQL 应转换为 Recording Rule,避免每次 Dashboard 刷新都重新计算:

# rules/recording_rules.yml
groups:
  - name: http_metrics
    interval: 1m
    rules:
      # 预计算:按 job 聚合的 5 分钟请求速率
      - record: job:http_requests:rate5m
        expr: sum by(job) (rate(http_requests_total[5m]))

      # 预计算:P99 延迟
      - record: job:http_request_duration_p99:rate5m
        expr: |
          histogram_quantile(0.99,
            sum by(job, le) (rate(http_request_duration_seconds_bucket[5m]))
          )

在 Dashboard 中直接查询 job:http_requests:rate5m,响应速度提升数倍。

黄金信号:监控什么

参考 Google SRE 四个黄金信号:

信号 指标示例 PromQL 示例
延迟(Latency) P99 请求时间 histogram_quantile(0.99, sum by(le) (rate(http_request_duration_seconds_bucket[5m])))
流量(Traffic) 每秒请求数 sum(rate(http_requests_total[5m]))
错误(Errors) 5xx 错误率 sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
饱和度(Saturation) CPU / 内存使用率 1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m]))

告警规则设计

  • 告警应对症状,而非原因:告警"错误率 > 5%"(用户能感知),而非"数据库连接池耗尽"(内部状态)
  • 避免无法执行的告警:每条告警都应有对应的 Runbook,注明处置步骤
  • 善用 for 防抖:基础设施告警用 5–10 分钟,避免闪烁
  • 分级路由:critical → 立即呼叫值班,warning → 工作时间处理,info → 仅记录

Grafana Dashboard 组织

  • 每个服务建一个 Dashboard,通过顶部变量($job$instance)切换实例
  • Row 按层次组织:Overview → 请求层 → 业务层 → 基础设施层
  • 优先使用 Grafana.com 社区 Dashboard(见上方推荐 ID),在其基础上定制
  • 使用 $__rate_interval 替代硬编码 [5m],自动适配 scrape interval 变化
  • Dashboard 用 JSON 文件纳入版本控制(grafana-dashboard-exporter 或 Terraform)

踩坑与注意事项

高基数 Label 导致性能问题

问题:将用户 ID、URL 参数、请求 ID 等高基数(大量唯一值)字段作为 Label,导致时序数量爆炸式增长,Prometheus 内存和存储急剧膨胀。

# 错误示例:user_id 可能有数百万个唯一值
REQUEST_COUNT = Counter("requests", "...", ["endpoint", "user_id"])
REQUEST_COUNT.labels(endpoint="/api", user_id=user.id).inc()

# 正确示例:只用低基数标签
REQUEST_COUNT = Counter("requests", "...", ["endpoint", "status"])
REQUEST_COUNT.labels(endpoint="/api", status="200").inc()

原则:Label 的唯一值组合(cardinality)不应超过 10,000,单个 Label 的唯一值不应超过 100。

Histogram bucket 设置不合理

问题:使用默认 bucket(最大 10 秒)监控数据库查询(通常 < 100ms),导致大量数据集中在第一个 bucket,分位数计算失真。

# 错误:使用默认 bucket,最大值为 10s,不适合毫秒级延迟
DB_LATENCY = Histogram("db_query_seconds", "Database query duration")

# 正确:根据实际延迟范围设置 bucket
DB_LATENCY = Histogram(
    "db_query_seconds",
    "Database query duration",
    buckets=[0.001, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0],
)

原则:bucket 应覆盖正常延迟的 90% 以上,在关注的延迟区间内密集分布。

rate() 函数使用注意

  • rate() 内的时间窗口至少要包含 4 个采样点,否则结果不稳定。公式:窗口 >= 4 × scrape_interval
  • rate() 会自动处理 Counter 重置,不要对 Gauge 使用 rate()
  • 长时间窗口(如 [1h])会平滑短期波动,短时间窗口响应更敏感

告警规则 for 字段

for 设置过短会导致告警抖动频繁发送通知,设置过长会延迟发现问题。建议:

  • 基础设施告警(CPU、内存):5-10 分钟
  • 业务指标告警(错误率):2-5 分钟
  • 依赖不可用(端点 down):1-2 分钟

常见陷阱

陷阱:rate() 应用于 Gauge 指标得到无意义结果

现象: 对 CPU 使用率(Gauge)用 rate(cpu_usage[5m]) 计算,结果忽大忽小毫无规律。
原因: rate() 是为单调递增的 Counter 设计的(自动处理重置),Gauge 可以任意上下波动,rate() 计算的是区间内的增长速率,对 Gauge 没有意义。
解决: Gauge 指标直接查询或用 avg_over_time(metric[5m]) 计算时间窗口内的平均值;只对 Counter(名称通常以 _total 结尾)使用 rate()

陷阱:Alert 频繁抖动(Flapping)

现象: 同一告警在短时间内反复触发和恢复,发送大量通知骚扰值班人员。
原因: 指标在阈值附近波动,for 持续时间设置过短,每次短暂超阈值就触发告警。
解决: 适当延长 for 字段(CPU 告警 ≥ 5 分钟),在 AlertManager 配置 repeat_interval 控制重复通知间隔,并启用 resolve_timeout 防止过早恢复。

陷阱:Grafana Dashboard 时区与数据时区不一致

现象: Grafana 图表显示的时间与实际事件时间相差 8 小时(或其他偏移)。
原因: Prometheus 存储时间戳为 UTC,Grafana Dashboard 的时区设置为本地时区,若服务器时区与 Grafana 配置不一致则产生偏移。
解决: 在 Dashboard 设置中将时区改为 Browser(跟随用户浏览器)或明确设置 Asia/Shanghai;确保 Prometheus 服务器和 Grafana 时区配置一致。


参见

阅读更多

Web 安全基础

1. HTML 转义(服务端渲染必须): 2. CSP(Content Security Policy): 3. HttpOnly Cookie:防止 JS 读取会话 Cookie: 4. 前端框架防护: 攻击者在第三方网站构造一个表单,诱导已登录用户提交,浏览器会自动携带目标站的 Cookie。 触发条件: 1. 用户已登录目标网站(Cookie 有效) 2. 目标 API 仅凭 Cookie 识别用户身份 3. 请求来源未验证 1. CSRF Token(推荐): 2. SameSite Cookie: 3. 验证 Origin/Referer 头:

By yellowdog

HTTP 协议深度指南

HTTP(HyperText Transfer Protocol)是 Web 的基础传输协议,基于 TCP/IP,采用请求/响应模型。 相关文档:Web安全基础(/web-an-quan-ji-chu/) FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) Nginx完全指南(/nginx-wan-quan-zhi-nan/) 幂等性:多次执行相同请求,服务器状态结果相同。PUT /users/1 多次执行结果一致;POST /users 每次创建新资源,非幂等。 浏览器直接从本地缓存读取,不向服务器发送请求。 缓存命中时,状

By yellowdog

系统设计基础

SLA 对照表: 选择建议:无状态服务(Web 层、API 层)优先水平扩展;数据库初期垂直扩展,达到瓶颈后考虑分库分表或读写分离。 缓存穿透(查询不存在的 key,每次都打到 DB): 缓存击穿(热点 key 过期,瞬间大量请求打到 DB): 缓存雪崩(大量 key 同时过期,或缓存服务宕机): 令牌桶 Python 实现: Redis 实现分布式限流(滑动窗口): URL 命名规则: Cursor 分页响应格式: 雪花算法结构(64 bit): 定义:分布式系统不能同时满足以下三个特性: 在分布式环境中 P 是必须保证的,所以实际是 CP vs AP

By yellowdog

算法思路与模板

二分查找要求序列有序,每次将搜索范围缩减一半,时间复杂度 O(log n)。 两个指针从两端向中间收缩,常用于有序数组。 滑动窗口维护一个满足条件的区间 left, right,right 不断向右扩张,条件不满足时收缩 left。 滑动窗口通用框架: 1. 确定"子问题":原问题可以分解为哪些规模更小的同类问题 2. 定义 dpi 或 dpij 的含义,要足够清晰 3. 推导状态转移方程 4. 确定初始状态(边界条件) 5. 确定计算顺序(确保依赖的子问题先计算) 每件物品最多选一次。dpj = 容量为 j 时的最大价值,逆序遍历容量防止重复选取。 每

By yellowdog