Go服务器性能调优:避坑选型,QPS翻倍实战
|
半年前那项目,QPS卡在三万八死活上不去,产品天天在群里@我,说竞品都五万了——我原以为就是换个协程池的事,结果改完更慢了,编译进度条卡在百分之三十五那会儿,群里还有人发了张“老板正在看”的表情包,我盯着屏幕直骂娘。 最开始选的是标准库的http.Server,想着“官方写的能差到哪去”,结果压测时发现,每个连接都占个goroutine,CPU刚到六十就抖得跟筛子似的。隔壁工位的老王凑过来看了一眼,说“你这不是写服务,是开养鸡场呢,一个请求一个鸡,能不卡吗?” 后来换了fasthttp,QPS确实涨了,但埋点数据全丢了——原来fasthttp为了性能,直接复用buffer,埋点的json.Marshal()拿到的全是前一个请求的残渣。设计那边还催着要上线,说“用户看不到埋点不影响体验”,我差点把键盘摔了——体验是不影响,但老板看数据的时候不得把我头拧下来? 外卖到了,拆开是麻辣香锅,辣得我直抽抽,顺手把风扇开到最大档——这时候突然想到,可能不是框架的问题,是GC在作妖。Go的GC虽然比Java强,但三万八的并发下,每秒分配的内存还是能堆满老年代。我翻出pprof一看,好家伙,alloc_space的峰值比珠峰还高,大部分都是http.Request里的那些临时变量。 改的方法特简单:把请求里的大对象全换成对象池,比如bytes.Buffer、json.Decoder这些,用完塞回池里,下次直接拿。但改的时候特别烦,因为要遍历所有handler,把每个可能分配内存的地方都标出来——编译了七次才过,第六次的时候窗外下雨,雨点砸在玻璃上的声音跟压测工具的报错声混在一起,我差点把显示器推下去。 改完一压,QPS直接蹦到四万二,产品乐得在群里发红包,结果第二天灰度的时候,白屏率涨了三个点。查日志发现,对象池没设置最大容量,高并发下池子被撑爆了,新的请求拿不到buffer,直接超时。我盯着日志骂了十分钟“这他妈也能忘”,最后给池子加了个上限,白屏率才降回去。 现在回头看,选型这事真不能跟风——fasthttp快是快,但不适合带埋点的业务;标准库稳是稳,但并发高了就是灾难。我原以为“优胜劣汰”是选最强的,结果发现是选最适合的:比如对象池,看着简单,但容量设小了会饿死,设大了会撑死,得根据业务压测调参数,没有一劳永逸的配置。 上周招聘,面试官问“Go性能调优最重要的是什么”,我说“别信官方文档,别信最佳实践,自己压测三遍再说话”。他愣了下,说“这么现实吗”,我笑了——现实点好,省得像我半年前那样,被产品追着骂,被GC坑得想跳楼。
文章配图,仅供参考 下一步打算把监控加细点,比如每个handler的内存分配、GC停顿时间,这些pprof里虽然有,但得手动查,太麻烦。要是能像Java那样,自动把关键指标打到日志里,调优能省一半时间——不过Go的生态就这样,得自己造轮子,谁让咱选了呢?(编辑:我爱资讯网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |


VR开发编译优化与性能调优实战