Finding and Fixing a 50k Goroutine Leak That Nearly Killed Production
4 months ago
- #goroutine-leak
- #production-incident
- #debugging
- 某生产环境的API服务出现严重goroutine泄漏问题,六周内从1,200个goroutine激增至50,847个,导致内存占用飙升至47GB,接口响应时间延迟达32秒。
- 泄漏根源在于WebSocket通知系统中存在三个关键缺陷:未调用context的cancel()方法、未停止定时器ticker、未关闭通信通道channel。
- Uber的LeakProf工具在定位泄漏过程中发挥关键作用,发现已断开的WebSocket连接对应的goroutine未被清理。
- 修复方案包括:规范资源回收流程——执行context的cancel()、停止ticker、关闭channel,并建立连接监测机制及时清理失效连接。
- 采用分阶段恢复策略:先实施紧急止血措施,再运行清理脚本消除现存泄漏,最后部署新型监控防止复发。
- 新增Prometheus监控指标,包括goroutine数量、WebSocket订阅数、活跃连接数等核心指标告警体系。
- 强化测试方案:增加泄漏检测测试、针对泄漏的负载测试、支持goroutine追踪的基准测试。
- 核心经验教训:必须明确goroutine退出机制、规范资源回收流程、监控goroutine数量变化、开展泄漏专项测试。
- 该故障导致性能劣化、客户投诉、人力成本、额外AWS支出及商誉损失等多维损失。
- 现行预防机制包括:提交前钩子检测遗漏的ticker.Stop()调用,测试中强制使用goleak进行泄漏检测。