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

基于Boost.Asio异步连接的HTTP压力测试工具报错排查

问题排查与压测最佳实践

一、代码问题分析

1. 端口耗尽(核心原因)

你遇到的错误码system:52对应Windows系统的ERROR_DUP_NAME,但实际根源是客户端临时端口耗尽。每次请求都新建TCP连接,关闭后端口会进入TIME_WAIT状态(默认持续2分钟),短时间内发起大量顺序请求时,系统可用的临时端口会很快被耗尽,导致无法建立新连接。

2. 不必要的资源频繁创建销毁

每次调用_http方法都会新建io_context,这会带来额外的线程调度和资源初始化开销,长期运行会累积性能损耗。

3. 连接关闭不规范

代码中仅调用stream.close(),未先对socket执行shutdown操作,可能导致TCP连接资源释放不彻底,加重TIME_WAIT的积累。

4. 未实现错误重试逻辑

代码中定义了retries变量但未实际使用,遇到连接错误时直接返回,无法应对临时网络波动。

二、代码修复建议

// 建议将io_context改为全局或类成员,复用而非每次创建
net::io_context g_io;

HttpResponse HttpClientAsyncBase::_http(HttpRequest&& req)
{
    using namespace boost::beast;
    namespace net = boost::asio;
    using tcp = net::ip::tcp;

    HttpResponse res;
    req.prepare_payload();
    boost::beast::error_code ec = {};

    const HOST_INFO host = resolve(req.host(), req.port, req.resolve);

    boost::asio::spawn(g_io, [&](boost::asio::yield_context yield)
    {
        const size_t max_retries = 3;
        size_t retries = 0;

        while (retries < max_retries)
        {
            tcp_stream stream(g_io);
            
            // 启用端口复用,辅助缓解端口耗尽问题
            stream.socket().set_option(tcp::socket::reuse_address(true));
            
            if (req.timeout_seconds == 0) 
                get_lowest_layer(stream).expires_never();
            else 
                get_lowest_layer(stream).expires_after(std::chrono::seconds(req.timeout_seconds));
            
            get_lowest_layer(stream).async_connect(host, yield[ec]);
            if (!ec) break;
            
            retries++;
            // 重试前添加指数退避延迟,避免频繁重试
            net::this_thread::sleep_for(std::chrono::milliseconds(100 * retries));
        }

        if (ec) return;

        http::async_write(stream, req, yield[ec]);
        if (ec)
        {
            // 先shutdown再close,规范释放连接资源
            stream.socket().shutdown(tcp::socket::shutdown_both, ec);
            stream.close();
            return;
        }

        flat_buffer buffer;
        http::async_read(stream, buffer, res, yield[ec]);

        // 规范关闭连接
        stream.socket().shutdown(tcp::socket::shutdown_both, ec);
        stream.close();
    });

    g_io.run();

    if (ec)
        throw boost::system::system_error(ec);

    return std::move(res);
}

三、基于Asio开发压力测试工具的最佳实践

  • 复用核心资源:全局复用io_context和线程池,避免每次请求创建销毁;复用tcp_stream、flat_buffer等对象,减少内存分配开销。
  • 使用HTTP持久连接:开启Keep-Alive,复用已建立的TCP连接,彻底解决端口耗尽问题,同时大幅提升请求效率。可通过req.set(http::field::connection, "keep-alive")设置,需确保服务端支持持久连接。
  • 采用并发请求模式:顺序请求效率极低,压测应使用异步并发模式,通过协程或线程池控制并发数(根据系统资源调整,避免过载)。
  • 优化TCP参数:
    • 客户端设置reuse_address和reuse_port选项,缓解端口压力;
    • 可调整Windows注册表TcpTimedWaitDelay项缩短TIME_WAIT时长,但需谨慎操作,避免影响其他网络服务。
  • 完善错误处理与重试:实现指数退避重试逻辑,区分临时错误(如连接超时)和永久错误(如地址不存在),避免无效重试。
  • 添加监控统计:实时统计请求成功率、平均响应时间、错误分布等指标,便于定位性能瓶颈。
  • 控制请求速率:通过令牌桶等流量控制算法限制请求发送速率,避免瞬间压垮目标服务或客户端系统。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 14:35:35