Go脚本运行与构建报错排查:打开文件过多及文件过大问题
问题分析与解决方案
咱们来逐个拆解你遇到的两个问题,分别分析背后的原因和对应的解决办法:
第一个错误:socket: too many open files
为什么会出现这个错误?
你一次性启动了1700个goroutine并发发起HTTP请求,而每个HTTP连接都会占用一个系统文件描述符(socket本质上也是一种文件描述符)。大多数系统默认的最大打开文件描述符数量(用ulimit -n查看)只有1024左右,远低于你发起的并发请求数。当同时打开的文件描述符超过系统限制时,就会抛出这个错误。
哪怕你把ulimit调到了2048,Go的默认HTTP客户端没有配置连接池和并发限制,依然会瞬间创建大量socket连接——毕竟每个连接从建立到释放需要时间,1700个请求几乎同时抢占资源,很容易再次触发限制。
怎么解决?
- 给HTTP客户端加连接池限制:
自定义http.Transport来控制并发连接数,避免无限制创建socket:import "net/http" import "time" func main() { transport := &http.Transport{ MaxIdleConns: 100, // 全局最大空闲连接数 MaxIdleConnsPerHost: 50, // 针对目标域名的最大空闲连接数 IdleConnTimeout: 30 * time.Second, // 空闲连接超时时间 } client := &http.Client{Transport: transport} // 后续用这个client发起请求 } - 用goroutine池控制并发量:
不要一次性启动1700个goroutine,用带缓冲的channel做信号量,把并发数控制在合理范围(比如50或100):func main() { sem := make(chan struct{}, 50) // 最多同时运行50个goroutine items := []string{/* 你的请求列表 */} for _, item := range items { sem <- struct{}{} // 占用一个并发名额 go func(id string) { defer func() { <-sem }() // 释放并发名额 // 这里执行HTTP请求逻辑,比如用上面配置好的client }(item) } // 等待所有goroutine执行完成 for i := 0; i < cap(sem); i++ { sem <- struct{}{} } } - 确保系统文件描述符限制设置正确:
确认你调整的是打开文件数限制,而不是其他参数:# 临时生效(当前终端会话) ulimit -n 4096 # 永久生效(编辑/etc/security/limits.conf,添加以下两行后重启会话) # * soft nofile 4096 # * hard nofile 4096
第二个错误:write $WORK/.../a.out: file too large
为什么会出现这个错误?
这个问题和你调整ulimit的操作直接相关——大概率是你误修改了文件大小限制(对应ulimit -f参数,单位是KB),导致Go构建时生成的可执行文件超过了这个限制,无法写入临时工作目录。当然也有可能是你的临时分区(比如/tmp)空间不足,但结合你刚调整ulimit的操作,前者的可能性更大。
怎么解决?
- 检查并调整文件大小限制:
先查看当前的文件大小限制:
如果数值很小(比如2048,也就是2MB),就把它调大或者直接取消限制:ulimit -f# 临时取消文件大小限制(当前会话) ulimit -f unlimited # 永久生效的话,编辑/etc/security/limits.conf,添加: # * soft fsize unlimited # * hard fsize unlimited - 检查临时分区空间:
用df -h命令查看/tmp或Go临时工作目录所在分区的剩余空间,如果空间不足,清理临时文件或者扩容对应分区。
内容的提问来源于stack exchange,提问作者Marcin Pietraszek
相关产品推荐
相关产品推荐

