net.Conn 默认缓冲区不匹配业务节奏会导致延迟或系统调用频繁;应按短连接(4096)或长连接(65536)显式设置,并安全复用 sync.Pool 中的 bufio.Reader/Writer,同时正确配置 keepalive 和 SO_REUSEPORT。
net.Conn 的默认读写缓冲区会拖慢高并发连接Go 的 net.Conn 默认使用操作系统级别的 socket 缓冲区(Linux 下通常为 212992 字节),但实际应用中,小包高频场景(如 MQTT 心跳、HTTP/1.1 短连接)容易因缓冲区过大导致延迟毛刺,或过小引发频繁系统调用。关键不是“调大”,而是匹配业务节奏。
SetReadBuffer(4096) 和 SetWriteBuffer(4096),减少内核拷贝开销65536,但需配合 SetNoDelay(false) 启用 Nagle 算法合并小包Accept 后立即调用 SetReadBuffer —— 此时连接可能尚未完成三次握手,部分系统(如 macOS)会静默失败sync.Pool 管理 bufio.Reader/Writer
每次新建 bufio.Reader 或 bufio.Writer 会分配内存并初始化缓冲区,在 QPS 过万时 GC 压力明显。用 sync.Pool 复用是有效解法,但必须注意生命周期边界。
net.Conn 的强引用,否则连接关闭后 Reader/Writer 无法被回收goroutine 内部从 Pool 获取,处理完立即 Put 回池,且不跨连接复用4096,避免不同 size 导致 Pool 内存碎片化var readerPool = sync.Pool{
New: func() interface{} {
return bufio.NewReaderSize(nil, 4096)
},
}
func handleConn(conn net.Conn) {
defer conn.Close()
r := readerPool.Get().(*bufio.Reader)
r.Reset(conn) // 关键:复用前重置底层 io.Reader
// ... 读取逻辑
readerPool.Put(r)
}
SetKeepAlive 和 SetKeepAlivePeriod 的真实生效条件很多服务开启 keepalive 却仍出现“连接被对端静默关闭”,

SetKeepAlive(true) 和 SetKeepAlivePeriod(30 * time.Second),只设前者会使用内核默认值(通常是 2 小时)SetKeepAlivePeriod 调用会被忽略,需改用应用层心跳(如发送 \n)net.ipv4.tcp_fin_timeout 缩短 FIN_WAIT2 时间,keepalive 探测可能在连接真正断开前就超时失败net.Listen 的 SO_REUSEPORT 在 Go 1.19+ 才值得默认启用Go 1.19 之前 SO_REUSEPORT 仅支持 Unix 系统,且需手动封装 syscall;1.19 引入 net.ListenConfig{Control:...} 后才具备跨平台稳定能力。
runtime.GOMAXPROCS ≥ CPU 核心数,否则多 listener 实际仍争抢同一个 OS 线程SO_REUSEPORT 可能打散长连接分布,需压测验证 RTT 波动真正难处理的是连接突发 + 证书协商(如 TLS 握手)叠加时的队列堆积——这时候缓冲区、Pool、keepalive 全得协同调优,而不是单独改某一项。