Go标准log包因全局锁在高并发下成瓶颈,应改用异步写入:业务goroutine发日志到带缓冲channel,由单独writer goroutine批量落盘;推荐zap或zerolog等无锁高性能库,并辅以内存缓冲、限流丢弃和关键日志直写保底。

避免日志写入成为并发瓶颈
Go 默认的 log 包是线程安全的,但内部用全局互斥锁保护,高并发下大量 goroutine 争抢同一把锁,会导致写日志变慢、甚至拖累主业务。这不是日志内容的问题,而是同步写 + 全局锁的设计在 QPS 上千后明显吃力。
用异步写入解耦日志生产和消费
核心思路是:业务 goroutine 只负责把日志消息发到 channel,由单独的 writer goroutine 串行接收并落盘。这样彻底避开锁竞争,也防止磁盘 I/O 拖慢业务逻辑。
- 定义带缓冲的 channel(如
chan *LogEntry),容量根据峰值日志量预估,避免业务阻塞 - 启动 1 个(或少数几个)后台 goroutine,循环
rangechannel 并批量写文件(减少系统调用次数) - 日志结构体建议包含时间、级别、消息、字段 map 等,便于后续结构化解析
轻量级无锁日志库可直接落地
自己实现 channel + file writer 虽可控,但需处理满载丢日志、崩溃恢复、滚动切割等细节。生产环境更推荐成熟方案:
-
zap(Uber):高性能结构化日志,自带异步模式(
zapcore.NewCore配合zapcore.LockingWriter或自定义WriteSyncer),默认就比标准库快数倍 -
zerolog(rs/zerolog):零内存分配设计,天然适合高并发;通过
io.MultiWriter组合多个输出(如文件 + 控制台),再用os.File自带缓冲或包装成带 buffer 的 writer 即可平滑异步
两者都不依赖全局锁,写入路径无 mutex 竞争,实测在万级 goroutine 下仍保持稳定延迟。
立即学习“go语言免费学习笔记(深入)”;
必要时加内存缓冲与限流保底
纯 channel 异步仍有风险:磁盘卡住、日志突增导致 channel 堵塞或 OOM。建议补充两层防护:
- channel 缓冲区设合理上限(如 1024~8192),超限时用
select+default快速丢弃低优先级日志(如 debug) - 用
sync.Pool复用bytes.Buffer或日志结构体,避免高频 GC - 关键错误日志可绕过异步通道,直写文件(带
os.O_SYNC),确保不丢失
基本上就这些。不复杂但容易忽略的是:别让日志影响主流程,异步是底线,选对库是捷径。










