Golang中解决目标机器主动拒绝连接的问题

Golang中解决目标机器主动拒绝连接的问题 我正在运行一个压力测试。假设我有两个服务 A 和 B。服务 A 正在向服务 B 发送请求。服务 A 在一个循环中发送大约 50000 次请求,并且请求是在单独的协程中调用的,以便后续请求能快速发送。在发送了大约 5000 个请求后,服务 A 开始收到“connectex: 无法建立连接,因为目标计算机主动拒绝它。”的错误。是什么限制导致了这个问题?有没有办法在操作系统或服务级别提高这个限制?

如果您需要更清晰的说明,请告诉我。

1 回复

更多关于Golang中解决目标机器主动拒绝连接的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这个问题通常是由于操作系统层面的网络连接限制导致的,特别是当服务A快速创建大量TCP连接时。在Windows系统上,默认的临时端口范围有限,且TIME_WAIT状态会占用端口资源。

以下是关键限制和解决方案:

1. 操作系统限制

  • 临时端口耗尽:Windows默认临时端口范围约16384个(49152-65535)
  • TIME_WAIT状态:连接关闭后端口会处于TIME_WAIT状态(默认240秒)

2. Go代码优化示例

package main

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

// 使用连接池和HTTP客户端复用
func optimizedClient() {
    // 创建自定义Transport,复用连接
    transport := &http.Transport{
        MaxIdleConns:        1000,      // 最大空闲连接数
        MaxIdleConnsPerHost: 1000,      // 每个主机最大空闲连接数
        IdleConnTimeout:     90 * time.Second,
        DisableKeepAlives:   false,     // 启用keep-alive
    }

    client := &http.Client{
        Transport: transport,
        Timeout:   30 * time.Second,
    }

    var wg sync.WaitGroup
    semaphore := make(chan struct{}, 1000) // 限制并发数

    for i := 0; i < 50000; i++ {
        wg.Add(1)
        semaphore <- struct{}{}
        
        go func(reqNum int) {
            defer wg.Done()
            defer func() { <-semaphore }()

            resp, err := client.Get("http://service-b:8080/api")
            if err != nil {
                // 处理错误,考虑重试逻辑
                return
            }
            defer resp.Body.Close()
            
            // 处理响应
        }(i)
    }
    
    wg.Wait()
}

3. 操作系统级调整(Windows)

增加临时端口范围:

# 查看当前设置
netsh int ipv4 show dynamicport tcp

# 设置临时端口范围(1024-65535)
netsh int ipv4 set dynamicport tcp start=1024 num=64511
netsh int ipv6 set dynamicport tcp start=1024 num=64511

调整TIME_WAIT设置:

# 修改注册表减少TIME_WAIT时间(秒)
reg add HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters /v TcpTimedWaitDelay /t REG_DWORD /d 30

4. 服务级别优化

// 使用连接复用和优雅关闭
type ServiceClient struct {
    client *http.Client
    mu     sync.RWMutex
}

func NewServiceClient() *ServiceClient {
    return &ServiceClient{
        client: &http.Client{
            Transport: &http.Transport{
                MaxIdleConns:        1000,
                MaxIdleConnsPerHost: 1000,
                MaxConnsPerHost:     1000,
                IdleConnTimeout:     90 * time.Second,
            },
            Timeout: 30 * time.Second,
        },
    }
}

// 批量处理请求
func (sc *ServiceClient) SendBatchRequests(urls []string) {
    batchSize := 1000
    for i := 0; i < len(urls); i += batchSize {
        end := i + batchSize
        if end > len(urls) {
            end = len(urls)
        }
        
        batch := urls[i:end]
        sc.processBatch(batch)
        time.Sleep(100 * time.Millisecond) // 批次间延迟
    }
}

5. 监控和诊断

// 添加连接状态监控
func monitorConnections() {
    // 使用netstat或自定义计数器监控连接状态
    // 可以集成prometheus指标
    var (
        activeConns int64
        failedConns int64
    )
    
    // 在请求函数中更新这些指标
}

主要解决方案是:1)优化Go代码使用连接复用,2)调整操作系统网络参数,3)实施适当的并发控制。Windows系统需要特别注意临时端口范围限制。

回到顶部