Cargo.toml如下
[package]
name = "hyper_1"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[[bin]]
name = "silverwind"
path = "src/main.rs"
[dependencies]
hyper = { version = "1.2.0", features = ["full"] }
tokio = { version = "1.36.0", features = ["full"] }
hyper-util = { version = "0.1.3", features = ["full"] }
bytes = "1"
http-body-util = { version = "0.1.0"}
anyhow = { version = "1.0.80", default-features = false }
log4rs = "1.3.0"
main.rs如下
use anyhow::anyhow;
use hyper::{server::conn::http1, service::service_fn};
use std::net::SocketAddr;
use tokio::net::TcpListener;
use bytes::Bytes;
use http_body_util::{combinators::BoxBody, BodyExt, Full};
use hyper::body::Incoming;
use hyper::{Request, Response, Uri};
use hyper_util::client::legacy::{connect::HttpConnector, Client};
use hyper_util::rt::TokioIo;
use std::convert::Infallible;
use tokio::runtime;
#[tokio::main]
async fn main() {
if let Err(err) = start_with_error().await {
println!("Failed to serve the connection: {:?}", err);
}
}
async fn check(uri: Uri) -> Result<(), anyhow::Error> {
let backend_path = uri.path_and_query().ok_or(anyhow!(""))?.as_str();
Ok(())
}
async fn do_req(
client: Client<HttpConnector, BoxBody<Bytes, Infallible>>,
req: Request<BoxBody<Bytes, Infallible>>,
) -> Result<Response<BoxBody<Bytes, Infallible>>, Infallible> {
let uri = req.uri().clone();
check(uri)
.await
.map_err(|_| -> Infallible { unreachable!() })?;
let response_incoming = client
.request(req)
.await
.map_err(|_| -> Infallible { unreachable!() })?;
let res = response_incoming
.map(|b| b.boxed())
.map(|item| item.map_err(|_| -> Infallible { unreachable!() }).boxed());
Ok(res)
}
async fn start_with_error() -> Result<(), Box<dyn std::error::Error>> {
let in_addr: SocketAddr = ([0, 0, 0, 0], 6667).into();
let out_addr_clone = "http://backend:8080";
let listener = TcpListener::bind(in_addr).await?;
println!("Listening on http://{}", in_addr);
println!("Proxying on http://{}", out_addr_clone);
let client = Client::builder(hyper_util::rt::TokioExecutor::new()).build(HttpConnector::new());
loop {
let (stream, _) = listener.accept().await?;
let io = TokioIo::new(stream);
let client_clone = client.clone();
let service = service_fn(move |mut req: Request<Incoming>| {
let client_clone1 = client_clone.clone();
let uri_now: hyper::http::uri::Uri = out_addr_clone.parse().unwrap();
*req.uri_mut() = uri_now.clone();
let req = req.map(|item| item.map_err(|_| -> Infallible { unreachable!() }).boxed());
do_req(client_clone1, req)
});
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.preserve_header_case(true)
.title_case_headers(true)
.serve_connection(io, service)
.await
{
println!("Failed to serve the connection: {:?}", err);
}
});
}
}
加了log4rs = "1.3.0"依赖之后,gateway的tps大概是40000。 去除了log4rs = "1.3.0"依赖之后,gateway的tps大概是70000。
tps差的有点多,主要是代码都没变过。代码已经放到https://gist.github.com/lsk569937453/b42a8cfce21bd20c5da8737db1f5a1b1.
1
共 7 条评论, 1 页
评论区
写评论方案1:工程源代码中不使用anyhow这个crates就好了。工程依赖的crates中如果有anyhow这个依赖的话不会有问题
方案2:工程源代码中使用anyhow这个crates且不开启std,并且第三方依赖的crates不能依赖开启std的anyhow。
--
👇
lithbitren: 所以这个最终咋解决啊
所以这个最终咋解决啊
应该不是这个问题,anyhow我换成anyhow = { version = "1.0.70"},还是有同样的问题
查了下你还别说,已经有人提了,是backtrack的问题,https://github.com/dtolnay/anyhow/issues/347
--
👇
Ryan-Git: 去提个 issue?这差距有点大啊。看看火焰图呢
去提个 issue?这差距有点大啊。看看火焰图呢
查到问题了,是由于log4rs引入了anyhow = { version = "1.0.xx"}导致的。由于项目里面还有个依赖delay_timer = "0.11.5"也引入了anyhow = { version = "1.0.xx" }。所以把这两个都排除掉就没有问题了。 至于为什么anyhow会引起性能快速下降,我也不知道。
代码中没有任何地方引用这个库,应该不是库中的代码影响的,我猜是不是加入这个库,导致你其他依赖的版本变化了,而其中某个库的性能有差异,建议对比一下看看