Skip to content

About

High level HTTP server library

Resources

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Latest commit

ย 

History

77 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Atomic HTTP

๊ณ ์„ฑ๋Šฅ HTTP ์„œ๋ฒ„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Arena ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์™€ Zero-copy ๊ธฐ์ˆ ์„ ํ™œ์šฉํ•œ ์ตœ์ ํ™”๋œ HTTP ์„œ๋ฒ„

๐Ÿš€ ์ฃผ์š” ๊ธฐ๋Šฅ

  • Arena ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ: ํšจ์œจ์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น๊ณผ ๊ด€๋ฆฌ
  • Zero-copy ๊ธฐ์ˆ : ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ ์—†๋Š” ํŒŒ์ผ ์„œ๋น™
  • ๋ฉ€ํ‹ฐํŒŒํŠธ ์ง€์›: ๊ณ ์„ฑ๋Šฅ ํŒŒ์ผ ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ
  • ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ: Tokio ๊ธฐ๋ฐ˜ ๋น„๋™๊ธฐ I/O
  • SSE ์ŠคํŠธ๋ฆฌ๋ฐ: into_sse()๋กœ Server-Sent Events ์ „์†ก
  • ํƒ€์ž… ์•ˆ์ „์„ฑ: Rust์˜ ํƒ€์ž… ์‹œ์Šคํ…œ ํ™œ์šฉ

๐Ÿ“ฆ ์„ค์น˜

[dependencies]
atomic_http = { version = "0.15.1", features = ["arena"] }

โ„น๏ธ ํ”„๋กœ๋•์…˜ ๋ฐฐํฌ ์ „ SECURITY.md ์˜ ๊ถŒ์žฅ ์„ค์ • (max_body_size, header_read_deadline_ms, TLS) ์„ ์ ์šฉํ•˜์„ธ์š”.

๐Ÿ› ๏ธ ๊ธฐ๋Šฅ๋ณ„ Features

  • arena: Arena ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ (๊ธฐ๋ณธ ํ™œ์„ฑํ™”)
  • router: Radix trie ๊ธฐ๋ฐ˜ ๋ผ์šฐํ„ฐ (๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ฐ€์ด๋“œ)
  • websocket: WebSocket ์—…๊ทธ๋ ˆ์ด๋“œ ์ง€์›
  • connection_pool: Keep-alive ์—ฐ๊ฒฐ ํ’€๋ง
  • response_file: ํŒŒ์ผ ์‘๋‹ต ์ง€์›
  • env: ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • ์ง€์›
  • debug: ๋””๋ฒ„๊ทธ ์ถœ๋ ฅ ํ™œ์„ฑํ™”

๐Ÿงช ํ…Œ์ŠคํŠธ ์‹คํ–‰ ๊ฐ€์ด๋“œ

๐Ÿ“‹ ์ƒˆ๋กœ์šด ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (์ถ”์ฒœ)

1. ์™„์ „ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ

์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์‹œ์ž‘ํ•˜๊ณ  ์ข…ํ•ฉ์ ์ธ ํ…Œ์ŠคํŠธ ์‹คํ–‰

# Arena + Zero-copy ๋ชจ๋“œ
cargo run --example integrated_test --features arena

# ํ‘œ์ค€ ๋ชจ๋“œ
cargo run --example integrated_test

2. ์„ฑ๋Šฅ ๋น„๊ต ๋ฒค์น˜๋งˆํฌ

Arena ์„œ๋ฒ„์™€ ํ‘œ์ค€ ์„œ๋ฒ„์˜ ์„ฑ๋Šฅ์„ ์ง์ ‘ ๋น„๊ต

# Arena vs ํ‘œ์ค€ ์„œ๋ฒ„ ์„ฑ๋Šฅ ๋น„๊ต
cargo run --example comparative_benchmark --features arena

# ๋ฆด๋ฆฌ์ฆˆ ๋ชจ๋“œ๋กœ ์ •ํ™•ํ•œ ์„ฑ๋Šฅ ์ธก์ •
cargo run --release --example comparative_benchmark --features arena

3. ๋ฉ€ํ‹ฐํŒŒํŠธ ํ…Œ์ŠคํŠธ

ํŒŒ์ผ ์—…๋กœ๋“œ์™€ ๋ฉ€ํ‹ฐํŒŒํŠธ ํผ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํ…Œ์ŠคํŠธ

# Arena ๋ฉ€ํ‹ฐํŒŒํŠธ ํ…Œ์ŠคํŠธ
cargo run --example integrated_multipart_test --features arena

# ํ‘œ์ค€ ๋ฉ€ํ‹ฐํŒŒํŠธ ํ…Œ์ŠคํŠธ  
cargo run --example integrated_multipart_test

๐Ÿ”ง ๊ฐ„๋‹จํ•œ ํ…Œ์ŠคํŠธ

0. ๋ฌธ์ œ ํ•ด๊ฒฐ์šฉ ๋””๋ฒ„๊ทธ ํ…Œ์ŠคํŠธ

# Arena ์„œ๋ฒ„ ๋””๋ฒ„๊ทธ
cargo run --example debug_test --features arena -- 9999

# ํ‘œ์ค€ ์„œ๋ฒ„ ๋””๋ฒ„๊ทธ
cargo run --example debug_test -- 9999

1. ๊ฐ„๋‹จํ•œ ๋ฒค์น˜๋งˆํฌ ํ…Œ์ŠคํŠธ (์ถ”์ฒœ)

# Arena ๊ฐ„๋‹จ ๋ฒค์น˜๋งˆํฌ
cargo run --example simple_benchmark_test --features arena -- 9998

# ํ‘œ์ค€ ๊ฐ„๋‹จ ๋ฒค์น˜๋งˆํฌ  
cargo run --example simple_benchmark_test -- 9998

2. ๊ธฐ๋ณธ ์„œ๋ฒ„ ํ…Œ์ŠคํŠธ

# Arena ์„œ๋ฒ„
cargo run --example simple_server_test --features arena -- 9080

# ํ‘œ์ค€ ์„œ๋ฒ„
cargo run --example simple_server_test -- 9081

2. ๊ฐ„๋‹จํ•œ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ

# Arena ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ
cargo run --example simple_performance_test --features arena

# ํ‘œ์ค€ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ
cargo run --example simple_performance_test

๐Ÿ“Š ๋ฒค์น˜๋งˆํฌ

Criterion์„ ์‚ฌ์šฉํ•œ ๋งˆ์ดํฌ๋กœ ๋ฒค์น˜๋งˆํฌ:

cargo bench

๐Ÿ” ๊ธฐ์กด ํ…Œ์ŠคํŠธ๋“ค (๋ ˆ๊ฑฐ์‹œ)

ํ•„์š”์‹œ ๊ฐœ๋ณ„ ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ:

# ๊ธฐ์กด ์„œ๋ฒ„ ํ…Œ์ŠคํŠธ
cargo run --example server --features arena

# ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ ํด๋ผ์ด์–ธํŠธ (๋ณ„๋„ ์‹คํ–‰)
cargo run --example load_test_client -- -n 1000 -c 50

# ํŒŒ์ผ ์„œ๋น™ ํ…Œ์ŠคํŠธ
cargo run --example file_serving_test --features arena,response_file

# ์ œ๋กœ์นดํ”ผ ํ…Œ์ŠคํŠธ
cargo run --example zero_copy_test --features arena

๐Ÿ“ˆ ์„ฑ๋Šฅ ํŠน์ง•

Arena ์„œ๋ฒ„์˜ ์žฅ์ 

  • โœ… ์ œ๋กœ์นดํ”ผ: ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ ์—†์Œ
  • โœ… ๋‚ฎ์€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰: ์›๋ณธ ๋ฐ์ดํ„ฐ๋งŒ ์œ ์ง€
  • โœ… ๋น ๋ฅธ ํŒŒ์‹ฑ: String ์ƒ์„ฑ ์—†์ด ๋ฐ”์ดํŠธ ์ง์ ‘ ์ ‘๊ทผ
  • โœ… ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์„ฑ๋Šฅ: GC ์••๋ฐ• ์—†์Œ
  • โœ… ๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์ตœ์ ํ™”: ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ 

ํ‘œ์ค€ ์„œ๋ฒ„ ํŠน์ง•

  • ๐Ÿ“ ์•ˆ์ •์ ์ด๊ณ  ๊ฒ€์ฆ๋œ ๋ฐฉ์‹
  • ๐Ÿ“ ๋ฉ”๋ชจ๋ฆฌ ๋ณต์‚ฌ์™€ String ํ• ๋‹น ํฌํ•จ
  • ๐Ÿ“ ์ƒ๋Œ€์ ์œผ๋กœ ๋†’์€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰

๐Ÿ’ก ์‚ฌ์šฉ ์˜ˆ์ œ

๊ธฐ๋ณธ ์„œ๋ฒ„ ์„ค์ •

use atomic_http::*;
use http::StatusCode;

#[tokio::main]
async fn main() -> Result<(), SendableError> {
    let mut server = Server::new("127.0.0.1:8080").await?;
    
    loop {
        let accept = server.accept().await?;
        
        tokio::spawn(async move {
            let (request, mut response) = accept.parse_request_arena_writer().await?;
            
            // JSON ํŒŒ์‹ฑ (Zero-copy)
            let data: MyData = request.get_json_arena()?;
            
            // ์‘๋‹ต ์ƒ์„ฑ (Arena ํ• ๋‹น)
            let result = serde_json::json!({
                "status": "success",
                "data": data
            });
            response.body_mut().set_arena_json(&result)?;
            *response.status_mut() = StatusCode::OK;
            
            response.responser_arena().await?;
            
            Ok::<(), SendableError>(())
        });
    }
}

๋ฉ€ํ‹ฐํŒŒํŠธ ํŒŒ์ผ ์—…๋กœ๋“œ

// Arena ๋ฉ€ํ‹ฐํŒŒํŠธ ์ฒ˜๋ฆฌ
match request.get_multi_part_arena()? {
    Some(form) => {
        // ํ…์ŠคํŠธ ํ•„๋“œ ์ ‘๊ทผ
        for i in 0..form.text_fields.len() {
            let name = form.get_text_field_name(i);
            let value = form.get_text_field_value(i);
        }
        
        // ํŒŒ์ผ ์ฒ˜๋ฆฌ
        for part in &form.parts {
            let filename = part.get_file_name();
            let file_data = part.get_body(); // Zero-copy ์ ‘๊ทผ
            
            // ํŒŒ์ผ ์ €์žฅ
            tokio::fs::write(filename?, file_data).await?;
        }
    }
    None => {
        // JSON ๋˜๋Š” ๋‹ค๋ฅธ ํ˜•์‹ ์ฒ˜๋ฆฌ
    }
}

Server-Sent Events (SSE)

์‘๋‹ต์€ ๋ณดํ†ต content-length์™€ ํ•จ๊ป˜ ํ•œ ๋ฒˆ์— ์ „์†ก๋˜์ง€๋งŒ, into_sse()๋Š” ์†Œ์ผ“์˜ write half๋ฅผ ๋„˜๊ฒจ๋ฐ›์•„ ํ—ค๋”๋ฅผ ํ•œ ๋ฒˆ ๋ณด๋‚ด๊ณ  ์ดํ›„ ํ”„๋ ˆ์ž„์„ ์›ํ•˜๋Š” ๋งŒํผ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. (Response<Writer>, Response<ArenaWriter> ๋ชจ๋‘ ์ง€์›)

use atomic_http::*;
use std::time::Duration;

async fn stream(response: http::Response<ArenaWriter>) -> Result<(), SendableError> {
    // ์ถ”๊ฐ€ ํ—ค๋”(Set-Cookie, CORS ๋“ฑ)๋Š” into_sse() ์ „์— response.headers_mut()๋กœ ์„ค์ •
    let mut sse = response.into_sse().await?;

    sse.send_event("token", "์•ˆ๋…•").await?;                       // event: token
    sse.send(&SseEvent::data("์—ฌ๋Ÿฌ ์ค„\n๋ฐ์ดํ„ฐ").id("42")).await?;  // ์ค„๋ฐ”๊ฟˆ์€ data: ์ค„๋กœ ๋ถ„๋ฆฌ

    // ๋А๋ฆฐ ์ž‘์—… ๋™์•ˆ 15์ดˆ๋งˆ๋‹ค ์ฃผ์„ ํ”„๋ ˆ์ž„์„ ๋ณด๋‚ด ์—ฐ๊ฒฐ ์œ ์ง€
    let answer = sse
        .keepalive_while(Duration::from_secs(15), slow_work())
        .await?;
    sse.send_event("done", &answer).await?;

    sse.finish().await // FIN ์ „์†ก
}
  • ์ƒํƒœ ์ฝ”๋“œ๋Š” ํ•ญ์ƒ 200 OK์ด๊ณ , ์ŠคํŠธ๋ฆผ์€ connection: close๋กœ ์†Œ์ผ“์ด ๋‹ซํžˆ๋ฉด ๋๋‚ฉ๋‹ˆ๋‹ค (chunked ๋ฏธ์‚ฌ์šฉ).
  • ์˜ค๋ฅ˜ ์‘๋‹ต์€ responser / responser_arena๋กœ ๋ณด๋‚ด์„ธ์š”.
  • ์ „์†ก ์‹คํŒจ๊ฐ€ ํด๋ผ์ด์–ธํŠธ ์ดํƒˆ์ธ์ง€ is_disconnect(&err)๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์˜ˆ์ œ: cargo run --example sse_test ํ›„ curl -N http://127.0.0.1:8080/events

๋ฐ”์ด๋„ˆ๋ฆฌ ์‘๋‹ต (์˜ค๋””์˜ค, ์ด๋ฏธ์ง€ ๋“ฑ)

set_arena_bytes()๋Š” UTF-8์ด ์•„๋‹Œ ๋ฐ”์ดํŠธ๋„ ๊ทธ๋Œ€๋กœ ๋ณธ๋ฌธ์œผ๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค. content-length๋Š” ์ž๋™์œผ๋กœ ๋ถ™๊ณ , content-type์€ ์ง์ ‘ ์ง€์ •ํ•˜์„ธ์š”.

use atomic_http::*;
use http::{header, HeaderValue, StatusCode};

async fn audio(mut response: http::Response<ArenaWriter>, wav: Vec<u8>) -> Result<(), SendableError> {
    *response.status_mut() = StatusCode::OK;
    response.headers_mut().insert(header::CONTENT_TYPE, HeaderValue::from_static("audio/wav"));
    response.body_mut().set_arena_bytes(&wav)?;
    response.responser_arena().await
}

๐Ÿ”ง ํ™˜๊ฒฝ ์„ค์ •

ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์„ค์ • (env ํ”ผ์ณ ํ™œ์„ฑํ™” ์‹œ):

export NO_DELAY=true
export READ_TIMEOUT_MILLISECONDS=5000
export READ_BUFFER_SIZE=8192
export ROOT_PATH="/var/www"
export ZERO_COPY_THRESHOLD=1048576
export ENABLE_FILE_CACHE=true
# 0.14+ ๋ณด์•ˆ ์˜ต์…˜ (DoS / slowloris ๋ฐฉ์–ด)
export MAX_BODY_SIZE=10485760           # ๋ณธ๋ฌธ cap (bytes); ๋ฏธ์„ค์ • ์‹œ ๋ฌด์ œํ•œ
export HEADER_READ_DEADLINE_MS=5000     # ํ—ค๋” ์ „์ฒด ์ˆ˜์‹  deadline

๐Ÿ—๏ธ ๊ฐœ๋ฐœ ๋ฐ ๊ธฐ์—ฌ

์š”๊ตฌ์‚ฌํ•ญ

  • Rust 1.77 ์ด์ƒ
  • Tokio ๋Ÿฐํƒ€์ž„

์ปดํŒŒ์ผ

# ๊ธฐ๋ณธ ๋นŒ๋“œ
cargo build

# Arena + Zero-copy ๋ชจ๋“  ๊ธฐ๋Šฅ
cargo build --features arena,response_file,env

# ๋ฆด๋ฆฌ์ฆˆ ๋นŒ๋“œ  
cargo build --release --features arena

ํ…Œ์ŠคํŠธ

# ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
cargo test

# ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ
cargo run --example integrated_test --features arena

# ์„ฑ๋Šฅ ๋ฒค์น˜๋งˆํฌ
cargo bench

๐Ÿ“„ ๋ผ์ด์„ ์Šค

Apache License 2.0

๐Ÿค ๊ธฐ์—ฌ

์ด์Šˆ์™€ ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์€ ๋จผ์ € ์ด์Šˆ๋ฅผ ์—ด์–ด ๋…ผ์˜ํ•ด ์ฃผ์„ธ์š”.

๐Ÿ“ž ์ง€์›


์ถ”์ฒœ ํ…Œ์ŠคํŠธ ์ˆœ์„œ:

  1. cargo run --example debug_test --features arena - ๊ธฐ๋ณธ ๋™์ž‘ ํ™•์ธ
  2. cargo run --example simple_benchmark_test --features arena - ๊ฐ„๋‹จํ•œ ๋ฒค์น˜๋งˆํฌ
  3. cargo run --example integrated_test --features arena - ์ „์ฒด ๊ธฐ๋Šฅ ํ™•์ธ
  4. cargo run --example comparative_benchmark --features arena - ์„ฑ๋Šฅ ๋น„๊ต
  5. cargo bench - ๋งˆ์ดํฌ๋กœ ๋ฒค์น˜๋งˆํฌ

๊ฐ ํ…Œ์ŠคํŠธ๋Š” ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฏ€๋กœ ๋ณ„๋„ ์„ค์ •์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿšจ ๋ฌธ์ œ ํ•ด๊ฒฐ

๋ฒค์น˜๋งˆํฌ ์‹คํŒจ ๋ฌธ์ œ

๋งŒ์•ฝ comparative_benchmark์—์„œ ์š”์ฒญ์ด ์‹คํŒจํ•œ๋‹ค๋ฉด:

  1. ๊ธฐ๋ณธ ํ…Œ์ŠคํŠธ๋ถ€ํ„ฐ ์‹คํ–‰:

    cargo run --example debug_test --features arena
  2. ๊ฐ„๋‹จํ•œ ๋ฒค์น˜๋งˆํฌ ์‹คํ–‰:

    cargo run --example simple_benchmark_test --features arena
  3. ํฌํŠธ ์ถฉ๋Œ ํ™•์ธ:

    # ๋‹ค๋ฅธ ํฌํŠธ ์‚ฌ์šฉ
    cargo run --example simple_benchmark_test --features arena -- 8888

์ผ๋ฐ˜์ ์ธ ๋ฌธ์ œ๋“ค

  • ์ปดํŒŒ์ผ ์˜ค๋ฅ˜: cargo clean && cargo build --features arena
  • ์—ฐ๊ฒฐ ์‹คํŒจ: ๋ฐฉํ™”๋ฒฝ์ด๋‚˜ ํฌํŠธ ์‚ฌ์šฉ ์ค‘์ธ์ง€ ํ™•์ธ
  • ์„ฑ๋Šฅ ์ธก์ •: --release ๋ชจ๋“œ๋กœ ์‹คํ–‰

๋กœ๊ทธ ํ™•์ธ

๊ฐ ํ…Œ์ŠคํŠธ๋Š” ์ƒ์„ธํ•œ ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๋ฏ€๋กœ ์‹คํŒจ ์ง€์ ์„ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

About

High level HTTP server library

Resources

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages