使用reqwest重复利用连接

4
我需要向同一服务器(我们称之为myapi.com)发出一系列REST调用。目前,我使用Rust库reqwest如下:
  • 我创建一个具有所有默认设置的reqwest :: Client
  • 对于每个REST调用:
    • 我使用client.post("https://myapi.com/path/to/the/api")创建一个reqwest::RequestBuilder
    • 我配置RequestBuilder以获得reqwest::Request
    • send()请求,读取reqwest::Response
    • 我删除除Client之外的所有内容,并重新开始。
我在文档中看到reqwest应该在同一Client内池化连接。鉴于我始终重用相同的Client,我期望第一个API调用需要更长时间(由于初始TCP和HTTPS握手)。然而,我观察到所有请求都具有一致的相当高的延迟。因此,我想知道是否根本没有重用连接,还是每次重新建立连接。如果没有,我该如何回收相同的连接?我觉得如果我能省略一些往返旅行,延迟会显着减少。

2
你不能在服务器上跟踪已接受的TCP连接,或者使用tcpdump/wireshark来检测SYN/FIN段吗?(只是为了确保在重构代码之前这些多个连接实际上发生了) - prog-fh
这是一个非常好的观点!不幸的是,服务器不是我的。我对低级网络并不是很专业,你能详细说明一下你提出的wireshark策略吗? - Matteo Monti
1个回答

0

行为取决于您使用的是reqwest::blocking::Client(同步)还是reqwest::Client(异步)。

是否重用现有连接可以通过启用调试日志来检查。

reqwest::blocking::Client

当使用同步API时,仅重用客户端即意味着重用连接。

这是因为,在第二次(或第三次或更多次)使用客户端时,保证第一次调用已完成并且我们有一个连接。

use std::env;

use reqwest::blocking::Client;

fn main() {
    env::set_var("RUST_LOG", "debug");
    env_logger::init();

    let client = Client::new();
    for _ in 0..3 {
        //calls an API which returns a random string
        let res = client
            .get("https://ciprand.p3p.repl.co/api?len=10&count=1")
            .send()
            .unwrap();
        println!("{}", res.text().unwrap());
    }
}

[2023-05-17T07:11:13Z DEBUG reqwest::connect] starting new connection: https://ciprand.p3p.repl.co/
{"Strings":["fa749eda765"],"Count":1,"Length":10}
{"Strings":["dd0a8bfdc57"],"Count":1,"Length":10}
{"Strings":["cdedd8e3982"],"Count":1,"Length":10}

(只有一个“starting new connection”被打印。)

reqwest::Client

当使用异步API时,仅重用客户端并不意味着重用连接。

这是因为在第二次(或第三次或更多次)使用客户端时,不能保证第一次调用已经完成并且我们拥有一个连接。

(以下代码仅用于实验目的:永远不要编写这样的异步代码。)

use std::{env, sync::Arc};

use reqwest::Client;

async fn call(url: &str, client: Arc<Client>) {
    client.get(url).send().await.unwrap();
    println!("completed");
}

#[tokio::main]
async fn main() {
    env::set_var("RUST_LOG", "debug");
    env_logger::init();

    let client = Arc::new(Client::new());

    for _ in 0..2 {
        tokio::spawn(call(
            "https://ciprand.p3p.repl.co/api?len=10&count=1",
            client.clone(),
        ));
    }

    std::thread::sleep(std::time::Duration::from_millis(1000));

    for _ in 0..2 {
        tokio::spawn(call(
            "https://ciprand.p3p.repl.co/api?len=10&count=1",
            client.clone(),
        ));
    }

    std::thread::sleep(std::time::Duration::from_millis(1000));
}

[2023-05-17T07:14:25Z DEBUG reqwest::connect] starting new connection: https://ciprand.p3p.repl.co/
[2023-05-17T07:14:25Z DEBUG reqwest::connect] starting new connection: https://ciprand.p3p.repl.co/
completed
completed
completed
completed

(只有两个starting new connection被打印出来。这是因为,在第三次和第四次使用客户端时,第一次(或者可能是第二次)调用已经偶然地完成并且我们已经建立了连接。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接