阶段9: 监控与运维
目标: 有结构化日志、Prometheus 指标、Grafana 面板、告警规则,系统可观测。
| 模块 | 内容 |
|---|---|
| Module 15 | 可观测性三大支柱(日志/指标/追踪)、健康检查、SLO/SLI/SLA |
步骤 1:结构化日志
Section titled “步骤 1:结构化日志”替换 fmt.Println,使用 JSON 格式日志。
请帮我为酒店预订系统引入结构化日志:
1. 选择日志库:zerolog(轻量高性能)或 zap(Uber 出品) - 我选 zerolog,请帮我集成
2. 日志格式(JSON): { "time": "2024-01-15T10:30:00Z", "level": "info", "msg": "booking created", "correlation_id": "abc-123", "user_id": 42, "booking_id": 1001, "room_id": 5, "check_in": "2024-02-01", "check_out": "2024-02-03", "duration_ms": 45 }
3. 请求日志中间件: - 每个请求自动生成 correlation_id(UUID) - 记录:method, path, status, latency, client_ip, user_agent - correlation_id 通过 context 传递,所有下游日志自动带上 - 放在 X-Correlation-ID 响应头中
4. 日志级别配置: - 开发环境:debug + 彩色控制台输出 - 生产环境:info + JSON 输出到 stdout
5. 替换现有代码中所有 fmt.Println / log.Println
给出完整的日志中间件和初始化代码。步骤 2:健康检查
Section titled “步骤 2:健康检查”实现存活和就绪探针。
请帮我为酒店预订系统实现健康检查接口:
1. GET /health(存活探针 Liveness): - 返回 {"status": "ok", "version": "1.0.0", "uptime": "2h30m"} - 只要进程活着就返回 200 - 不依赖外部服务
2. GET /health/ready(就绪探针 Readiness): - 检查 PostgreSQL 连接:db.Exec("SELECT 1") - 检查 Redis 连接:redis.Ping() - 全部通过 → 200 {"status": "ready", "checks": {"postgres": "ok", "redis": "ok"}} - 任一失败 → 503 {"status": "not_ready", "checks": {"postgres": "ok", "redis": "fail"}}
3. Docker healthcheck 配置: - Dockerfile: HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD wget -qO- http://localhost:8080/health || exit 1 - docker-compose: healthcheck 使用 /health/ready
4. 这两个接口不需要认证,不记录访问日志(避免日志刷屏)
给出完整的 handler 代码和路由注册。步骤 3:Prometheus 指标
Section titled “步骤 3:Prometheus 指标”暴露系统和业务指标。
请帮我为酒店预订系统集成 Prometheus 指标:
1. 引入 prometheus/client_golang
2. 系统指标(中间件自动采集): - http_requests_total{method, path, status} — Counter - http_request_duration_seconds{method, path} — Histogram(桶:0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10) - http_requests_in_flight — Gauge
3. 数据库指标: - db_connections_active — Gauge - db_connections_idle — Gauge - db_query_duration_seconds{operation} — Histogram
4. 业务指标: - bookings_created_total{room_type, status} — Counter - bookings_cancelled_total{reason} — Counter - search_results_total{city} — Histogram(搜索返回的房间数量) - active_bookings — Gauge(当前活跃预订数)
5. 暴露端点:GET /metrics - 不需要认证 - 但生产环境应限制只允许 Prometheus 服务器访问
6. 写一个 Gin 中间件自动采集 HTTP 指标7. 在业务代码的关键位置手动记录业务指标
给出完整的指标定义、中间件和业务埋点代码。步骤 4:Grafana Dashboard
Section titled “步骤 4:Grafana Dashboard”搭建监控面板。
请帮我为酒店预订系统搭建 Prometheus + Grafana 监控:
1. docker-compose 添加服务: - prometheus: - image: prom/prometheus:v2.48.0 - volumes: ./prometheus.yml:/etc/prometheus/prometheus.yml - ports: 9090:9090 - grafana: - image: grafana/grafana:10.2.0 - volumes: grafana_data:/var/lib/grafana - ports: 3000:3000 - environment: GF_SECURITY_ADMIN_PASSWORD=admin
2. prometheus.yml 配置: - scrape_interval: 15s - 目标:app:8080/metrics
3. Grafana Dashboard JSON(四大黄金信号): - 请求速率(Rate):QPS 折线图,按 path 分组 - 错误率(Errors):5xx 占比,红色告警线 5% - 延迟(Latency):P50/P95/P99 折线图 - 饱和度(Saturation):数据库连接池使用率,内存使用率
4. 业务 Dashboard: - 今日预订数 / 取消数 - 各城市搜索热度 - 各房型预订占比(饼图)
给出 docker-compose 追加配置、prometheus.yml 和 Grafana Dashboard JSON。步骤 5:告警规则
Section titled “步骤 5:告警规则”关键指标异常时及时通知。
请帮我为酒店预订系统配置 Prometheus 告警规则:
文件:alert_rules.yml
告警规则:1. HighErrorRate: - 5xx 错误率 > 5%,持续 5 分钟 - severity: critical
2. HighLatency: - P99 延迟 > 2 秒,持续 5 分钟 - severity: warning
3. DatabaseConnectionPoolHigh: - 活跃连接 > 最大连接数的 80%,持续 3 分钟 - severity: warning
4. DiskSpaceHigh: - 磁盘使用率 > 90% - severity: critical
5. ServiceDown: - 健康检查失败,持续 1 分钟 - severity: critical
告警通知(Alertmanager):- 配置发送到飞书/钉钉 Webhook(给出 Webhook 配置模板)- critical 级别立即通知- warning 级别每 30 分钟通知一次
给出 alert_rules.yml 和 alertmanager.yml 配置。步骤 6:定义 SLO
Section titled “步骤 6:定义 SLO”明确系统的服务目标。
请帮我为酒店预订系统定义 SLO(服务等级目标):
1. 可用性 SLO: - 目标:99.9%(每月允许宕机 43 分钟) - SLI:成功请求数 / 总请求数(排除 4xx) - 计算 PromQL:1 - (sum(rate(http_requests_total{status=~"5.."}[30d])) / sum(rate(http_requests_total[30d])))
2. 延迟 SLO: - 搜索 API P95 < 200ms - 预订 API P95 < 500ms - SLI:histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{path="/api/search"}[5m]))
3. 预订成功率 SLO: - 目标:99.5%(排除用户主动取消) - SLI:成功预订数 / 尝试预订数
4. 错误预算: - 99.9% 可用性 = 每月 43 分钟错误预算 - 错误预算消耗 > 50% 时冻结新功能发布 - 错误预算消耗 > 80% 时触发事故复盘
5. 在 Grafana 上创建 SLO Dashboard: - 当前可用性百分比(大数字) - 剩余错误预算(进度条) - 30 天可用性趋势(折线图)
给出 PromQL 查询和 Grafana Dashboard 配置。- 日志已替换为 zerolog/zap,JSON 格式,带 correlation_id
- GET /health 和 GET /health/ready 正常返回
- Prometheus 指标暴露在 /metrics,含 HTTP + 业务指标
- Grafana 面板显示四大黄金信号(速率/错误/延迟/饱和度)
- 告警规则已配置(错误率/延迟/连接池/磁盘/存活)
- SLO 已定义并在 Grafana 有 Dashboard
- 告警通知能发送到飞书/钉钉
-
日志太多撑爆磁盘: 生产环境不要开 debug 级别。日志输出到 stdout 让 Docker 管理,配置 Docker 的 log-driver 限制文件大小(
max-size: 10m, max-file: 3)。不要直接写文件,否则忘记 rotate 会把磁盘写满。 -
Prometheus 指标基数爆炸: 不要把 user_id、booking_id 这种高基数字段放进 label。
http_requests_total{user_id="12345"}会产生无数时间序列,拖垮 Prometheus。label 只放低基数的分类字段(method/path/status/room_type)。 -
健康检查接口太重:
/health/ready每 30 秒检查一次数据库和 Redis,如果检查逻辑太复杂(比如跑一个大查询),反而会成为性能瓶颈。用最简单的 ping 即可,不要在健康检查里做业务逻辑。 -
Grafana 面板看不到数据: 常见原因:Prometheus 没有正确 scrape 到应用(检查 targets 页面)、PromQL 查询写错了(先在 Prometheus UI 验证)、Grafana 数据源没配对。先用
curl localhost:8080/metrics确认指标存在。 -
告警风暴: 一个故障触发几十条告警。用 Alertmanager 的 group_by 和 group_wait 聚合告警,同一个问题只发一次通知。设置合理的 for 持续时间(比如 5 分钟),避免瞬间抖动触发告警。