系统配置优化
Go程序处理大量并发连接时,最容易卡在文件描述符这个瓶颈上。怎么破?两招:一是修改 /etc/security/limits.conf,加上 * soft nofile 65535 和 * hard nofile 65535,或者临时跑一下 ulimit -n 65535 提上限;二是调内核参数,比如把 net.core.somaxconn 和 net.ipv4.tcp_max_syn_backlog 都设成 65535,改完 /etc/sysctl.conf 后执行 sysctl -p 让它生效。

内存方面也别含糊。如果程序吃内存厉害,可以搞个交换文件来缓一缓:sudo fallocate -l 4G /swapfile → chmod 600 /swapfile → mkswap /swapfile → swapon /swapfile,再写到 /etc/fstab 里永久生效。虽然交换空间比物理内存慢,但至少能防止OOM。
Go环境与编译优化
运行环境这块,GOMAXPROCS 是必调的。通过 runtime.GOMAXPROCS(runtime.NumCPU()) 让程序利用所有CPU核心,并发能力直接拉满。
编译时也有很多文章可做。加上 -ldflags="-s -w" 可以去掉调试信息和符号表,二进制体积能缩小10%~30%。如果对性能有极致要求,试试 -gcflags="-N -l" 禁用内联和逃逸分析——高频函数调用场景下,运行速度反而能提升。更骚的操作是启用LTO:-gcflags="-l -N -lto",不过得根据实际压测结果决定。
体积敏感的话,UPX压缩是利器:sudo apt install upx 之后,upx --best --lzma main 可以把二进制再压掉一半以上。代价是启动时多花几十毫秒解压,线上部署通常能接受。
代码级性能优化
代码层面,内存分配是头号敌人。用 sync.Pool 复用短生命周期对象,比如 bufferPool := &sync.Pool{New: func() interface{} { return make([]byte, 1024) }},避免频繁new带来的GC压力。处理大量字符串操作时,优先用 []byte 而非 string,前者底层更轻。
并发设计要克制。goroutine不是越多越好——通过 worker pool 模式限制数量,配合 sync.WaitGroup 管理生命周期,防止主程序提前跑路。channel 用好了是利器,用滥了就是死锁陷阱。
I/O层面,bufio.NewReader/bufio.NewWriter 能大幅减少系统调用次数。算法选型上,map 适合快速查找,slice 适合动态数组,别在循环里做字符串拼接——换成 strings.Builder 性能能提升好几个数量级。
GC调优是门平衡艺术。通过 GOGC 环境变量控制触发频率:默认100%(堆内存翻倍时触发),生产环境设成 export GOGC=200 能减少GC停顿次数。如果对延迟极度敏感,可以暂时 GOGC=off 关闭GC,但必须监控内存——否则很可能直接OOM。
性能分析与监控
所有优化都得靠数据说话。Go内置的pprof是必杀技:导入 _ "net/http/pprof" 并启动HTTP服务,比如 go func() { log.Println(http.ListenAndServe("localhost:6060", nil)) }()。然后通过 go tool pprof https://localhost:6060/debug/pprof/profile 做CPU分析,go tool pprof https://localhost:6060/debug/pprof/heap 看内存分配。生成的可视化火焰图能直接告诉你热点函数在哪,瓶颈在哪——照着改就对了。
