Rust สำหรับเว็บ: เปรียบเทียบ Actix Web กับ Axum และคำถามสัมภาษณ์ 2026

การเปรียบเทียบเชิงปฏิบัติของ Actix Web 4.14 และ Axum 0.8 สำหรับการพัฒนาเว็บ Rust ในปี 2026 สถาปัตยกรรม, benchmark TechEmpower Round 23, ประสบการณ์นักพัฒนา และคำถามสัมภาษณ์สำหรับตำแหน่ง backend Rust

เปรียบเทียบ Rust Actix Web กับ Axum

การนำ framework เว็บ Rust มาใช้เพิ่มขึ้นอย่างรวดเร็วในปี 2026 และมีสอง framework ที่ครองการ deploy บน production: Actix Web 4.14 และ Axum 0.8 การเลือกระหว่างทั้งสองส่งผลต่อทุกอย่างตั้งแต่การ onboard ทีมไปจนถึง throughput บน production และคำถามนี้มักปรากฏในการสัมภาษณ์ backend Rust

กรอบการตัดสินใจอย่างรวดเร็ว

Actix Web 4.14 นำหน้าใน raw throughput (10-15% request/วินาทีมากกว่าภายใต้ภาระหนัก) Axum 0.8 ให้ ergonomi ที่ดีกว่าผ่าน native async traits, ความสามารถในการประกอบ middleware ของ Tower และการบูรณาการกับ Tokio ที่แน่นแฟ้นกว่า สำหรับทีมส่วนใหญ่ที่เริ่มโปรเจกต์ใหม่ในปี 2026 Axum เป็นตัวเลือกที่เป็นรูปธรรม เว้นแต่ความต้องการ throughput สูงสุดจะกำหนดเป็นอย่างอื่น

ความแตกต่างด้านสถาปัตยกรรมระหว่าง Actix Web และ Axum

ความแตกต่างด้านสถาปัตยกรรมระหว่างสอง framework นี้อธิบายการแลกเปลี่ยนด้านประสิทธิภาพและ ergonomi ส่วนใหญ่

Actix Web รัน N runtime Tokio แบบ single-threaded หนึ่งตัวต่อ core กายภาพหนึ่งตัว Task ถูกตรึงกับ thread โดยไม่มีการย้ายข้อมูลข้าม thread สิ่งนี้ขจัด overhead ของ work-stealing และ cache-line bouncing ซึ่งอธิบายข้อได้เปรียบด้าน throughput ที่สม่ำเสมอภายใต้ภาระต่อเนื่อง

Axum รันบน runtime Tokio แบบ multi-threaded เดียวที่มี work-stealing ทีม Tokio สร้าง Axum โดยเฉพาะเพื่อแสดงความสามารถของ runtime ดังนั้นการตัดสินใจออกแบบทุกอย่างจึงปรับให้เหมาะสมสำหรับการประกอบกับระบบนิเวศ Tokio ที่กว้างขึ้น Handler เป็นฟังก์ชัน async ธรรมดา และ middleware ใช้ trait Service ของ Tower

actix_hello.rs - Actix Web minimal serverrust
use actix_web::{web, App, HttpServer, HttpResponse};

async fn health() -> HttpResponse {
    HttpResponse::Ok().json(serde_json::json!({ "status": "ok" }))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new()
            .route("/health", web::get().to(health))
    })
    .bind("0.0.0.0:8080")?
    .run()
    .await
}
axum_hello.rs - Axum minimal serverrust
use axum::{Router, Json, routing::get};
use serde_json::{json, Value};

async fn health() -> Json<Value> {
    Json(json!({ "status": "ok" }))
}

#[tokio::main]
async fn main() {
    let app = Router::new()
        .route("/health", get(health));

    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}

ตัวอย่างทั้งสองสามารถคอมไพล์และรันได้ แต่ความแตกต่างเห็นได้ชัดแล้ว Actix Web ใช้ macro #[actix_web::main] ของตัวเองและคืนค่า std::io::Result Axum ใช้ #[tokio::main] มาตรฐานและสร้าง route ผ่าน struct Router Handler ของ Axum คืนค่า typed extractor (Json<Value>) แทนที่จะสร้าง HttpResponse ด้วยตนเอง

Benchmark ประสิทธิภาพ: Actix Web 4.14 vs Axum 0.8

ข้อมูล benchmark จาก TechEmpower Round 23 (มกราคม 2026) ให้การเปรียบเทียบที่เชื่อถือได้ที่สุด ทั้งสอง framework อยู่ใน tier สูงสุดในทุกหมวดหมู่

ตัวชี้วัดActix Web 4.14Axum 0.8.9
Plaintext (req/s)~7,100,000~6,200,000
JSON serialization (req/s)~1,200,000~1,050,000
DB single query (req/s)~190,000~175,000
Memory usage (hello world)~8 MB~6 MB
P99 latency (JSON)1.1 ms1.3 ms

Actix Web รักษาข้อได้เปรียบด้าน throughput 10-15% ในทุกหมวดหมู่ Axum ใช้หน่วยความจำน้อยกว่าเล็กน้อยเนื่องจาก shared Tokio runtime เพื่อเป็นบริบท ทั้งสอง framework มีประสิทธิภาพเหนือกว่า HTTP server มาตรฐานของ Go 2-3 เท่าและ Node.js 5-8 เท่าบน hardware ที่เทียบเท่ากัน

ช่องว่างด้านประสิทธิภาพมีความสำคัญสำหรับ ad serving, pipeline วิเคราะห์แบบ real-time และ gateway สำหรับการเทรดความถี่สูง สำหรับ REST API ทั่วไปที่ให้บริการ 10,000 request/วินาที ทั้งสอง framework อยู่ไกลเกินคอขวด ซึ่งจะเป็น database หรือการเรียกบริการภายนอก

เปรียบเทียบ Extractor และการจัดการ Request

Extractor กำหนดวิธีที่ framework แยกวิเคราะห์ request ที่เข้ามา Axum 0.8 ทำการปรับปรุงที่สำคัญตรงนี้โดยการลบ #[async_trait] เพื่อใช้ native async traits และแนะนำ OptionalFromRequestParts สำหรับการจัดการ Option<T> ที่ดีขึ้น

axum_extractors.rs - Axum 0.8 extractor patternrust
use axum::{
    extract::{Path, Query, State, Json},
    routing::get,
    Router,
};
use serde::Deserialize;
use std::sync::Arc;

#[derive(Deserialize)]
struct Pagination {
    page: Option<u32>,    // defaults to None if missing
    per_page: Option<u32>,
}

// State shared across handlers
struct AppState {
    db_pool: sqlx::PgPool,
}

// Axum 0.8: /{id} syntax (replaced /:id)
async fn get_user(
    State(state): State<Arc<AppState>>,
    Path(user_id): Path<i64>,
    Query(pagination): Query<Pagination>,
) -> Json<serde_json::Value> {
    let page = pagination.page.unwrap_or(1);
    // Query database using state.db_pool
    Json(serde_json::json!({
        "user_id": user_id,
        "page": page
    }))
}
actix_extractors.rs - Actix Web extractor patternrust
use actix_web::{web, HttpResponse};
use serde::Deserialize;

#[derive(Deserialize)]
struct Pagination {
    page: Option<u32>,
    per_page: Option<u32>,
}

struct AppState {
    db_pool: sqlx::PgPool,
}

async fn get_user(
    state: web::Data<AppState>,
    path: web::Path<i64>,
    query: web::Query<Pagination>,
) -> HttpResponse {
    let user_id = path.into_inner();
    let page = query.page.unwrap_or(1);
    HttpResponse::Ok().json(serde_json::json!({
        "user_id": user_id,
        "page": page
    }))
}

Extractor ของ Axum ใช้ tuple destructuring โดยตรงใน parameter ของฟังก์ชัน Actix Web ห่อทุกอย่างใน web::Path, web::Query เป็นต้น ซึ่งต้องเรียก .into_inner() ทั้งสองวิธีเป็น type-safe ในเวลาคอมไพล์ แต่วิธีของ Axum อ่านได้เป็นธรรมชาติกว่า

การเปลี่ยนแปลง Breaking ของ Axum 0.8

Path parameter เปลี่ยนจาก syntax /:id เป็น /{id} ใน Axum 0.8 (ผ่าน matchit 0.8) ซึ่งสอดคล้องกับ path syntax ของ OpenAPI การ escape ใช้วงเล็บปีกกาคู่: {{ สำหรับ { แบบ literal

สถาปัตยกรรม Middleware: Tower vs Actix Middleware

การประกอบ middleware เป็นจุดที่ความแตกต่างด้านสถาปัตยกรรมสร้างผลกระทบในทางปฏิบัติมากที่สุด

Axum ใช้ trait Service และ Layer ของ Tower middleware ใด ๆ ที่เข้ากันได้กับ Tower ทำงานกับ Axum รวมถึง rate limiter, tracing, compression และ layer การยืนยันตัวตนที่สร้างขึ้นสำหรับบริการอื่น ๆ ที่ใช้ Tower ความสามารถในการประกอบนี้ขยายเกินกว่า HTTP; middleware เดียวกันสามารถห่อบริการ gRPC ผ่าน Tonic

axum_middleware.rs - Tower middleware compositionrust
use axum::{
    Router, middleware,
    routing::get,
    extract::Request,
    response::Response,
};
use tower_http::{
    cors::CorsLayer,
    compression::CompressionLayer,
    trace::TraceLayer,
};
use std::time::Instant;

// Custom middleware as a plain async function
async fn timing_middleware(
    request: Request,
    next: middleware::Next,
) -> Response {
    let start = Instant::now();
    let response = next.run(request).await;
    let duration = start.elapsed();
    tracing::info!("Request took {:?}", duration);
    response
}

fn build_router() -> Router {
    Router::new()
        .route("/api/data", get(|| async { "ok" }))
        .layer(middleware::from_fn(timing_middleware))
        .layer(CompressionLayer::new())
        .layer(CorsLayer::permissive())
        .layer(TraceLayer::new_for_http())
}

Actix Web ใช้ระบบ middleware ของตัวเองด้วย trait Transform และ Service (ไม่ใช่ของ Tower) Middleware จากระบบนิเวศ Tower ที่กว้างกว่าต้องใช้ adapter หรือเขียนใหม่

สำหรับทีมที่ลงทุนในระบบนิเวศ Tower ผ่าน Tonic (gRPC) หรือ Hyper แล้ว middleware ของ Axum เป็นข้อได้เปรียบที่สำคัญ สำหรับทีมที่สร้างบริการ HTTP แบบ standalone ระบบ middleware ของ Actix Web มีความสามารถเท่าเทียมกัน เพียงแต่ไม่สามารถสลับใช้แทนกันได้

Actix Web 4.14 แนะนำการตรวจสอบ route middleware ที่ panic ถ้า handler ถูกเพิ่มหลังจากห่อ middleware ซึ่งจับข้อผิดพลาดการกำหนดค่าที่ startup แทนที่จะเป็น runtime

พร้อมที่จะพิชิตการสัมภาษณ์ Rust แล้วหรือยังครับ?

ฝึกฝนด้วยตัวจำลองแบบโต้ตอบ, flashcards และแบบทดสอบเทคนิคครับ

การบูรณาการ Database ด้วย SQLx

ทั้งสอง framework ทำงานร่วมกับ SQLx ได้ดี ซึ่งเป็น toolkit SQL แบบ async-first ที่ตรวจสอบ query ในเวลาคอมไพล์ รูปแบบการบูรณาการแตกต่างกันเล็กน้อย

shared_db.rs - SQLx with compile-time query validationrust
use sqlx::PgPool;

// This struct works identically with Actix Web and Axum
#[derive(sqlx::FromRow, serde::Serialize)]
struct User {
    id: i64,
    email: String,
    created_at: chrono::NaiveDateTime,
}

// sqlx::query_as! validates against a live DB at compile time
async fn find_user_by_email(
    pool: &PgPool,
    email: &str,
) -> Result<Option<User>, sqlx::Error> {
    sqlx::query_as!(
        User,
        "SELECT id, email, created_at FROM users WHERE email = $1",
        email
    )
    .fetch_optional(pool)
    .await
}

layer database ยังคงเหมือนกันไม่ว่าจะเลือก framework ใด macro query_as! ของ SQLx เชื่อมต่อกับ database แบบ live ในเวลาคอมไพล์และตรวจสอบชื่อคอลัมน์ ชนิดข้อมูล และการมีอยู่ของตาราง การพิมพ์ชื่อคอลัมน์ผิดทำให้เกิด error คอมไพล์ ไม่ใช่ crash ตอน runtime

เปรียบเทียบรูปแบบการจัดการ Error

การจัดการ error เผยให้เห็นปรัชญาการออกแบบที่แตกต่างกัน Actix Web ใช้การ implement trait ResponseError Axum พึ่งพา IntoResponse รวมกับชนิด Result

axum_errors.rs - Axum error handling with IntoResponserust
use axum::{
    http::StatusCode,
    response::{IntoResponse, Response},
    Json,
};

// Define application-level errors
enum AppError {
    NotFound(String),
    DatabaseError(sqlx::Error),
    ValidationError(String),
}

// Convert errors into HTTP responses
impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let (status, message) = match self {
            AppError::NotFound(msg) => (
                StatusCode::NOT_FOUND, msg
            ),
            AppError::DatabaseError(_) => (
                StatusCode::INTERNAL_SERVER_ERROR,
                "Internal server error".to_string(),
            ),
            AppError::ValidationError(msg) => (
                StatusCode::BAD_REQUEST, msg
            ),
        };
        (status, Json(serde_json::json!({ "error": message })))
            .into_response()
    }
}

// Handlers return Result<T, AppError>
async fn get_user(
    axum::extract::Path(id): axum::extract::Path<i64>,
) -> Result<Json<serde_json::Value>, AppError> {
    if id <= 0 {
        return Err(AppError::ValidationError(
            "ID must be positive".to_string()
        ));
    }
    Ok(Json(serde_json::json!({ "id": id })))
}

วิธีของ Axum ประกอบได้อย่างเป็นธรรมชาติกับ operator ? ของ Rust และชนิด Result Actix Web บรรลุสิ่งเดียวกันผ่าน ResponseError ซึ่งต้อง implement ทั้ง trait Display และ ResponseError ทั้งสองทำงานได้ แต่รูปแบบของ Axum รู้สึกเป็นธรรมชาติกว่าสำหรับนักพัฒนา Rust ที่คุ้นเคยกับ trait From และการแพร่กระจาย error

เมื่อใดควรเลือก Actix Web แทน Axum

Actix Web ยังคงเป็นตัวเลือกที่ถูกต้องในสถานการณ์เฉพาะ:

  • ความต้องการ throughput สูงสุด: Ad exchange, real-time bidding, pipeline การนำเข้าข้อมูลวิเคราะห์ที่ 10-15% req/s มากกว่าคุ้มค่ากับการแลกเปลี่ยน
  • แอปพลิเคชันที่ใช้ WebSocket หนัก: การสนับสนุน WebSocket ของ Actix Web ได้รับการทดสอบในการ deploy production มากกว่า การสนับสนุน WebSocket ของ Axum (ผ่าน axum::extract::ws) ทำงานได้ดีแต่มีประวัติ production ที่สั้นกว่า
  • Codebase Actix Web ที่มีอยู่: การย้ายจาก Actix Web 3.x เป็น 4.x ค่อนข้างตรงไปตรงมา การเขียนใหม่เป็น Axum ให้ผลตอบแทนที่ลดลงสำหรับบริการที่เสถียร
  • ความคุ้นเคยของทีม: หากทีมรู้จัก Actix Web อยู่แล้ว การเปลี่ยน framework เพื่อประโยชน์ด้าน ergonomi แทบไม่คุ้มในระยะสั้น

เมื่อใดควรเลือก Axum แทน Actix Web

Axum เหมาะกว่าในบริบทเหล่านี้:

  • โปรเจกต์ใหม่ในปี 2026: การสอดคล้องกับระบบนิเวศ Tokio (Tonic, Hyper, Tower) ลดแรงเสียดทานในการบูรณาการ
  • บริการผสม gRPC และ HTTP: middleware Tower ทำงานข้ามทั้งสองโปรโตคอลโดยไม่ต้องมี layer การปรับตัว
  • ทีมใหม่กับ Rust: extractor แบบ type-driven และข้อความ error ตอนคอมไพล์ของ Axum ให้เส้นโค้งการเรียนรู้ที่นุ่มนวลกว่า path syntax /{id} (สอดคล้องกับ OpenAPI) คุ้นเคยทันที
  • สถาปัตยกรรม microservice: trait Service ของ Tower ช่วยให้นำ middleware มาใช้ซ้ำข้ามบริการ ลด boilerplate

คำถามสัมภาษณ์: Actix Web และ Axum สำหรับตำแหน่ง Backend Rust

คำถามสัมภาษณ์ Rust สำหรับ backend ครอบคลุมความรู้ด้าน web framework มากขึ้น คำถามเหล่านี้ปรากฏในการสัมภาษณ์ backend ระดับ senior และ systems engineering

ถ: อธิบายความแตกต่างด้านสถาปัตยกรรมระหว่างโมเดล runtime ของ Actix Web และ Axum

Actix Web รันหนึ่ง runtime Tokio แบบ single-threaded ต่อ CPU core Task ถูกตรึงกับ thread ซึ่งขจัด overhead ของ work-stealing Axum รันบน shared runtime Tokio แบบ multi-threaded ที่มี work-stealing โมเดลของ Actix Web ลด cache-line contention ภายใต้ภาระหนัก ทำให้ได้ throughput สูงกว่า โมเดลของ Axum ทำให้การจัดการ shared state ง่ายขึ้นเพราะทุก task แชร์ runtime เดียวกัน

ถ: การลบ #[async_trait] ใน Axum 0.8 ส่งผลต่อ custom extractor อย่างไร?

Axum 0.8 ใช้ประโยชน์จาก return-position impl Trait native ใน trait ของ Rust (เสถียรปลายปี 2023) Custom extractor ที่ implement FromRequestParts หรือ FromRequest ตอนนี้กำหนด method async โดยตรงโดยไม่ต้องใช้ attribute #[async_trait] สิ่งนี้ขจัดการ allocate heap จาก Box<dyn Future> และปรับปรุงเวลาคอมไพล์ Extractor ที่มีอยู่ต้องลบ macro และปรับการ implement trait

ถ: อธิบายว่า middleware Tower ต่างจาก middleware Actix Web อย่างไร

Tower กำหนด trait Service<Request> แบบ generic ที่เป็น protocol-agnostic layer timeout ของ Tower ทำงานกับ HTTP (Axum), gRPC (Tonic) และโปรโตคอลที่กำหนดเองใด ๆ middleware Actix Web ใช้ trait Transform และ Service เฉพาะสำหรับ framework ของมัน ผลกระทบในทางปฏิบัติ: middleware Axum สามารถนำมาใช้ซ้ำได้ทั่วทั้งระบบนิเวศ Tower; middleware Actix Web เฉพาะสำหรับ framework

ถ: การตรวจสอบ query ตอนคอมไพล์ของ SQLx ทำงานอย่างไร และการแลกเปลี่ยนคืออะไร?

macro query_as! ของ SQLx เชื่อมต่อกับ database PostgreSQL แบบ live ระหว่างการคอมไพล์ มันตรวจสอบ syntax SQL, ชื่อคอลัมน์, ชนิด และการมีอยู่ของตาราง การแลกเปลี่ยน: build ต้องการการเข้าถึง database ซึ่งทำให้ pipeline CI ซับซ้อนขึ้น SQLx ให้ sqlx prepare เพื่อสร้าง metadata query แบบ offline โดยเก็บผลการตรวจสอบในไดเรกทอรี .sqlx ที่ commit ไปยัง version control

ถ: เมื่อใดการเลือก Actix Web แทน Axum เป็นการตัดสินใจทางเทคนิคที่ถูกต้อง?

Actix Web ถูกต้องเมื่อ throughput ต่อเนื่องเป็นข้อจำกัดหลัก: ad serving, การนำเข้าข้อมูลวิเคราะห์แบบ real-time หรือ gateway สำหรับการเทรดความถี่สูง โมเดล runtime แบบ pinned-thread ขจัด overhead ของ work-stealing ทำให้ได้ 10-15% req/s มากกว่าภายใต้ภาระ Axum ถูกต้องเมื่อความสามารถในการประกอบกับระบบนิเวศ Tokio มีความสำคัญมากกว่าการได้ throughput เพิ่มเล็กน้อย โดยเฉพาะในสถาปัตยกรรม microservice ที่ใช้ทั้ง HTTP และ gRPC

ข้อผิดพลาดที่พบบ่อยในการสัมภาษณ์

ผู้สมัครมักอ้างว่า framework หนึ่งดีกว่าอีก framework อย่างสากล คำตอบที่ดียอมรับการแลกเปลี่ยน: Actix Web ปรับให้เหมาะสมสำหรับ throughput, Axum ปรับให้เหมาะสมสำหรับความสามารถในการประกอบกับระบบนิเวศ ตัวเลือกที่ถูกต้องขึ้นอยู่กับข้อจำกัดของระบบ ไม่ใช่ความชอบส่วนตัว

แหล่งข้อมูล

  • TechEmpower Framework Benchmarks Round 23 (มกราคม 2026): ข้อมูล benchmark สำหรับการทดสอบ JSON, plaintext และ database
  • Axum 0.8.9 Release Notes: การเลือก WebSocket subprotocol, เวอร์ชัน Rust ขั้นต่ำ 1.80
  • Actix Web 4.14.0 Release (มิถุนายน 2026): การตรวจสอบ route middleware, การสนับสนุน IPv6 dual-stack, h1_write_buffer_size

ประเด็นสำคัญสำหรับการพัฒนาเว็บ Rust ในปี 2026

  • Actix Web 4.14 ให้ throughput สูงกว่า 10-15% ผ่านโมเดล runtime แบบ pinned-thread ทำให้เป็นตัวเลือกที่ถูกต้องสำหรับบริการที่ต้องการ latency ต่ำและ throughput สูง
  • Axum 0.8 ให้ ergonomi ที่ดีกว่าด้วย native async traits, path syntax /{id} และความเข้ากันได้กับ middleware Tower อย่างเต็มที่ทั้ง HTTP และ gRPC
  • ทั้งสอง framework ใช้ layer database เดียวกัน (SQLx พร้อมการตรวจสอบตอนคอมไพล์) ดังนั้นการเลือกไม่ส่งผลต่อรูปแบบการเข้าถึงข้อมูล
  • สำหรับโปรเจกต์เว็บ Rust ใหม่ในปี 2026 ที่ไม่มีความต้องการ throughput สูงสุด การสอดคล้องของระบบนิเวศ Axum กับ Tokio, Tonic และ Tower ลดต้นทุนการบำรุงรักษาระยะยาว
  • คำถามสัมภาษณ์ในหัวข้อนี้ทดสอบความเข้าใจเกี่ยวกับโมเดล runtime, สถาปัตยกรรม middleware และการให้เหตุผลเรื่องการแลกเปลี่ยน ไม่ใช่ความชอบ framework
  • การเตรียมตัวสัมภาษณ์ Rust ต้องการความเข้าใจในการตัดสินใจด้านสถาปัตยกรรมของทั้งสอง framework ไม่ใช่แค่ syntax ของ API

เริ่มฝึกซ้อมเลย!

ทดสอบความรู้ของคุณด้วยตัวจำลองสัมภาษณ์และแบบทดสอบเทคนิคครับ

ชาเลนจ์ประจำวัน

คุณหาบั๊กใน Rust เจอไหม

โค้ดจริงหนึ่งชิ้น บั๊กที่ซ่อนอยู่หนึ่งจุด วันละหนึ่งครั้ง ลองได้โดยไม่ต้องมีบัญชี

Anthony Fillion-Maillet

เขียนโดย

Anthony Fillion-Maillet

ผู้ก่อตั้ง SharpSkill

เป็นนักพัฒนาฟูลสแตกมากว่า 10 ปี ดูแล SharpSkill และรับผิดชอบทุกสิ่งที่เผยแพร่ที่นี่

อัปเดตเมื่อ 22 สิงหาคม 2569

แท็ก

#rust
#actix-web
#axum
#web-framework
#backend
#comparison

แชร์

บทความที่เกี่ยวข้อง