You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go HTTP请求出现read: connection reset by peer错误的解决求助

解决Go并发请求中"Connection reset by peer"问题

我查阅了相关解答,将MaxConnsPerHost设置为并发请求数,但仍出现错误:read tcp 127.0.0.1:52517->127.0.0.1:8080: read: connection reset by peer。

客户端代码

package main

import (
    "fmt"
    "io"
    "net/http"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 400; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()

            url := "http://127.0.0.1:8080/sleep"
            rt := http.Transport{
                MaxIdleConns:        400,
                MaxIdleConnsPerHost: 400,
                MaxConnsPerHost:     400,
                IdleConnTimeout:     20 * time.Second,
                DisableKeepAlives:   false,
            }
            client := http.Client{
                Transport: &rt,
            }
            resp, err := client.Get(url)
            if err != nil {
                fmt.Printf("%d Request to [%s] failed, error: %v\n", i, url, err)
                return
            }
            defer resp.Body.Close()

            body, err := io.ReadAll(resp.Body)
            if err != nil {
                fmt.Printf("%d Failed to read response from [%s], error: %v\n", i, url, err)
                return
            }

            fmt.Printf("%d Response from [%s] result: %s\n", i, url, string(body))
        }(i)
    }

    wg.Wait()
}

服务端代码

package main

import (
    "github.com/gin-gonic/gin"
    "time"
)

func main() {
    r := gin.Default()

    r.GET("/sleep", func(c *gin.Context) {
        time.Sleep(10)
        c.JSON(200, gin.H{
            "message": "Slept for 10 seconds",
        })
    })

    r.Run() // listen and serve on 0.0.0.0:8080
}

问题原因与解决方案

核心问题1:客户端每次请求创建新的Transport

当前客户端在每个goroutine里都新建http.Transport实例,导致每个请求使用独立连接池,MaxConnsPerHost的限制完全失效——400个goroutine会同时发起400个独立连接,远超系统或服务端的连接上限,最终触发连接重置。

核心问题2:服务端默认连接数限制

Gin默认的http.Server未调整最大连接数,系统默认文件描述符限制(通常为1024)会导致服务端无法处理过多并发连接,主动重置超出限制的连接。

修复步骤

1. 客户端复用全局Transport

将http.Transport和http.Client提升为全局变量,让所有goroutine复用同一个连接池:

package main

import (
    "fmt"
    "io"
    "net/http"
    "sync"
    "time"
)

// 全局复用的客户端和Transport
var client = &http.Client{
    Transport: &http.Transport{
        MaxIdleConns:        400,
        MaxIdleConnsPerHost: 400,
        MaxConnsPerHost:     400,
        IdleConnTimeout:     20 * time.Second,
        DisableKeepAlives:   false,
    },
}

func main() {
    var wg sync.WaitGroup

    for i := 0; i < 400; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()

            url := "http://127.0.0.1:8080/sleep"
            resp, err := client.Get(url)
            if err != nil {
                fmt.Printf("%d Request to [%s] failed, error: %v\n", id, url, err)
                return
            }
            defer resp.Body.Close()

            body, err := io.ReadAll(resp.Body)
            if err != nil {
                fmt.Printf("%d Failed to read response from [%s], error: %v\n", id, url, err)
                return
            }

            fmt.Printf("%d Response from [%s] result: %s\n", id, url, string(body))
        }(i)
    }

    wg.Wait()
}

2. 调整服务端最大连接数与超时

修改Gin的http.Server配置,增加最大连接数并设置合理超时:

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)

func main() {
    r := gin.Default()

    r.GET("/sleep", func(c *gin.Context) {
        time.Sleep(10 * time.Millisecond) // 修正单位:原代码time.Sleep(10)为纳秒,与注释逻辑不符
        c.JSON(200, gin.H{
            "message": "Slept for 10 milliseconds",
        })
    })

    // 自定义Server配置,提升连接限制
    srv := &http.Server{
        Addr:         ":8080",
        Handler:      r,
        ReadTimeout:  10 * time.Second,
        WriteTimeout: 10 * time.Second,
        MaxHeaderBytes: 1 << 20,
        // 若需更高并发,需配合调整系统文件描述符限制
    }

    if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
        panic(err)
    }
}

3. 调整系统文件描述符限制(必要时)

如果并发数超过系统默认限制,临时调整当前会话的限制:

ulimit -n 4096

或修改系统配置文件(如/etc/security/limits.conf)永久调整。


内容的提问来源于stack exchange,提问作者xmh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 17:35:19