rust axum tokio model

agnusdei·2025년 2월 16일

Tokio 모델 완벽 정리 🦀🚀

Tokio(토키오)는 Rust에서 비동기(async) 프로그래밍을 위한 런타임이다.
Actix Web은 액터 모델을 사용하지만, Axum은 Tokio 기반 비동기 모델을 사용한다.
그럼, "Tokio 모델이 대체 뭐고, 왜 중요한가?"를 자세히 알아보자.


1. Tokio 모델이란?

Tokio는 Rust에서 비동기 동작을 처리하는 이벤트 기반(Runtime) 시스템이다.
Rust에서 "Node.js"처럼 비동기 방식으로 동작하는 런타임이라고 보면 된다.

💡 Tokio = 비동기 실행 엔진 + 태스크 스케줄러

  • Rust 표준 라이브러리(Stdlib)는 기본적으로 동기(Sync) 방식
  • Tokio는 async/await을 활용한 비동기 처리를 지원

Tokio의 핵심 목표:
최소한의 스레드 사용으로 많은 요청 처리 (고성능)
안전하고 예측 가능한 동시성
네트워크, DB 연결, 타이머 등 다양한 비동기 기능 지원


2. Tokio 모델이 필요한 이유 (비동기 프로그래밍의 필요성)

(1) 기존 동기(Synchronous) 모델의 문제점

동기 방식에서는 한 작업이 끝나야 다음 작업을 실행할 수 있음.

fn sync_function() {
    let data = get_data(); // 3초 걸림 (DB 조회)
    println!("Data: {}", data); // 데이터 출력
}

💥 단점:

  • get_data()가 실행될 동안 CPU가 아무것도 하지 않고 대기함 (비효율적)
  • 많은 요청이 오면 블로킹(Block)이 발생하여 서버가 느려짐

(2) 비동기(Asynchronous) 모델의 장점

Tokio를 사용하면, 비동기 작업이 완료될 때까지 다른 작업을 수행할 수 있음.

async fn async_function() {
    let data = get_data().await; // 3초 걸려도 다른 작업 가능
    println!("Data: {}", data);
}

장점:

  • await을 사용하면 get_data()가 실행되는 동안 다른 요청을 처리 가능
  • CPU가 쉬지 않고 계속 일을 수행할 수 있음
  • 대규모 트래픽을 효율적으로 처리 가능 (웹 서버, 마이크로서비스 등)

3. Tokio 모델의 작동 방식 (시간 순서대로 이해하기)

Tokio의 핵심 구조는 이벤트 루프(Event Loop) + Future(태스크) 기반이다.

Tokio 실행 흐름

1️⃣ 사용자가 async 함수를 호출하면, Future가 생성됨
2️⃣ Tokio 런타임이 Future를 실행 큐(Task Queue)에 추가
3️⃣ 멀티스레드 환경에서 여러 Future를 동시에 실행
4️⃣ Future가 완료되면 결과를 반환 (await 사용)

💡 간단한 예제

use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
    println!("Start");

    let task = async {
        sleep(Duration::from_secs(2)).await;
        println!("Task done");
    };

    tokio::spawn(task); // 비동기 태스크 실행

    println!("End");
}

🔍 출력 결과:

Start
End
Task done  // (2초 후 실행됨)

tokio::spawn()을 사용하면, sleep(2초) 동안 대기하지 않고 다른 작업을 먼저 수행 가능!


4. Tokio의 핵심 개념

(1) Future (미래 값)

Rust에서 async 함수는 Future<T> 타입을 반환함.

  • Future는 "미래에 결과가 올 것이다"라고 약속하는 객체.
  • Future가 완료될 때까지 await으로 기다려야 함.
async fn hello() -> String {
    "Hello, world!".to_string()
}

#[tokio::main]
async fn main() {
    let result = hello().await;
    println!("{}", result);
}

(2) Task (비동기 태스크)

Tokio에서 Future는 실행되지 않음 → Tokio 런타임이 Task로 관리해야 실행됨.

  • tokio::spawn()을 사용하면 백그라운드에서 실행되는 비동기 태스크가 됨.
use tokio::task;

#[tokio::main]
async fn main() {
    let handle = task::spawn(async {
        "Hello from task"
    });

    let result = handle.await.unwrap();
    println!("{}", result);
}

(3) Runtime (Tokio 런타임)

Rust 표준 라이브러리는 기본적으로 비동기 실행 환경이 없음.
Tokio는 Rust에서 비동기 작업을 실행하기 위한 런타임 역할을 함.

  • #[tokio::main] → 단일 스레드 또는 멀티 스레드 런타임 실행
  • #[tokio::test] → 비동기 테스트 실행
#[tokio::main]
async fn main() {
    println!("Running with Tokio runtime!");
}

(4) Reactor + Executor 구조

Tokio는 ReactorExecutor를 조합한 구조를 가짐.

개념설명
ReactorOS 비동기 I/O 이벤트 감지 (예: 네트워크, 파일, DB)
ExecutorFuture를 실행하는 태스크 스케줄러

🔍 Tokio 내부 동작 과정
1. Reactor가 "이벤트 발생"을 감지 (예: 네트워크 요청 수신)
2. Executor가 Future를 실행 큐(Task Queue)에 추가
3. Future가 실행되다가 I/O 작업이 필요하면 다시 Reactor에 넘김
4. I/O 작업이 완료되면 Reactor가 다시 Executor로 전달
5. Executor가 Future를 계속 실행하여 최종 결과 반환


5. Tokio vs Actix Web 비교 (비동기 vs 액터 모델 차이점)

비교 항목Tokio (Axum 기반)Actix Web (Actor 모델)
동작 방식Future 기반 비동기 실행Actor 기반 메시지 전달
Rust 생태계 호환성✅ 표준 (Tokio 기반)❌ Actix 독자적인 구조
성능🚀 빠름 (하지만 Actix보다 약간 느림)🚀🚀 초고속 (Rust에서 가장 빠름)
동시성 처리멀티태스킹 기반멀티 액터 기반
코드 직관성✅ 쉬움 (async/await)❌ 어려움 (Actor 메시지 패싱)
유지보수성✅ 높음❌ 상대적으로 낮음

6. 결론: Axum(Tokio) vs Actix Web(액터 모델) 선택 가이드

✅ 언제 Tokio(Axum)를 사용할까?

  • Rust의 표준 비동기 패턴을 따르고 싶을 때
  • 유지보수가 쉬운 REST API 서버를 개발할 때
  • 기존 Rust 라이브러리(Tokio 기반)와 잘 맞는 구조가 필요할 때

🚀 언제 Actix Web을 사용할까?

  • 극한의 성능이 필요한 경우 (초고속 웹 서버)
  • 수많은 동시 요청을 처리해야 할 때 (WebSocket, 실시간 채팅)
  • Actor 모델을 활용한 분산 시스템을 개발할 때

7. 최종 요약

개념설명
Tokio 모델비동기(async/await) 기반 실행 모델
Actix Web액터 모델 기반 동시성 처리
Tokio의 장점Rust 표준, 유지보수 용이, 높은 확장성
Actix Web의 장점초고속 성능, 액터 기반 멀티태스킹

💡 결론:

  • "일반적인 웹 서버 개발" → Axum(Tokio) 추천
  • "고성능 & 실시간 처리" → Actix Web 추천

🚀 Rust로 서버 개발을 처음 한다면 Axum(Tokio)부터 시작하는 것이 좋다!

profile
DevSecOps, Pentest, Cloud(OpenStack), Develop, Data Engineering, AI-Agent

0개의 댓글