В этой статье я собираюсь сравнить собственный HTTP-сервер Go с Hyper HTTP-сервером Rust. Основываясь на своих исследованиях, я обнаружил, что Hyper - самый популярный сервер на стороне Rust. Если есть лучшие и популярные альтернативы, пожалуйста, дайте мне знать.
Сравнение будет справедливым, поскольку оба являются компилированными языками, которые создают машинный код. Давайте проведем тесты и проверим результаты.
Тестовая настройка
Тесты выполняются на MacBook Pro M1 с 16 ГБ оперативной памяти.
Версии программного обеспечения следующие:
- Go v1.20.2
- Rust v1.68.2
Код HTTP-сервера hello world в обоих случаях выглядит следующим образом:
Go
package main
import (
"io"
"net/http"
)
func main() {
http.HandleFunc("/", helloWorld)
http.ListenAndServe(":3000", nil)
}
func helloWorld(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!")
}
Rust
use std::convert::Infallible;
use std::net::SocketAddr;
use bytes::Bytes;
use http_body_util::Full;
use hyper::server::conn::http1;
use hyper::service::service_fn;
use hyper::{Request, Response};
use tokio::net::TcpListener;
async fn hello(_: Request<hyper::body::Incoming>) -> Result<Response<Full<Bytes>>, Infallible> {
let response = Response::builder()
.header("Content-type", "text/plain")
.body(Full::new(Bytes::from("Hello World!")))
.unwrap();
Ok(response)
}
#[tokio::main]
pub async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let addr: SocketAddr = ([127, 0, 0, 1], 3000).into();
let listener = TcpListener::bind(addr).await?;
loop {
let (stream, _) = listener.accept().await?;
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(stream, service_fn(hello)).await {
println!("Error serving connection: {:?}", err);
}
});
}
}
Cargo.toml
[package]
name = "hello_world"
version = "0.1.0"
edition = "2021"
[dependencies]
bytes = "1"
hyper = { version = "1.0.0-rc.3", features = ["full"] }
tokio = { version = "1", features = ["full"] }
http-body-util = "0.1.0-rc.2"
Код Rust был собран в режиме релиза:
> cargo build --release
...
Compiling hyper v1.0.0-rc.3
Compiling hello_world v0.1.0 (/Users/mayankc/Work/source/perfComparisons/rust)
Finished release [optimized] target(s) in 19.88s
Тестирование
Каждый тест выполняется для 5 миллионов запросов
Тесты выполняются для 10, 100 и 300 одновременных подключений.
Нагрузочный тест выполняется с помощью инструмента HTTP-тестирования Bombardier.
Ниже приведены таблицы, показывающие результаты для каждого уровня параллелизма:
По сравнению со сравнениями с Bun и Deno, на этот раз конкуренция была справедливой, потому что и Go, и Rust являются компилируемыми языками. Они создают машинный код, который выполняется напрямую. Однако с точки зрения производительности Rust превосходит его по всем аспектам.
ПОБЕДИТЕЛЬ: Rust Hyper