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

基于Rocket的reqwest请求转发服务性能瓶颈优化求助

优化方案

先分析你代码里的几个核心问题,这些是高并发下CPU飙升的主要诱因:

  • 每次请求都新建reqwest::Client,重复创建连接池、TLS上下文等资源,极大浪费CPU
  • 串行发送N个请求,任务频繁挂起/唤醒,导致调度器切换开销剧增
  • 不必要的字符串序列化操作,额外消耗CPU资源

以下是具体优化措施:

1. 全局复用reqwest Client

reqwest::Client是线程安全的,设计为长期复用的实例。全局初始化一次,所有请求共用同一个Client,避免重复创建资源:

use lazy_static::lazy_static;
use reqwest::Client;

lazy_static! {
    // 全局初始化Client,启动时创建一次
    static ref HTTP_CLIENT: Client = Client::builder()
        .pool_max_idle_per_host(64) // 配置每个主机的最大空闲连接,减少TCP握手开销
        .build()
        .unwrap();
}

pub async fn handler(data: Json<Value>) {
    let data_str = data.take().to_string();
    for url in urls {
        match HTTP_CLIENT.post(url)
            .header("Content-Type", "application/json")
            .body(data_str.clone())
            .send().await {
                // ... 你的处理逻辑
            }
    }
}

2. 并行发送请求,减少调度切换

原代码串行处理N个请求,每个await都会让当前任务挂起,调度器需要频繁切换。改用join_all并行处理所有请求,大幅减少调度次数:

use futures::future::join_all;

pub async fn handler(data: Json<Value>) {
    let data_bytes = serde_json::to_vec(&data.0).unwrap(); // 提前序列化为字节,减少字符串操作

    // 生成所有请求的future
    let request_futures = urls.into_iter().map(|url| {
        HTTP_CLIENT.post(url)
            .header("Content-Type", "application/json")
            .body(data_bytes.clone())
            .send()
    });

    // 并行等待所有请求完成
    let results = join_all(request_futures).await;

    // 批量处理结果
    for result in results {
        match result {
            Ok(resp) => { /* 处理成功响应 */ },
            Err(e) => { /* 处理错误 */ },
        }
    }
}

如果不需要等待所有请求完成(即“火即忘”场景),可以用tokio::spawn把请求放到后台执行:

pub async fn handler(data: Json<Value>) {
    let data_bytes = serde_json::to_vec(&data.0).unwrap();

    for url in urls {
        let url_clone = url.clone();
        let data_clone = data_bytes.clone();

        // 把请求放到后台任务
        tokio::spawn(async move {
            match HTTP_CLIENT.post(&url_clone)
                .header("Content-Type", "application/json")
                .body(data_clone)
                .send().await {
                    // ... 后台处理结果
                }
        });
    }
}

3. 限制并发请求数

如果N很大,无限制并行会导致大量并发连接,反而增加CPU和网络开销。用Semaphore限制并发数:

use tokio::sync::Semaphore;

lazy_static! {
    static ref CONCURRENCY_SEMAPHORE: Semaphore = Semaphore::new(32); // 限制最多32个并发请求
}

pub async fn handler(data: Json<Value>) {
    let data_bytes = serde_json::to_vec(&data.0).unwrap();

    let request_futures = urls.into_iter().map(|url| {
        // 获取并发许可
        let permit = CONCURRENCY_SEMAPHORE.acquire().await.unwrap();
        let url_clone = url.clone();
        let data_clone = data_bytes.clone();

        async move {
            let _permit = permit; // 持有许可直到请求完成
            HTTP_CLIENT.post(&url_clone)
                .header("Content-Type", "application/json")
                .body(data_clone)
                .send().await
        }
    });

    let results = join_all(request_futures).await;
    // ... 处理结果
}

4. 调整Rocket工作池配置

Rocket默认的工作线程数基于CPU核心数,对于IO密集型任务,适当调高工作线程数可以减少调度压力:

use rocket::config::{Config, Environment};

#[launch]
fn rocket() -> _ {
    let config = Config::builder(Environment::Production)
        .workers(16) // 根据服务器CPU核心数调整,比如核心数*2
        .build()
        .unwrap();

    rocket::custom(config)
        .mount("/", routes![handler])
}

5. 减少序列化开销

原代码把Json<Value>转成String,可以直接序列化为字节数组Vec<u8>,减少字符串操作的CPU消耗:

// 替换原代码中的data.take().to_string()
let data_bytes = serde_json::to_vec(&data.0).unwrap();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 16:10:15