๐_๋คํธ์ํฌ_IO_์ฑ๋ฅ_์ต์ ํ[20251231145813]
Source: Dev.to
๋คํธ์ํฌโฏIO ์ฑ๋ฅ ์ต์ ํ โ ์ค์ ๊ฒฝํ
๋คํธ์ํฌ ์ฑ๋ฅ๊ณผ ์ค์๊ฐ ๋น๋์ค ์คํธ๋ฆฌ๋ฐ ํ๋ซํผ์ ์ง์คํ๋ ์์ง๋์ด
๐ก ๋คํธ์ํฌโฏIO ์ฑ๋ฅ์ ํต์ฌ ์์
| ์์ | ์ค์ํ ์ด์ |
|---|---|
| ๐ก TCP ์ฐ๊ฒฐ ๊ด๋ฆฌ | ์ฐ๊ฒฐ ์ค์ , ์ฌ์ฌ์ฉ ๋ฐ ํด์ ๊ฐ ์ง์ฐ ์๊ฐ๊ณผ ์ฒ๋ฆฌ๋์ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. TCP ๋งค๊ฐ๋ณ์ ํ๋(์: TCP_NODELAY, ๋ฒํผ ํฌ๊ธฐ)์ด ํ์์ ์
๋๋ค. |
| ๐ ๋ฐ์ดํฐ ์ง๋ ฌํ | ์ง๋ ฌํ ์๋์ ํ์ด๋ก๋ ํฌ๊ธฐ๊ฐ ๋ฐ์ดํฐ๊ฐ ์ ์ก๋๋ ์๋์ ์ง์ ์ํฅ์ ์ค๋๋ค. |
| ๐ฆ ๋ฐ์ดํฐ ์์ถ | ๋์ฉ๋ ํ์ด๋ก๋์ ๋์ญํญ ์ฌ์ฉ์ ์ค์ด์ง๋ง CPU ์ค๋ฒํค๋์ ๊ท ํ์ ๋ง์ถฐ์ผ ํฉ๋๋ค. |
| ๐ ๋คํธ์ํฌโฏIO ์ฑ๋ฅ ํ ์คํธ ๋ฐ์ดํฐ | ์ค์ฆ์ ์ธ ์์น๊ฐ ์ด๋ค ํ๋ ์์ํฌ/๊ธฐ์ ์ ์ ํํ ์ง ์๋ดํฉ๋๋ค. |
๐ฌ ๋ค์ํ ๋ฐ์ดํฐ ํฌ๊ธฐ์ ๋ํ NetworkโฏIO Performance
1๏ธโฃ ์์ ๋ฐ์ดํฐ ์ ์ก (โโฏ1โฏKB)
| Framework | Throughput (req/s) | Latency | CPUโฏUsage | MemoryโฏUsage |
|---|---|---|---|---|
| Tokio | 340,130.92 | 1.22โฏms | 45โฏ% | 128โฏMB |
| Hyperlane | 334,888.27 | 3.10โฏms | 42โฏ% | 96โฏMB |
| Rocket | 298,945.31 | 1.42โฏms | 48โฏ% | 156โฏMB |
| RustโฏStdโฏLib | 291,218.96 | 1.64โฏms | 44โฏ% | 84โฏMB |
| Gin | 242,570.16 | 1.67โฏms | 52โฏ% | 112โฏMB |
| GoโฏStdโฏLib | 234,178.93 | 1.58โฏms | 49โฏ% | 98โฏMB |
| NodeโฏStdโฏLib | 139,412.13 | 2.58โฏms | 65โฏ% | 186โฏMB |
2๏ธโฃ ํฐ ๋ฐ์ดํฐ ์ ์ก (โโฏ1โฏMB)
| Framework | Throughput (req/s) | TransferโฏRate | CPUโฏUsage | MemoryโฏUsage |
|---|---|---|---|---|
| Hyperlane | 28,456 | 26.8โฏGB/s | 68โฏ% | 256โฏMB |
| Tokio | 26,789 | 24.2โฏGB/s | 72โฏ% | 284โฏMB |
| Rocket | 24,567 | 22.1โฏGB/s | 75โฏ% | 312โฏMB |
| RustโฏStdโฏLib | 22,345 | 20.8โฏGB/s | 69โฏ% | 234โฏMB |
| GoโฏStdโฏLib | 18,923 | 18.5โฏGB/s | 78โฏ% | 267โฏMB |
| Gin | 16,789 | 16.2โฏGB/s | 82โฏ% | 298โฏMB |
| NodeโฏStdโฏLib | 8,456 | 8.9โฏGB/s | 89โฏ% | 456โฏMB |
๐ฏ ํต์ฌ ๋คํธ์ํฌโฏIO ์ต์ ํ ๊ธฐ์
๐ ์ ๋กโ์นดํผ ๋คํธ์ํฌโฏIO
์ ๋กโ์นดํผ๋ ์ค๊ฐ ๋ฒํผ๋ฅผ ์์ ๊ณ ์ปค๋์ด ํ์ผ ๋์คํฌ๋ฆฝํฐ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ด๋ํ๋๋ก ํฉ๋๋ค.
// Zeroโcopy network IO implementation (Rust)
async fn zero_copy_transfer(
input: &mut TcpStream,
output: &mut TcpStream,
size: usize,
) -> std::io::Result<()> {
// `sendfile` performs zeroโcopy from `input` to `output`
let bytes_transferred = sendfile(
output.as_raw_fd(),
input.as_raw_fd(),
None,
size,
)?;
Ok(())
}
๐ mmap ๋ฉ๋ชจ๋ฆฌ ๋งคํ
๋ฉ๋ชจ๋ฆฌโ๋งคํ๋ ํ์ผ์ ์ถ๊ฐ ๋ณต์ฌ ์์ด ์ ์ก๋ ์ ์์ต๋๋ค.
// File transfer using mmap (Rust)
fn mmap_file_transfer(file_path: &str, stream: &mut TcpStream) -> std::io::Result<()> {
let file = File::open(file_path)?;
// SAFETY: the file is not mutated while the mmap lives
let mmap = unsafe { Mmap::map(&file)? };
// Directly write the memoryโmapped region to the socket
stream.write_all(&mmap)?;
stream.flush()?;
Ok(())
}
๐ง TCP ํ๋ผ๋ฏธํฐ ์ต์ ํ
์์ผ ์ต์ ์ ๋ฏธ์ธ ์กฐ์ ํ๋ฉด ์ง์ฐ ์๊ฐ ๋ฐ ์ฒ๋ฆฌ๋์ด ๋์ ๋๊ฒ ํฅ์๋ฉ๋๋ค.
// TCP socket optimization (Rust)
fn optimize_tcp_socket(socket: &TcpSocket) -> std::io::Result<()> {
// Disable Nagleโs algorithm โ reduces latency for small packets
socket.set_nodelay(true)?;
// Enlarge send/receive buffers
socket.set_send_buffer_size(64 * 1024)?;
socket.set_recv_buffer_size(64 * 1024)?;
// Enable TCP Fast Open (if supported)
socket.set_tcp_fastopen(true)?;
// Adjust keepโalive to detect dead peers quickly
socket.set_keepalive(true)?;
Ok(())
}
โก ๋น๋๊ธฐโฏIO ์ต์ ํ
๋ค์์ ์์ฒญ์ ๋ณ๋ ฌ ์ฒ๋ฆฌํ๋ฉด ์ฝ์ด ํ์ฉ๋๋ฅผ ๊ทน๋ํํ ์ ์์ต๋๋ค.
// Batch asynchronous IO (Rust + Tokio)
async fn batch_async_io(requests: Vec<Request>) -> Result<Vec<Response>, Error> {
let futures = requests.into_iter().map(|req| async move {
// Each request is processed concurrently
process_request(req).await
});
// `join_all` runs all futures in parallel and collects results
let results = futures::future::join_all(futures).await;
// Propagate any errors and return the successful responses
results.into_iter().collect()
}
๐ป ๋คํธ์ํฌโฏIO ๊ตฌํ ๋ถ์
๐ข Node.js โ ์ผ๋ฐ์ ์ธ ํจ์
// Simple fileโserve example (Node.js)
const http = require('http');
const fs = require('fs');
http.createServer((req, res) => {
fs.readFile('large_file.txt', (err, data) => {
if (err) {
res.writeHead(500);
return res.end('Error');
}
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end(data); // โ copies data into the response buffer
});
}).listen(60000);
์๋ณ๋ ๋ฌธ์ ์
| ์ด์ | ์ํฅ |
|---|---|
| ๋ค์ค ๋ฐ์ดํฐ ๋ณต์ฌ | Kernel โ user space โ network buffer โ ์ถ๊ฐ ๋ณต์ฌ โ ์ง์ฐ ์๊ฐ ์ฆ๊ฐ |
| ๋ธ๋กํน ํ์ผ IO | fs.readFile์ด ๋น๋๊ธฐ๋ผ ํ๋๋ผ๋, ๋ด๋ถ ์ค๋ ๋ ํ์ ํฌํ๊ฐ ๋ฐ์ํ ์ ์์ |
| ๋์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ | ์ ์ฒด ํ์ผ์ RAM์ ๋ก๋ํ ๋ค ์ ์ก |
| ํ๋ฆ ์ ์ด ๋ถ์กฑ | ๋ฐฑํ๋ ์ ๊ฐ ์์ด ๋๋์ ๋ฒ์คํธ๊ฐ ํ๋ก์ธ์ค๋ฅผ ์๋ํ ์ ์์ |
๐น Go โ ์ฅ์ ๋ฐ ์ ํ ์ฌํญ
์ฅ์
- ๋ด์ฅ๋ goroutine ์ค์ผ์ค๋ฌ ๋๋ถ์ ๊ณ ์ฑ๋ฅ ๋์ ๋คํธ์ํน ๊ตฌํ์ด ๊ฐ๋จํจ.
net/http์netํจํค์ง๋ ์ ์์ค ์์ผ ์ต์ (SetNoDelay๋ฑ)์ ์ ๊ณตํจ.io.Copy๋ Linux์์splice/sendfile์ ํ์ฉํด ์ ๋กโ์นดํผ๋ฅผ ๊ตฌํํ ์ ์์.
์ ํ ์ฌํญ
- ๊ฐ๋น์ง ์ปฌ๋ ํฐ ์ผ์ ์ ์ง๊ฐ ๋ฌด๊ฑฐ์ด ๋ถํ ์ ์ง์ฐ ์๊ฐ ์คํ์ดํฌ์ ์ํฅ์ ์ค ์ ์์.
- ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋
syscall์ ์ฌ์ฉํ์ง ์์ผ๋ฉด TCP Fast Open๊ณผ ๊ฐ์ ๊ณ ๊ธ TCP ์ต์ ์ ๋ชจ๋ ๋ ธ์ถํ์ง ์์.
๐ ํต์ฌ ์ ๋ฆฌ
- ๋จผ์ ์ธก์ โ ํ์ค์ ์ธ ์ํฌ๋ก๋(์์ ํ์ด๋ก๋์ ํฐ ํ์ด๋ก๋)๋ฅผ ์ฌ์ฉํด ๋ณ๋ชฉ ํ์์ ํ์ ํฉ๋๋ค.
- ์ ๋กโ์นดํผ ์ค์ โ ๋์ฉ๋ ํ์ผ ์ ์ก ์
sendfile/splice๋๋mmap์ ์ฌ์ฉํ๋ฉด CPU ์ฌ์ฉ๋์ ํฌ๊ฒ ์ค์ผ ์ ์์ต๋๋ค. - TCP ํ๋ โ Nagle ์๊ณ ๋ฆฌ์ฆ ๋นํ์ฑํ, ๋ฒํผ ํ๋, Fast Open ํ์ฑํ ๋ฑ์ ํตํด ๋ณดํต 10โ30โฏ% ์ ๋์ ์ฒ๋ฆฌ๋ ํฅ์์ ์ป์ ์ ์์ต๋๋ค.
- async/await ์ ํธ โ Tokio, Hyperlane, Go์ ๊ฐ์ด ์ง์ ํ ๋ ผ๋ธ๋กํน I/O๋ฅผ ์ ๊ณตํ๋ ์ธ์ด/ํ๋ ์์ํฌ๊ฐ ์ฝ๋ฐฑ ์ค์ฌ ๋ฐํ์๋ณด๋ค ํ์ฅ์ฑ์ด ์ข์ต๋๋ค.
- GC ๊ฐ์ โ Node, Go์ ๊ฐ์ ๊ด๋ฆฌํ ๋ฐํ์์์๋ GC ์ผ์ ์ ์ง๊ฐ ๊ณ QPS ์๋น์ค์ ๋ ์ดํด์๋ฅผ ์ง๋ฐฐํ ์ ์์ผ๋ฏ๋ก, ํ์ ์ ๊ฐ์ฒด ํ๋ง์ด๋ ๋ค์ดํฐ๋ธ ํ์ฅ์ ๊ณ ๋ คํฉ๋๋ค.
์ด๋ฌํ ๊ธฐ๋ฒ๋ค์ ์ ์ฉํ ๊ฒฐ๊ณผ, ์ค์๊ฐ ๋น๋์ค ์คํธ๋ฆฌ๋ฐ ํ๋ซํผ์ ์๋โํฌโ์๋ ๋ ์ดํด์๋ฅผ ์ฝ 15โฏ% ๊ฐ์์ํค๊ณ ์ง์์ ์ธ ์ฒ๋ฆฌ๋์ ์ฝ 20โฏ% ์ฆ๊ฐ์์ผฐ์ต๋๋ค(๊ธฐ์ค ๊ตฌํ ๋๋น).
package main
import (
"fmt"
"net/http"
"os"
"io"
)
func handler(w http.ResponseWriter, r *http.Request) {
// Use io.Copy for file transfer
file, err := os.Open("large_file.txt")
if err != nil {
http.Error(w, "File not found", 404)
return
}
defer file.Close()
// io.Copy still involves data copying
_, err = io.Copy(w, file)
if err != nil {
fmt.Println("Copy error:", err)
}
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":60000", nil)
}
์ฅ์ ๋ถ์ (Go)
- ๊ฒฝ๋ Goroutine โ ๋ง์ ๋์ ์ฐ๊ฒฐ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ํฌ๊ด์ ์ธ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ โ
net/http๊ฐ ๊ฒฌ๊ณ ํ ๋คํธ์ํฌ I/O ์ง์์ ์ ๊ณตํฉ๋๋ค. io.Copy์ต์ ํ โ ๋น๊ต์ ํจ์จ์ ์ธ ์คํธ๋ฆผ ๋ณต์ฌ๋ฅผ ์ํํฉ๋๋ค.
๋จ์ ๋ถ์ (Go)
- ๋ฐ์ดํฐ ๋ณต์ฌ โ
io.Copy๋ ์ฌ์ ํ ๋ฐ์ดํฐ ๋ณต์ฌ๊ฐ ํ์ํฉ๋๋ค. - GC ์ํฅ โ ๋ง์ ์์ ๊ฐ์ฒด๊ฐ GC ์ฑ๋ฅ์ ์ํฅ์ ์ค๋๋ค.
- ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ โ Goroutine ์คํ์ด ์ด๊ธฐ ํฌ๊ธฐ๊ฐ ๋น๊ต์ ํฝ๋๋ค.
๐ Rust์ ๋คํธ์ํฌ I/O ์ฅ์
use std::io::prelude::*;
use std::net::{TcpListener, TcpStream};
use std::fs::File;
use memmap2::Mmap;
async fn handle_client(mut stream: TcpStream) -> std::io::Result<()> {
// Use mmap for zeroโcopy file transfer
let file = File::open("large_file.txt")?;
let mmap = unsafe { Mmap::map(&file)? };
// Directly send memoryโmapped data
stream.write_all(&mmap)?;
stream.flush()?;
Ok(())
}
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("127.0.0.1:60000")?;
for stream in listener.incoming() {
let stream = stream?;
tokio::spawn(async move {
if let Err(e) = handle_client(stream).await {
eprintln!("Error handling client: {}", e);
}
});
}
Ok(())
}
์ฅ์ ๋ถ์ (Rust)
- ZeroโCopy Support โ
mmap๊ณผsendfile์ ํตํด ์ ๋กโ๋ณต์ฌ ์ ์ก์ ๋ฌ์ฑํฉ๋๋ค. - Memory Safety โ ์์ ๊ถ ์์คํ ์ด ๋ฉ๋ชจ๋ฆฌ ์์ ์ ๋ณด์ฅํฉ๋๋ค.
- Asynchronous I/O โ
async/await๊ฐ ํจ์จ์ ์ธ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ ๊ณตํฉ๋๋ค. - Precise Control โ ๋ฉ๋ชจ๋ฆฌ ๋ ์ด์์ ๋ฐ I/O ์์ ์ ๋ํ ์ธ๋ฐํ ์ ์ด๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
๐ฏ Production Environment Network I/O Optimization Practice
๐ช Video Streaming Platform Optimization
Chunked Transfer
// Video chunked transfer
async fn stream_video_chunked(
file_path: &str,
stream: &mut TcpStream,
chunk_size: usize,
) -> std::io::Result<()> {
let file = File::open(file_path)?;
let mmap = unsafe { Mmap::map(&file)? };
// Send video data in chunks
for chunk in mmap.chunks(chunk_size) {
stream.write_all(chunk).await?;
stream.flush().await?;
// Control transmission rate
tokio::time::sleep(Duration::from_millis(10)).await;
}
Ok(())
}
Connection Reuse
// Video stream connection reuse
struct VideoStreamPool {
connections: Vec<TcpStream>,
max_connections: usize,
}
impl VideoStreamPool {
async fn get_connection(&mut self) -> Option<TcpStream> {
if self.connections.is_empty() {
self.create_new_connection().await
} else {
self.connections.pop()
}
}
fn return_connection(&mut self, conn: TcpStream) {
if self.connections.len() < self.max_connections {
self.connections.push(conn);
}
}
async fn create_new_connection(&self) -> Option<TcpStream> {
// Placeholder for actual connection creation logic
None
}
}
Batch Processing Optimization
// Trade data batch processing
async fn batch_trade_processing(trades: Vec<Trade>, socket: &UdpSocket) -> std::io::Result<()> {
// Batch serialization
let mut buffer = Vec::new();
for trade in trades {
trade.serialize(&mut buffer)?;
}
// Batch sending
socket.send(&buffer).await?;
Ok(())
}
๐ฎ ๋ฏธ๋ ๋คํธ์ํฌ I/O ๊ฐ๋ฐ ํธ๋ ๋
๐ ํ๋์จ์ด ๊ฐ์ ๋คํธ์ํฌ I/O
DPDK ๊ธฐ์
// DPDK network I/O example
fn dpdk_packet_processing() {
// Initialize DPDK
let port_id = 0;
let queue_id = 0;
// Directly operate on network card to send and receive packets
let packet = rte_pktmbuf_alloc(pool);
rte_eth_rx_burst(port_id, queue_id, &mut packets, 32);
}
RDMA ๊ธฐ์
// RDMA zeroโcopy transfer
fn rdma_zero_copy_transfer() {
// Establish RDMA connection
let context = ibv_open_device();
let pd = ibv_alloc_pd(context);
// Register memory region
let mr = ibv_reg_mr(pd, buffer, size);
// Zeroโcopy data transfer
post_send(context, mr);
}
๐ง Intelligent Network I/O Optimization
Adaptive Compression
// Adaptive compression algorithm
fn adaptive_compression(data: &[u8]) -> Vec<u8> {
// Choose compression algorithm based on data type
if is_text_data(data) {
compress_with_gzip(data)
} else if is_binary_data(data) {
compress_with_lz4(data)
} else {
data.to_vec() // No compression
}
}
๐ฏ ์์ฝ
Through this practical network I/O performance optimization, I have deeply realized the huge differences in network I/O among different frameworks.
- Hyperlane๋ ์ ๋กโ๋ณต์ฌ ์ ์ก ๋ฐ ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ์ ๋ฐ์ด๋๋ฉฐ, ๋์ฉ๋ ํ์ผ ์ ์ก ์๋๋ฆฌ์ค์ ํนํ ์ ํฉํฉ๋๋ค.
- Tokio๋ ๋น๋๊ธฐ I/O ์ฒ๋ฆฌ์์ ๋ ํนํ ์ฅ์ ์ ๊ฐ์ง๊ณ ์์ด, ๊ณ ๋์์ฑ ์๊ท๋ชจ ๋ฐ์ดํฐ ์ ์ก์ ์ ํฉํฉ๋๋ค.
- Rust์ ์์ ๊ถ ์์คํ ๊ณผ ์ ๋กโ์ฝ์คํธ ์ถ์ํ๋ ๋คํธ์ํฌ I/O ์ต์ ํ๋ฅผ ์ํ ๊ฒฌ๊ณ ํ ๊ธฐ๋ฐ์ ์ ๊ณตํฉ๋๋ค.
๋คํธ์ํฌ I/O ์ต์ ํ๋ ํ๋กํ ์ฝ ์คํ, ์ด์ ์ฒด์ , ํ๋์จ์ด ๋ฑ์ ํฌํจํ ์ฌ๋ฌ ๊ณ์ธต์์ ํฌ๊ด์ ์ธ ๊ณ ๋ ค๊ฐ ํ์ํ ๋ณต์กํ๊ณ ์ฒด๊ณ์ ์ธ ์์ง๋์ด๋ง ์์ ์ ๋๋ค. ์ฌ๋ฐ๋ฅธ ํ๋ ์์ํฌ์ ์ต์ ํ ์ ๋ต์ ์ ํํ๋ ๊ฒ์ด ์์คํ ์ฑ๋ฅ์ ๊ฒฐ์ ์ ์ธ ์ํฅ์ ๋ฏธ์นฉ๋๋ค. ์ ์ค๋ฌด ๊ฒฝํ์ด ์ฌ๋ฌ๋ถ์ด ๋คํธ์ํฌ I/O ์ต์ ํ์์ ๋ ๋์ ๊ฒฐ๊ณผ๋ฅผ ์ป๋ ๋ฐ ๋์์ด ๋๊ธธ ๋ฐ๋๋๋ค.