Go 1.27 让 HTTP/1 的连接复用真正生效
来源:go.dev — 2026-10-14
📋 概述
Go 官方博客解释了一个性能修复:同一个只取状态码的函数用 HTTP/1 打 100 次请求,Go 1.26 约需 710 毫秒,Go 1.27 只要约 150 毫秒,快了近 5 倍。原因是 HTTP/1 的响应在连接上严格按顺序传送,net/http 只有在当前响应体被读到末尾之后才能定位下一个响应的起点;当调用方不读 resp.Body 就直接关闭时,net/http 判断连接无法复用,于是丢弃连接、为后续请求反复新建——而建连要付 TCP 与 TLS 握手的代价,跨区域时单程延迟常在 50 毫秒以上,一次建连可能花掉 3 个 RTT。即使读了响应体也可能中招:encoding/json.Decoder 读到对象的右花括号就停,若服务器在 JSON 后还有一个换行,这一个未消费的字节就让连接作废。过去的办法是手动排空响应体再关闭,但响应很大时排空比新建连接更慢,所以 Go 1.27 把这件事收进了标准库。
🔑 核心要点
- 同一个函数打 100 次请求,Go 1.26 约 710 毫秒,Go 1.27 只要约 150 毫秒,快了近 5 倍
- 根因是 HTTP/1 响应在同一连接上严格按顺序发送,必须读完当前响应体才能定位下一个响应的起点
- 不读响应体就关闭时,net/http 判定连接不可复用而丢弃它,后续请求反复付建连成本
- 建连成本很高:TCP 与 TLS 握手合计可能要 3 个 RTT,跨区域单程延迟常在 50 毫秒以上
- 即使读了也可能不够:encoding/json.Decoder 读到右花括号就停,留在后面的换行会让连接作废
- 过去要手动排空响应体再关闭,而响应很大时排空比新建连接更慢,Go 1.27 把这件事收进标准库
💡 金句
HTTP/1 连接复用里这个细微之处,会让看起来无害的代码悄悄出现性能退化。
👍 0
👎 0
← 返回 Lobsters 首页