需在HTTP handler中用原子计数器+环形缓冲区实时统计错误率,以WriteHeader状态码为主、排除401/403/429等客户端错误,结合响应体字段二次判断,并通过连续窗口超限+文件锁防抖告警。

怎么在 HTTP handler 里实时统计错误率
错误率不是靠事后查日志算出来的,得在请求处理链路里埋点,边响应边更新。核心是用原子计数器记录成功/失败次数,并按时间窗口滑动计算——别直接用 time.Now().Second() 做桶,会因并发导致同一秒内多个 goroutine 写乱。
- 用
sync/atomic维护两个uint64:一个记总请求数,一个记错误数,避免锁竞争 - 错误判定只看
http.ResponseWriter的实际写入状态(比如检查是否已写 header),而不是靠 panic 捕获——panic 无法覆盖 400、500 等正常返回的业务错误 - 时间窗口建议用固定长度的环形缓冲区(如每秒一个 slot,保留最近 60 秒),比用
time.Ticker定时重置更准,避免 GC 或调度延迟导致的统计漂移
如何定义“错误”才不漏报也不误报
HTTP 错误码 ≠ 业务错误。比如 401 Unauthorized 是标准流程,500 Internal Server Error 才该进错误率;但有些接口把参数校验失败统一返回 400,这时就得结合响应体里的 code 字段二次判断。
- 优先以
http.ResponseWriter.WriteHeader()调用的 status code 为准,但需排除401、403、429这类客户端可控错误(除非你明确要监控鉴权失败率) - 对 JSON API,可在 middleware 解析响应体,匹配
"code": 500或"success": false等字段,但注意别影响性能——加个开关控制是否开启深度解析 - 不要把
context.DeadlineExceeded当普通错误计入,它是超时控制机制的一部分,应单独统计,否则会掩盖真实服务异常
错误率超标后怎么可靠触发告警
告警不是一超过阈值就发邮件。得防抖、防重复、带上下文,否则半夜被 100 条相同告警叫醒。
- 用 “连续 N 个窗口都超限” 触发(比如 3 个连续 10 秒窗口错误率 > 5%),比单次超标更稳,过滤毛刺
- 告警内容必须带当时采样到的原始数据:错误数、总数、错误码分布直方图(用
map[int]int记录)、top 3 失败路径(从http.Request.URL.Path截取) - 发送告警前先写入本地
/tmp/alert_cooldown文件并加文件锁,10 分钟内同类型告警只发一次——别依赖内存变量,进程重启就丢了
为什么不用 Prometheus + Grafana 就搞不定这事
能用,但容易掉坑里。Prometheus 的 rate() 函数默认基于 5 分钟滑动窗口,而接口错误率需要秒级敏感度;且它的采样是 pull 模式,如果实例突然 crash,最后一分钟指标就断了,告警延迟不可控。
立即学习“go语言免费学习笔记(深入)”;
- 自己维护滑动窗口能精确到 1 秒粒度,且 push 式上报(比如通过 UDP 发到本地 logstash)不依赖目标存活
- 如果硬要用 Prometheus,必须配
scrape_interval: 1s和evaluation_interval: 1s,但会显著增加 server 压力,小厂机器扛不住 - 真正难的不是采集,是区分“瞬时抖动”和“真实恶化”——这得靠你在滑动窗口里做方差检测,Prometheus 表达式写不出来
最麻烦的是错误归因:同一个错误率飙升,可能是下游 DB 挂了,也可能是某个新上线的正则表达式 O(n²) 匹配卡住 CPU。监控只是信号灯,背后得有配套的日志 trace ID 对齐和 pprof 快照抓取机制,不然光看数字没用。


















