Go 项目高并发、多线程、IO 查询场景常见问题清单
一、高并发场景常见问题
高并发场景的核心矛盾是 “资源供给” 与 “请求压力” 不匹配,以及 “并发控制” 不当导致的系统稳定性问题,具体包括以下 12 类:
1. 资源耗尽类问题
1.1 Goroutine 泄漏:无退出机制的 Goroutine 持续堆积(如未监听
context.Done()
、Channel 永久阻塞),最终耗尽系统线程资源,导致新请求无法创建 Goroutine。1.2 内存溢出(OOM):
高频创建临时对象(如循环内创建
[]byte
、string
)且未复用,GC 来不及回收;全局缓存未设置过期策略,缓存数据持续堆积(如用
map
存热点数据无清理逻辑);大文件 / 大请求体未分片处理,一次性加载到内存(如读取 1GB 文件直接
ioutil.ReadFile
)。
1.3 文件句柄(FD)耗尽:
未关闭 IO 资源(如
os.File
、net.Conn
、数据库连接未Close()
);并发请求量超系统 FD 上限(默认 Linux 单进程 FD 上限为 1024,高并发下需手动调整)。
1.4 端口耗尽:客户端高频发起短连接(如每次请求创建新 HTTP 连接),未复用连接池,导致本地端口被占满,无法建立新连接。
2. 并发控制类问题
2.1 无并发限制导致 “请求风暴”:
循环内无限制创建 Goroutine(如
for _, task := range tasks { go handle(task) }
),瞬间创建上万 Goroutine,CPU 上下文切换开销剧增;未限制数据库 / Redis 并发连接数,导致下游服务连接池满,拒绝新请求。
2.2 锁竞争与死锁:
过度使用
sync.Mutex
,多 Goroutine 同时竞争同一把锁(如全局锁保护高频读写的map
),导致 CPU 空转;锁顺序不当(如 Goroutine1 先锁 A 再锁 B,Goroutine2 先锁 B 再锁 A),触发死锁;
未释放锁(如
defer mu.Unlock()
遗漏,或锁内panic
未捕获,导致锁永久占用)。
2.3 数据竞争(Data Race):
共享变量未加锁直接并发读写(如全局
count
变量被多 Goroutinecount++
);错误使用 “无锁编程”(如依赖
atomic
操作但逻辑不完整,导致数据不一致)。
2.4 并发安全容器使用不当:
用非并发安全容器存共享数据(如
map
而非sync.Map
,slice
并发 append 导致内存越界);sync.Map
滥用(低频读写场景用sync.Map
,反而因底层锁机制降低性能)。
3. 性能损耗类问题
3.1 CPU 上下文切换频繁:
Goroutine 数量远超 CPU 核心数(如 1000 核 CPU 跑 10 万 Goroutine),内核频繁切换 Goroutine 上下文,CPU 利用率从 100% 降至 30% 以下;
频繁使用
channel
传递小数据(如每秒百万次chan int
通信),触发大量用户态与内核态切换。
3.2 GC 频繁与 STW(Stop The World):
短时间创建大量临时对象(如 HTTP handler 内每次请求创建新的
json.Decoder
),GC 触发间隔缩短至毫秒级;大对象分配(如单次分配 100MB 内存),导致 GC 标记 / 清理阶段耗时过长,STW 时间超 100ms,影响服务响应。
4. 资源调度与分配问题
4.1 内存分配不均(堆内存碎片化):
高频分配 / 释放大小不一的堆内存(如时而分配 1KB、时而分配 100KB),导致堆内存碎片化,GC 无法有效回收空闲内存,即使总空闲内存充足,仍触发 OOM;