liburing 라이브러리 소개
liburing은 리눅스 커널이 제공하는 io_uring 인터페이스를 보다 쉽게 사용할 수 있도록 설계된 C 언어용 래퍼 라이브러리입니다. io_uring은 대규모 동시성 환경에서 효율적인 입출력 처리를 가능하게 하는 비동기 I/O 메커니즘으로, 기존의 epoll, aio와 비교해 낮은 지연 시간과 높은 처리량을 자랑합니다. liburing은 저수준 시스템 콜의 복잡성을 추상화하여 개발자가 직관적으로 비동기 작업을 제출하고 완료 이벤트를 처리할 수 있게 해줍니다.
빌드 및 설치 절차
최신 버전의 liburing을 소스에서 컴파일하려면 다음 단계를 따르세요:
git clone https://github.com/axboe/liburing.git
cd liburing
./configure --prefix=/usr/local
make -j$(nproc)
sudo make install
설치 후에는 헤더 파일(<liburing.h>)과 라이브러리(liburing.so)가 시스템에 등록되며, 컴파일 시 -luring 플래그로 링크할 수 있습니다.
실용 예제: 비동기 파일 복사
아래 코드는 입력 파일을 비동기로 읽고, 그 내용을 출력 파일에 쓰는 간단한 복사 도구를 구현한 것입니다. 두 개의 연속적인 작업(읽기 → 쓰기)을 큐에 제출하며, 각 완료 이벤트를 순차적으로 처리합니다.
#include <liburing.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 4096
int copy_file(const char *input_path, const char *output_path) {
int in_fd = open(input_path, O_RDONLY);
if (in_fd == -1) {
perror("입력 파일 열기 실패");
return -1;
}
int out_fd = open(output_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (out_fd == -1) {
perror("출력 파일 열기 실패");
close(in_fd);
return -1;
}
struct io_uring ring;
if (io_uring_queue_init(64, &ring, 0) != 0) {
fprintf(stderr, "io_uring 초기화 실패\n");
close(in_fd);
close(out_fd);
return -1;
}
char *buf = aligned_alloc(4096, BUFFER_SIZE);
struct io_uring_sqe *sqe;
struct io_uring_cqe *cqe;
bool reading = true;
while (reading) {
// 읽기 요청 준비
sqe = io_uring_get_sqe(&ring);
if (!sqe) {
fprintf(stderr, "SQE 부족\n");
break;
}
io_uring_prep_read(sqe, in_fd, buf, BUFFER_SIZE, 0);
// 큐에 제출
io_uring_submit(&ring);
// 완료 이벤트 대기
if (io_uring_wait_cqe(&ring, &cqe)) continue;
if (cqe->res <= 0) {
reading = false; // EOF 또는 오류
} else {
size_t bytes_read = cqe->res;
// 쓰기 요청 제출
sqe = io_uring_get_sqe(&ring);
if (sqe) {
io_uring_prep_write(sqe, out_fd, buf, bytes_read, 0);
io_uring_submit(&ring);
}
}
io_uring_cqe_seen(&ring, cqe);
}
free(buf);
io_uring_queue_exit(&ring);
close(in_fd);
close(out_fd);
return 0;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
printf("사용법: %s <원본> <대상>\n", argv[0]);
return 1;
}
return copy_file(argv[1], argv[2]);
}
컴파일 방법
위 코드를 컴파일하려면 다음과 같이 gcc 명령어를 사용하세요:
gcc -o filecopy filecopy.c -luring
주요 활용 분야
고성능 스토리지 엔진
데이터베이스나 키-밸류 저장소와 같은 시스템은 디스크 I/O 성능에 민감합니다. liburing을 통해 다수의 I/O 요청을 배치 처리함으로써 컨텍스트 스위칭을 줄이고, 전체 처리 지연을 감소시킬 수 있습니다.
비동기 네트워크 서비스
웹 서버, 프록시, 게임 백엔드 등 실시간 통신이 요구되는 애플리케이션에서 liburing은 연결 수락, 데이터 송수신, 타이머 처리 등을 모두 동일한 비동기 프레임워크 내에서 수행할 수 있게 합니다. 특히 io_uring의 linked operations 기능을 활용하면 복잡한 상태 머신 없이도 연쇄적인 작업을 정의할 수 있습니다.
생태계 및 관련 기술
- Kernel 5.1+: io_uring은 커널 버전에 따라 지원 기능이 달라지므로 최신 안정 커널 사용을 권장합니다.
- liburing-rs: Rust 생태계에서도 liburing 기반의 바인딩이 활발히 사용되며, Tokio 등의 런타임과 통합됩니다.
- Ceph, MySQL, Redis: 일부 고성능 오픈소스 프로젝트들이 실험적으로 io_uring을 도입하여 I/O 성능을 개선 중입니다.