# 可观测性技术栈说明 本文档用于记录 GoFrame 重构时建议引入的监控、日志、链路追踪和采集技术栈,方便后续回看和落地。 ## 1. 一句话理解 | 组件 | 简单理解 | 主要用途 | | --- | --- | --- | | Prometheus | 看指标 | 采集和存储 QPS、耗时、失败率、队列积压等数字指标 | | Loki | 查日志 | 存储和检索应用日志、支付回调日志、异常日志 | | Tempo | 查链路 | 查看一次请求从入口到 DB、Redis、外部接口的完整调用过程 | | Grafana | 统一看板 | 在一个界面里看指标、日志、链路和告警 | | OpenTelemetry | 统一埋点标准 | 规定应用如何输出 metrics、logs、traces | | Alloy | 统一采集器 | 收集日志、指标、链路数据,再转发给 Prometheus、Loki、Tempo | ## 2. 整体关系 ```text GoFrame API / Worker / Nginx / Redis / MySQL | | 产生 metrics / logs / traces v Grafana Alloy / OpenTelemetry Collector | +--> Prometheus 存指标 +--> Loki 存日志 +--> Tempo 存链路 | v Grafana 统一展示、查询、告警 ``` 这套体系要解决的问题不是“做一个漂亮大屏”,而是让线上问题能快速回答: - 哪个接口慢了? - 哪个渠道支付回调失败变多了? - Redis Stream 是否积压? - CP 通知是否失败? - 一笔订单从回调到发货到底卡在哪一步? - 某个 `order_no`、`trace_id`、`channel` 相关日志在哪里? ## 3. Prometheus:看指标 Prometheus 负责存储数字型监控指标,适合做趋势、告警和服务健康判断。 在当前项目中建议重点采集: | 指标 | 示例 | | --- | --- | | API 请求量 | 每个接口每分钟请求数 | | API 耗时 | P50、P95、P99 延迟 | | API 错误率 | 按 route、code、appid 聚合 | | 支付回调 | 成功数、失败数、验签失败数、重复回调数 | | CP 通知 | 成功数、失败数、重试次数 | | Redis Stream | pending 数、lag、消费失败数 | | MySQL | 连接池使用量、慢查询数量、事务失败数 | | 外部接口 | 实名、支付、渠道 SDK 的耗时和失败率 | 典型告警: ```text 5 分钟内支付回调失败率 > 5% Redis Stream pending > 1000 CP 通知连续失败 > 20 次 接口 P95 延迟 > 800ms 某渠道登录失败率突然升高 ``` 注意:Prometheus 不适合当订单账本,支付金额、订单状态、发货状态必须以 MySQL 为准。 官方文档:https://prometheus.io/docs/introduction/overview/ ## 4. Loki:查日志 Loki 负责日志存储和查询,适合定位具体问题。 GoFrame 日志建议输出 JSON,统一字段: ```json { "time": "2026-06-09T14:30:00+08:00", "level": "error", "trace_id": "trace-xxx", "request_id": "req-xxx", "route": "/api/pay/notify", "appid": "10001", "user_id": 123, "order_no": "P20260609xxx", "channel": "wxpay", "error_code": "PAY_SIGN_INVALID", "message": "pay notify verify failed" } ``` 建议作为 Loki label 的字段: ```text service env level route channel ``` 不建议作为 label 的字段: ```text order_no user_id request_id trace_id mobile id_card ``` 这些字段数量太多,放进日志内容里查询即可,避免 Loki label 爆炸。 当前项目最该记录的日志: - SDK 协议解密失败 - appid/sign 校验失败 - 登录失败 - 注册失败 - 支付下单失败 - 支付回调验签失败 - 支付金额不一致 - 重复支付回调 - CP 通知失败 - complex 渠道登录失败 - 实名/防沉迷接口失败 官方文档:https://grafana.com/docs/loki/latest/ ## 5. Tempo:查链路 Tempo 负责分布式链路追踪。它关心一次请求内部经历了哪些步骤,每一步耗时多少,哪里失败。 支付回调链路示例: ```text HTTP POST /pay/notify -> parse request -> verify payment sign -> query order -> check amount -> update order paid -> write member asset log -> XADD Redis Stream -> worker consume -> notify CP ``` 每一步都可以是一个 span。未来排查订单时,可以通过 `trace_id` 找到整条链路。 第一版建议接入的 trace 链路: - 登录 - 注册 - 下单 - 支付回调 - CP 通知 - complex 登录 - complex 支付回调 - 实名认证 Tempo 不需要像日志一样保存大量文本,它主要保存 trace/span 信息。 官方文档:https://grafana.com/docs/tempo/latest/ ## 6. Grafana:统一看板 Grafana 是统一查询和展示入口。Prometheus、Loki、Tempo 都可以接到 Grafana 里。 建议第一版做这些 Dashboard: | Dashboard | 内容 | | --- | --- | | API 总览 | 请求量、错误率、P95/P99、Top 慢接口 | | 支付总览 | 下单数、回调数、成功率、失败原因、渠道分布 | | CP 通知 | 通知成功率、失败列表、重试次数、积压数 | | complex 渠道 | 各渠道登录/支付成功率、失败率、耗时 | | Redis Stream | stream 长度、pending、consumer lag | | MySQL | 连接池、慢查询、错误数 | | 日志检索 | 按 order_no、trace_id、channel 查询 | Grafana 还可以配置告警,例如: ```text 支付回调失败率升高 -> 钉钉/企业微信告警 Redis Stream 积压 -> 告警 CP 通知失败持续增长 -> 告警 某渠道登录失败率异常 -> 告警 ``` 官方文档:https://grafana.com/docs/grafana/latest/introduction/ ## 7. OpenTelemetry:统一埋点标准 OpenTelemetry 是标准,不是存储系统。 它负责定义应用如何输出: ```text metrics 指标 logs 日志 traces 链路 ``` 使用 OpenTelemetry 的好处: - GoFrame 服务、worker、后续拆出来的服务都用同一套 trace_id。 - 以后从本地 Grafana 换到云厂商可观测平台,埋点不用大改。 - 可以统一 HTTP、MySQL、Redis、外部 API 的耗时观测。 GoFrame 重构时建议从一开始就设计这些上下文字段: ```text trace_id request_id appid user_id game_id order_no channel route ``` 官方文档:https://opentelemetry.io/docs/what-is-opentelemetry/ ## 8. Alloy:统一采集器 Grafana Alloy 是采集器,可以理解为“观测数据中转站”。 它可以采集: - Go 服务暴露的 metrics - Go 服务输出的 OTLP traces - Docker 容器日志 - Nginx access/error 日志 - 本地文件日志 - MySQL/Redis exporter 指标 然后转发到: ```text Prometheus Loki Tempo Grafana Cloud ``` 在当前项目里,Alloy 可以负责: ```text 采集 GoFrame JSON 日志 -> 发给 Loki 采集 OpenTelemetry trace -> 发给 Tempo 采集应用 metrics -> 发给 Prometheus 采集 Nginx 日志 -> 发给 Loki ``` 官方文档:https://grafana.com/docs/alloy/latest/ ## 9. 第一版落地建议 不要一次性把所有东西都做复杂,建议分阶段。 ### 阶段 1:先接 Prometheus + Grafana 目标:能看到接口和支付的关键指标。 必须有: - API 请求量 - API 错误率 - API P95/P99 - 支付回调成功/失败数 - CP 通知失败数 - Redis Stream pending 数 ### 阶段 2:接 Loki + Alloy 目标:能按订单、渠道、trace_id 查日志。 必须统一日志字段: ```text trace_id request_id route appid user_id order_no channel error_code ``` ### 阶段 3:接 Tempo + OpenTelemetry 目标:核心链路能追踪。 优先接: - 支付回调链路 - CP 通知链路 - 登录链路 - complex 渠道链路 ## 10. 对当前项目的关键价值 | 当前痛点 | 这套技术栈的帮助 | | --- | --- | | 支付失败难排查 | 指标看失败率,日志查订单,链路看卡点 | | 渠道太多 | 按 channel 聚合成功率、失败率、耗时 | | CP 通知不稳定 | Redis Stream 指标 + 日志 + 重试链路 | | 老代码逻辑分散 | 通过 trace_id 把一次业务请求串起来 | | 问题发现太晚 | Prometheus/Grafana 告警提前发现 | | 日志散落 | Loki 统一查询 | ## 11. 最小可用版本 第一版不追求全量完美,建议至少做到: ```text Prometheus:接口指标、支付指标、Redis Stream 指标 Loki:GoFrame JSON 日志、Nginx 日志 Grafana:API、支付、渠道、队列四个 Dashboard OpenTelemetry:生成 trace_id,并在日志里透传 Tempo:先只接支付回调和 CP 通知链路 Alloy:统一采集日志和 trace ``` 这样就能覆盖重构初期最核心的风险:接口异常、支付异常、渠道异常、队列积压、发货失败。