0

0

Go并发HTTP请求中"no such host"错误与文件描述符限制解析

霞舞

霞舞

发布时间:2025-09-20 10:30:02

|

293人浏览过

|

来源于php中文网

原创

Go并发HTTP请求中

在Go语言高并发HTTP请求场景下,当请求量达到一定阈值时,可能会遭遇“lookup [HOST]: no such host”错误。本文将深入探讨该错误并非简单的DNS解析失败,而是操作系统层面的文件描述符(File Descriptor)限制所致。教程将指导读者如何识别并调整系统文件描述符限制,从而有效解决Go应用在高并发网络I/O中的稳定性问题。

Go并发HTTP请求中的“no such host”错误分析

go语言中进行网络编程时,特别是在高并发地发起http请求时,有时会遇到一个令人困惑的错误信息:“lookup www.httpbin.org: no such host”。初看之下,这似乎表明dns解析失败,目标主机无法被识别。然而,当应用程序在低并发场景下运行正常,并且在并发数达到某个临界点(例如1000个以上)时才出现此类错误,问题往往并非出在dns服务器或网络连通性上。

让我们来看一个典型的Go并发请求代码示例:

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "sync" // 引入sync包用于等待所有goroutine完成
)

func get(url string) ([]byte, error) {
    // 建议使用http.DefaultClient或自定义client,此处为示例
    client := &http.Client{}
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        fmt.Printf("Error creating request for %s: %v\n", url, err)
        return nil, err
    }

    res, err := client.Do(req)
    if err != nil {
        // 这里的错误可能就是"no such host"
        fmt.Printf("Error doing request for %s: %v\n", url, err)
        return nil, err
    }
    defer res.Body.Close() // 确保响应体被关闭

    bytes, read_err := ioutil.ReadAll(res.Body)
    if read_err != nil {
        fmt.Printf("Error reading response body for %s: %v\n", url, read_err)
        return nil, read_err
    }

    // fmt.Println(string(bytes)) // 打印内容可能过多,此处注释
    return bytes, nil
}

func main() {
    const parallelNum = 1040 // 模拟高并发数量
    var wg sync.WaitGroup

    fmt.Printf("Starting %d parallel HTTP requests...\n", parallelNum)

    for i := 0; i < parallelNum; i++ {
        wg.Add(1)
        go func(idx int) {
            defer wg.Done()
            url := fmt.Sprintf("http://www.httpbin.org/get?a=%d", idx)
            _, err := get(url)
            if err != nil {
                // 仅打印错误,不中断主程序
            }
        }(i)
    }

    wg.Wait() // 等待所有goroutine完成
    fmt.Println("All requests finished.")
}

在上述代码中,我们明确地调用了 res.Body.Close() 来关闭HTTP响应体。这排除了许多人首先会想到的“不关闭响应体导致资源泄露”的问题。那么,究竟是什么原因导致了“no such host”错误呢?

根源:操作系统文件描述符限制

当Go应用程序发起HTTP请求时,实际上是在底层创建了网络连接(socket)。在类Unix系统中,每个打开的文件、网络连接(socket)、管道等都被抽象为文件描述符(File Descriptor,简称FD)。操作系统对每个进程可以同时打开的文件描述符数量是有限制的。当并发请求数量激增,导致程序尝试打开的文件描述符数量超过系统或用户为该进程设定的上限时,操作系统将拒绝新的资源请求,并可能以各种错误形式体现,其中之一就是Go语言中看到的“no such host”错误,因为它无法为新的网络连接分配必要的资源。

如何检查和调整文件描述符限制

解决这类问题的关键在于检查并调整操作系统的文件描述符限制。

1. 检查当前限制

你可以通过在Shell中运行 ulimit -a 命令来查看当前用户的所有资源限制,其中 -n 选项对应着文件描述符(file descriptors)的限制。

$ ulimit -a
-t: cpu time (seconds)         unlimited
-f: file size (blocks)         unlimited
-d: data seg size (kbytes)     unlimited
-s: stack size (kbytes)        8192
-c: core file size (blocks)    0
-v: address space (kb)         unlimited
-l: locked-in-memory size (kb) unlimited
-u: processes                  709
-n: file descriptors           2560

在上述输出中,file descriptors 行显示了当前用户进程的文件描述符限制。如果这个值(例如2560)低于你的并发请求峰值,那么很可能就是问题的根源。

你也可以单独查询文件描述符的限制:

$ ulimit -n
2560

2. 临时增加限制

为了测试或在当前会话中解决问题,你可以使用 ulimit -n 命令临时提高文件描述符的限制。例如,将其设置为5000:

$ ulimit -n 5000

这个命令通常不会有输出,表示设置成功。你可以再次运行 ulimit -n 来验证:

TextIn Tools
TextIn Tools

是一款免费在线OCR工具,包含文字识别、表格识别,PDF转文件,文件转PDF、其他格式转换,识别率高,体验好,免费。

下载
$ ulimit -n
5000

请注意,这种方式的修改只对当前Shell会话及其子进程有效。一旦关闭当前Shell,限制将恢复为系统默认值。

3. 永久增加限制(Linux系统)

对于生产环境或需要长期运行的服务,建议通过修改系统配置文件来永久性地增加文件描述符限制。这通常涉及编辑 /etc/security/limits.conf 文件。

打开该文件:

sudo nano /etc/security/limits.conf

在文件末尾添加或修改以下行:

*   soft    nofile  65535
*   hard    nofile  65535
  • *: 表示对所有用户生效。你也可以指定特定用户名。
  • soft: 软限制,用户可以自行修改,但不能超过硬限制。
  • hard: 硬限制,普通用户无法超过,只有root用户可以修改。
  • nofile: 指代文件描述符数量。
  • 65535: 你希望设置的新限制值。根据实际需求调整,但通常不应设置过大(如超过百万),因为这也会消耗内核资源。

保存文件后,需要重新登录用户或者重启系统才能使这些更改生效。

注意事项:

  • 在某些系统上,可能还需要编辑 /etc/pam.d/common-session 或 /etc/pam.d/login 文件,确保 pam_limits.so 模块被加载,例如添加 session required pam_limits.so。
  • 对于Systemd管理的进程,你可能还需要在其服务单元文件(.service)中添加 LimitNOFILE 指令,例如:
    [Service]
    LimitNOFILE=65535

    然后重新加载Systemd配置并重启服务:sudo systemctl daemon-reload && sudo systemctl restart your-service-name。

总结

当Go语言应用在高并发场景下遇到“lookup [HOST]: no such host”错误,并且已经确认HTTP响应体已正确关闭时,最常见且隐蔽的原因是操作系统层面的文件描述符限制。通过检查并适当提高 ulimit -n 值,可以有效解决此类问题,确保Go应用在处理大量并发网络连接时能够稳定运行。理解并管理好操作系统的资源限制,是构建健壮、高性能并发应用的关键一环。

相关专题

更多
session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

302

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

704

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

88

2025.08.19

Go中Type关键字的用法
Go中Type关键字的用法

Go中Type关键字的用法有定义新的类型别名或者创建新的结构体类型。本专题为大家提供Go相关的文章、下载、课程内容,供大家免费下载体验。

233

2023.09.06

go怎么实现链表
go怎么实现链表

go通过定义一个节点结构体、定义一个链表结构体、定义一些方法来操作链表、实现一个方法来删除链表中的一个节点和实现一个方法来打印链表中的所有节点的方法实现链表。

442

2023.09.25

go语言编程软件有哪些
go语言编程软件有哪些

go语言编程软件有Go编译器、Go开发环境、Go包管理器、Go测试框架、Go文档生成器、Go代码质量工具和Go性能分析工具等。本专题为大家提供go语言相关的文章、下载、课程内容,供大家免费下载体验。

245

2023.10.13

0基础如何学go语言
0基础如何学go语言

0基础学习Go语言需要分阶段进行,从基础知识到实践项目,逐步深入。php中文网给大家带来了go语言相关的教程以及文章,欢迎大家前来学习。

691

2023.10.26

Go语言实现运算符重载有哪些方法
Go语言实现运算符重载有哪些方法

Go语言不支持运算符重载,但可以通过一些方法来模拟运算符重载的效果。使用函数重载来模拟运算符重载,可以为不同的类型定义不同的函数,以实现类似运算符重载的效果,通过函数重载,可以为不同的类型实现不同的操作。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

187

2024.02.23

桌面文件位置介绍
桌面文件位置介绍

本专题整合了桌面文件相关教程,阅读专题下面的文章了解更多内容。

0

2025.12.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.2万人学习

Git 教程
Git 教程

共21课时 | 2.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号