當前位置: 妍妍網 > 碼農

Rust Actix-Web 高效能HTTP伺服器的實作與配置

2024-06-01碼農

Actix-Web是Rust生態系中非常強大的Web框架之一,憑借其高並行性和靈活性,成為了許多開發者首選的Web伺服器框架。在這篇文章中,我們將詳細探討Actix-Web的HTTP伺服器實作,以及如何透過不同的配置選項來最佳化伺服器效能。

HTTP伺服器的基礎實作

在Actix-Web中, HttpServer 型別負責處理HTTP請求。要啟動一個Web伺服器,首先需要將其繫結到網路套接字上。可以使用 HttpServer::bind() 方法繫結到一個套接字地址,例如 ("127.0.0.1", 8080) 或者 "0.0.0.0:8080"

範例程式碼

以下是一個簡單的範例,展示了如何啟動一個Actix-Web伺服器並在根路徑上返回一個「OK」響應:

use actix_web::{web, App, HttpResponse, HttpServer};
#[actix_web::main]
asyncfnmain() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/", web::get().to(HttpResponse::Ok)))
.bind(("127.0.0.1"8080))?
.run()
.await
}

這個例子中,我們透過 HttpServer::new() 方法建立了一個新的伺服器例項,並繫結到 127.0.0.1:8080 。呼叫 HttpServer::run() 方法啟動伺服器,使其開始處理請求。

多執行緒處理

HttpServer 預設會啟動多個HTTP工作執行緒,其數量等於單機的物理CPU核心數。然而,可以透過 HttpServer::workers() 方法來覆蓋這個預設值。例如:

use actix_web::{web, App, HttpResponse, HttpServer};
#[actix_web::main]
asyncfnmain() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/", web::get().to(HttpResponse::Ok)))
.workers(4) // 啟動4個工作執行緒
.bind(("127.0.0.1"8080))?
.run()
.await
}

工作執行緒建立後,每個執行緒將接收一個獨立的套用例項來處理請求。註意,套用狀態在不同執行緒間並不共享,因此處理常式可以自由地操作其狀態而無需考慮並行問題。

對於需要在不同工作執行緒間共享的狀態,可以使用 Arc / Data 來實作。但是,在引入共享和同步機制時需要特別註意,以避免因釘選共享狀態而導致的效能瓶頸。

異步處理

在Actix-Web中,任何長時間的非CPU繫結操作(例如I/O、資料庫操作等)都應該以異步函式或 Future 的形式表達。這樣可以避免工作執行緒因阻塞操作而停止處理新請求。

範例程式碼

同步處理器範例(不推薦):

fnmy_handler() -> impl Responder {
std::thread::sleep(std::time::Duration::from_secs(5)); // 不推薦,會導致當前工作執行緒掛起
"response"
}

異步處理器範例(推薦):

asyncfnmy_handler() -> impl Responder {
tokio::time::sleep(std::time::Duration::from_secs(5)).await// 推薦,工作執行緒可以在此期間處理其他請求
"response"
}

同樣的限制也適用於提取器。當處理常式接收到一個實作 FromRequest 的參數時,如果該實作阻塞了當前執行緒,那麽工作執行緒也會在執行處理常式時被阻塞。因此,在需要的地方應實作異步提取器。

支持TLS/HTTPS

Actix-Web支持兩種TLS實作: rustls openssl 。可以在 Cargo.toml 中指定相應的特性來啟用這些實作。例如,使用 openssl

[dependencies]
actix-web = { version = "4", features = ["openssl"] }
openssl = { version = "0.10" }

範例程式碼

下面是一個啟用HTTPS的範例:

use actix_web::{get, App, HttpRequest, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
#[get("/")]
asyncfnindex(_req: HttpRequest) -> impl Responder {
"Welcome!"
}
#[actix_web::main]
asyncfnmain() -> std::io::Result<()> {
letmut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
HttpServer::new(|| App::new().service(index))
.bind_openssl("127.0.0.1:8080", builder)?
.run()
.await
}

要生成 key.pem cert.pem 檔,可以使用如下命令:

openssl req -x509 -newkey rsa:4096 -nodes -keyout key.pem -out cert.pem -days 365 -subj '/CN=localhost'

Keep-Alive支持

Actix-Web會保持連線開啟以等待後續請求。可以透過伺服器設定來定義Keep-Alive連線行為。例如:

use actix_web::{http::KeepAlive, HttpServer};
use std::time::Duration;
#[actix_web::main]
asyncfnmain() -> std::io::Result<()> {
let server = HttpServer::new(app)
.keep_alive(Duration::from_secs(75)) // 設定Keep-Alive為75秒
.keep_alive(KeepAlive::Os) // 使用作業系統的Keep-Alive設定
.keep_alive(None); // 禁用Keep-Alive
server.run().await
}

使用 HttpResponseBuilder 上的 force_close() 方法可以強制關閉連線:

use actix_web::{http, HttpRequest, HttpResponse};
asyncfnindex(_req: HttpRequest) -> HttpResponse {
letmut resp = HttpResponse::Ok()
.force_close() // 強制關閉連線
.finish();
resp.head_mut().set_connection_type(http::ConnectionType::Close); // 關閉連線
resp
}

優雅的關機處理

Actix-Web支持優雅的關機處理,在接收到關機訊號後,工作執行緒有一定的時間來完成正在處理的請求。超時後,仍然存活的工作執行緒將被強制關閉。可以使用 HttpServer::shutdown_timeout() 方法來修改預設的30秒關機超時設定。

HttpServer::new(...).shutdown_timeout(60); // 設定關機超時為60秒

預設情況下, HttpServer 處理多個作業系統訊號:

  • SIGINT - 強制關閉工作執行緒

  • SIGTERM - 優雅關閉工作執行緒

  • SIGQUIT - 強制關閉工作執行緒

  • 可以透過 HttpServer::disable_signals() 方法來禁用訊號處理。

    以上內容詳細介紹了Actix-Web中的HTTP伺服器實作與多執行緒、異步處理、TLS/HTTPS支持、Keep-Alive以及優雅的關機處理。在實際開發中,合理使用這些特性和配置,可以顯著提高Web伺服器的效能和可靠性。希望這篇文章能夠幫助你更好地理解和使用Actix-Web來構建高效能的Web套用。

    文章精選

    「Rust