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

基于boost::beast的低延迟HTTP请求性能优化方案问询

低延迟HTTP请求优化咨询

背景

正在构建低延迟项目,快速发送HTTP请求是核心环节。当前基于Boost.Beast实现的HTTP客户端平均延迟在10-20微秒,目标是优化至个位数微秒级别,运行环境为AWS搭载Intel Xeon 3GHz处理器的虚拟机。

当前实现代码

#include <thread>
#include <iostream>
#include <coroutine>
#include <optional>
#include <variant>
#include <vector>
#include <utility>
#include <string>
#include <chrono>

#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/json.hpp>
#include <boost/beast.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ssl/context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/coroutine/all.hpp>
#include <boost/beast/ssl/ssl_stream.hpp>
#include <boost/beast/core/tcp_stream.hpp>
#include <boost/beast/core/flat_static_buffer.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/http/string_body.hpp>
#include <boost/beast/http/verb.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/detached.hpp>

class http_client {
private:
    using response = boost::beast::http::response<boost::beast::http::string_body>;

    std::string http_hostname;
    std::string ip_address;
    boost::asio::ssl::context ssl_context;
    boost::asio::ip::tcp::resolver hostname_resolver;
    std::optional<boost::beast::ssl_stream<boost::beast::tcp_stream>> tcp_stream;
    boost::beast::flat_static_buffer<4 * 1024 * 1024> receive_flat_buffer;
public:
    http_client(const std::string& http_name, boost::asio::io_context& io_context) :
        http_hostname(http_name),
        ssl_context(boost::asio::ssl::context::tlsv12_client),
        hostname_resolver(io_context),
        tcp_stream(boost::beast::ssl_stream<boost::beast::tcp_stream>(io_context, ssl_context)),
        receive_flat_buffer()
    {

        ssl_context.set_verify_mode(boost::asio::ssl::verify_peer);
        ssl_context.set_options(
            boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 |
            boost::asio::ssl::context::no_sslv3 | boost::asio::ssl::context::single_dh_use);

        if (!SSL_set_tlsext_host_name(tcp_stream->native_handle(), http_hostname.c_str())) {
            boost::beast::error_code error_code{static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()};
            throw boost::beast::system_error{error_code};
        }

        auto const resolved_endpoint = hostname_resolver.resolve(http_hostname, "443");
        ip_address = resolved_endpoint->endpoint().address().to_string();

        boost::beast::get_lowest_layer(tcp_stream.value()).connect(resolved_endpoint);
        boost::beast::get_lowest_layer(tcp_stream.value()).socket().set_option(boost::asio::socket_base::keep_alive(true));
        boost::beast::get_lowest_layer(tcp_stream.value()).socket().set_option(boost::asio::ip::tcp::no_delay(true));

        std::cout << "Connected to REST endpoint at IP address <\"" << ip_address << "\"> which was resolved from <\"" << resolved_endpoint->host_name() << std::endl;
        tcp_stream->handshake(boost::asio::ssl::stream_base::client);
    }


    void send_request(boost::asio::io_context& io_context, const std::string& target, const std::function<void(response)>& callback) {
        boost::asio::spawn(
            io_context, [target = std::move(target), callback = std::move(callback), this](boost::asio::yield_context yield_context) mutable
            {
                boost::beast::http::request<boost::beast::http::string_body> http_request{
                    boost::beast::http::verb::get,
                    target,
                    11};

                http_request.set(boost::beast::http::field::host, http_hostname);
                http_request.set(boost::beast::http::field::content_type, "application/json");
                http_request.set(boost::beast::http::field::connection, "Keep-Alive");
                http_request.set(boost::beast::http::field::keep_alive, "timeout=86400");
                http_request.keep_alive(true);
                http_request.prepare_payload();

                size_t bytes_transferred = boost::beast::http::async_write(tcp_stream.value(), http_request, yield_context);

                response http_response;
                boost::beast::http::async_read(tcp_stream.value(), receive_flat_buffer, http_response, yield_context);

                callback(http_response);
            }
        );
    }
};

int main() {
    boost::asio::io_context io_context{};

    std::string host_name{"fapi.binance.com"};
    http_client client(host_name, io_context);

    for (int i = 0; i < 100; i++) {
        auto const stime = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
        client.send_request(io_context, "/fapi/v1/time", [&](boost::beast::http::response<boost::beast::http::string_body> const& http_response) {});

        auto const etime = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
        std::cout << "time diff = " << etime - stime << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    io_context.run();

    return 0;
}

编译选项

g++ -std=c++20 -O2 -flto -g beast_http_client.cpp -I/home/dev/vcpkg/installed/x64-linux/include -L/home/dev/vcpkg/installed/x64-linux/lib -lboost_system -lboost_coroutine -lboost_thread -lboost_json -lssl -lcrypto -lboost_context

性能优化建议

1. 替换Boost.Beast为极简HTTP实现

Boost.Beast是通用HTTP库,包含大量适配逻辑和错误处理,对低延迟场景冗余。可以直接基于Boost.Asio的SSL/TCP流手动构造HTTP请求:

  • 预构造固定格式的GET请求头字符串(比如针对/fapi/v1/time的请求,所有字段都是固定的),避免每次请求动态构建
  • 直接调用async_write发送预构造好的字节流,跳过Beast的request对象封装
  • 响应解析只做必要的处理(比如读取状态码和响应体长度),不需要完整的HTTP响应对象解析

2. 消除动态内存分配

  • 将请求缓冲区、响应缓冲区设为类成员静态变量,复用内存,避免每次请求分配/释放
  • 预构造HTTP请求头为字符数组,避免std::string的动态内存操作
  • 移除std::function回调,改用编译期绑定的函数对象或直接内联处理逻辑,减少虚函数调用和内存分配

3. 优化协程与调度

  • 避免每次send_request都spawn新协程:因为是单连接Keep-Alive,串行发送请求更高效,可以用一个持久协程处理所有请求,通过队列传递任务
  • 改用C++20原生协程(std::awaitable)替代Boost.Coroutine,减少Boost库的额外开销
  • 确保io_context的线程数与CPU核心匹配(当前单线程,Xeon虚拟机可设为1或2线程,避免上下文切换)

4. 网络参数调优

  • 缓存DNS解析结果:当前构造函数已做,但要确保不会重复解析
  • 调整TCP缓冲区大小:设置SO_RCVBUF和SO_SNDBUF为64KB或128KB(根据MTU和网络环境),减少系统调用次数
  • 启用TCP_FASTOPEN:如果服务器支持,在socket上设置该选项,减少TCP握手延迟
  • 确认SSL会话复用:启用SSL会话缓存,避免每次重新握手(当前代码用的是长连接,SSL握手只做一次,这部分已经优化,但可确认ssl_context是否开启会话复用)

5. 编译选项强化

  • 移除-g调试符号,减少运行时内存开销和二进制大小
  • 添加-march=native,让编译器针对Intel Xeon架构生成最优指令
  • 改用-O3优化级别,开启更多编译器优化(注意测试兼容性,避免优化带来的逻辑问题)
  • 添加-fno-rtti和-fno-exceptions(如果代码可以适配),消除RTTI和异常处理的运行时开销
  • 保留-flto链接时优化,进一步提升二进制执行效率

6. 精确延迟测量

  • 当前代码测量的是send_request函数的调用时间,不是真实的请求往返延迟。应将计时起点放在请求发送前,终点放在响应接收完成后的回调中,准确统计从发送到收到响应的时间
  • 使用std::chrono::high_resolution_clock(比system_clock更精确)或rdtsc指令进行计时,避免系统时钟的误差

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 22:07:03