加入收藏 | 设为首页 | 会员中心 | 我要投稿 航空爱好网 (https://www.ikongjun.com/)- 混合云存储、媒体智能、AI行业应用、应用程序集成、办公协同!
当前位置: 首页 > 服务器 > 系统 > 正文

Go服务器性能调优:避坑选型,QPS翻倍实战

发布时间:2026-11-09 14:07:07 所属栏目:系统 来源:DaWei
导读:  第八次压测到凌晨两点十七分,监控面板上QPS突然往下掉——不是抖动,是斜着塌下去的,像一桶水从桶底漏光那样干净。我盯着那个下降斜率,手还悬在键盘上没敲出命令,王工端着保温杯站我身后说:“别查GC了,这次不是它。” 

  第八次压测到凌晨两点十七分,监控面板上QPS突然往下掉——不是抖动,是斜着塌下去的,像一桶水从桶底漏光那样干净。我盯着那个下降斜率,手还悬在键盘上没敲出命令,王工端着保温杯站我身后说:“别查GC了,这次不是它。”


  我原以为是pprof采样开多了拖垮协程调度,结果把runtime/trace全关了重跑,照样塌。连着三天晚上改runtime.GOMAXPROCS、调net/http.Server.ReadTimeout、换io.ReadAll为bufio.NewReader,全没用。直到周四下午翻旧日志,发现五月初那版上线后,所有502都堆在凌晨一点到三点之间,而运维小张发来的告警截图里,Nginx upstream timed out的错误后面,跟着一行被折叠的warning:“http: response.WriteHeader on hijacked connection”。


  ——这行字我早见过,但一直以为是WebSocket握手残留日志。那天我把debug日志级别调到最高,盯着一条请求流:从gin.Context.Writer.WriteHeader(200)开始,到中间件里某次json.Marshal之后调了ctx.Next(),再到某个defer里又碰了一次Writer,最后在return前被hijack进sse流……整个链路根本没报panic,只悄悄吞掉了WriteHeader,而Nginx等不到header,超时就打502。


  我们删了那个defer里的writer.Close(),QPS当场涨回峰值。但第二天早上七点,监控又抖了一下——这次是Redis连接池满了。不是代码漏close,是go-redis/v9默认MaxRetries=3,重试时并发发起新连接,刚好撞上我们的短连接+高并发模型,第七次重试时池子就卡死。我调低MaxRetries到1,QPS又涨一截。反正这事没法单说哪个环节错了,就是选型时没人问过“你打算让这个库在每秒两千个并发下重试几次”。


文章配图,仅供参考

  昨天上线新版本,客服后台跳出条自动回复:“您反馈的加载慢问题,已定位为服务端响应延迟,预计二十来分钟内修复。”——其实根本没修,只是把那块逻辑从HTTP切到了gRPC内部调用,绕开了HTTP层那圈writer/hijack/timeout的烂账。我看着那条回复愣了两秒,没删也没改,就点了发送。


  (咖啡机修了三次,第二次修完漏水,第三次干脆不出蒸汽)


  (地铁站B口闸机昨天起只能刷单程票,不识二维码)


  现在问题是:gRPC服务里那个proto字段叫repeated string tags,但前端传空数组时,go-json Unmarshal会把它转成nil切片,而我们的鉴权中间件只判len(tags)>0,结果空tags直接跳过校验——这事我上周就发现了,但没动,因为改它要连带改四五个微服务的schema,还要推运营侧重新导一遍配置表。我也不知道算不算坑,反正线上跑着没事。


  有谁碰到过这个吗?就是HTTP handler里hijack了之后,再调一次WriteHeader,Go runtime不panic,也不报错,就默默让下游Nginx挂掉——但你看任何panic日志、trace、甚至dmesg都找不到痕迹,只有抓包才能看见SYN-ACK之后没有HTTP header发出去。

(编辑:航空爱好网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!