mcpField
I
io-uring

io-uring

github.com/mohitmishra786開発269289 回インストール18 週間前に更新
リポジトリ

io-uring について

Linux io_uring のキューモデル、liburing API、非同期操作、Rust 連携を Agent 向けに解説するガイドです。高スループットのネットワークやディスクサービスの I/O 設計を検討する際に、性能上の選択肢やセキュリティ上の注意点を把握できます。

主な機能

  1. 01SQE と CQE のキューモデル
  2. 02liburing のファイル・ネットワーク操作
  3. 03マルチショット accept/recv とバッファリング
  4. 04固定ファイル、登録バッファー、ゼロコピー送信
  5. 05tokio-uring の Rust 連携

活用シーン

  1. 01高スループットの Linux ネットワーク・ディスクサービス構築
  2. 02io_uring と epoll の比較検討
  3. 03多数接続向けマルチショット accept/recv の実装
  4. 04Rust での非同期 I/O 統合

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill io-uring

インストール後、Claude Code で/io-uringを入力して読み込まれたか確認します。

詳細

io_uring

目的

Linux io_uringについて、エージェント向けに説明します。サブミッション/コンプリーションキューモデル(SQE/CQE)、liburing API、マルチショットのaccept/recv、提供バッファリング、固定ファイルと登録済みバッファ、ゼロコピー送信、tokio-uringとのRust統合、epollとのパフォーマンス比較、セキュリティ上の考慮事項を扱います。

使用する場面

  • Linux 5.1以降で高スループットのネットワークサーバーやディスクサーバーを構築する
  • システムコールを減らすため、epoll + スレッドプールを置き換える
  • 接続数の多いサービス向けに、マルチショットのaccept/recvを実装する
  • IORING_OP_SEND_ZCでゼロコピーのネットワーク通信を使用する
  • tokio-uring経由でRustの非同期I/Oを統合する
  • ワークロードに対するio_uringとepollの性能を評価する

ワークフロー

1. SQ/CQモデル
Application                    Kernel
    │                            │
    ├── mmap SQ ring ───────────►│ submission queue (SQE)
    ├── mmap CQ ring ◄──────────│ completion queue (CQE)
    ├── io_uring_submit() ──────►│ processes SQEs
    └── io_uring_wait_cqe() ◄──│ posts CQEs

各SQEは1つの操作を記述し、各CQEは結果とuser_dataクッキーを報告します。

2. liburingの最小限の例
#include <liburing.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(void) {
    struct io_uring ring;
    io_uring_queue_init(32, &ring, 0);

    int fd = open("test.txt", O_RDONLY);
    char buf[4096];

    struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
    io_uring_prep_read(sqe, fd, buf, sizeof(buf), 0);
    io_uring_sqe_set_data(sqe, (void *)1);

    io_uring_submit(&ring);

    struct io_uring_cqe *cqe;
    io_uring_wait_cqe(&ring, &cqe);
    if (cqe->res >= 0)
        printf("read %d bytes\n", cqe->res);
    else
        perror("read");

    io_uring_cqe_seen(&ring, cqe);
    io_uring_queue_exit(&ring);
    close(fd);
    return 0;
}
gcc -o uring_read uring_read.c -luring
./uring_read
3. よく使われるprep操作
関数操作
io_uring_prep_readファイルの読み取り
io_uring_prep_writeファイルの書き込み
io_uring_prep_recvソケットの受信
io_uring_prep_sendソケットの送信
io_uring_prep_accept接続の受け入れ
io_uring_prep_connectアウトバウンド接続
io_uring_prep_poll_addfdのポーリング
io_uring_prep_timeoutタイムアウト/リンクタイムアウト
// Batch multiple SQEs before single submit
for (int i = 0; i < n; i++) {
    sqe = io_uring_get_sqe(&ring);
    io_uring_prep_read(sqe, fds[i], bufs[i], sizes[i], 0);
    io_uring_sqe_set_data(sqe, (void *)(intptr_t)i);
}
io_uring_submit(&ring);
4. マルチショット操作
// Multi-shot accept — one SQE handles many connections
sqe = io_uring_get_sqe(&ring);
io_uring_prep_multishot_accept(sqe, listen_fd, NULL, NULL, 0);
io_uring_sqe_set_data(sqe, (void *)ACCEPT_COOKIE);

// Loop on CQEs until CQE_FLAG_MORE is clear
while (1) {
    io_uring_wait_cqe(&ring, &cqe);
    if (cqe->user_data == ACCEPT_COOKIE) {
        int client_fd = cqe->res;
        if (client_fd >= 0)
            handle_client(client_fd);
        if (!(cqe->flags & IORING_CQE_F_MORE))
            break;  // re-arm accept SQE
    }
    io_uring_cqe_seen(&ring, cqe);
}
5. 提供バッファリング
#include <liburing.h>

#define BUF_GROUP 0
#define BUF_SIZE  4096
#define BUF_COUNT 64

struct io_uring_buf_ring *buf_ring;
char bufs[BUF_COUNT][BUF_SIZE];

// Setup buffer ring
buf_ring = io_uring_setup_buf_ring(&ring, BUF_COUNT, BUF_GROUP, 0, &ret);
for (int i = 0; i < BUF_COUNT; i++)
    io_uring_buf_ring_add(buf_ring, bufs[i], BUF_SIZE, i, BUF_COUNT - 1 - i, 0);
io_uring_buf_ring_advance(buf_ring, BUF_COUNT);

// Recv with provided buffers
sqe = io_uring_get_sqe(&ring);
io_uring_prep_recv_multishot(sqe, sock_fd, NULL, 0, 0);
sqe->buf_group = BUF_GROUP;

カーネルがリングからバッファを選択するため、受信ごとのバッファ割り当てが不要になります。

6. 固定ファイルと登録済みバッファ
// Register files — avoids per-op fd table lookup
int fds[64];
io_uring_register_files(&ring, fds, 64);
io_uring_prep_read(sqe, 0, buf, size, offset);  // index 0, not fd

// Registered buffers — pinned, DMA-friendly
struct iovec iov = { .iov_base = buf, .iov_len = size };
io_uring_register_buffers(&ring, &iov, 1);
io_uring_prep_read_fixed(sqe, fd, buf, size, offset, 0);
7. ゼロコピー送信
sqe = io_uring_get_sqe(&ring);
io_uring_prep_send_zc(sqe, sock_fd, data, len, 0, 0);
// May complete with IORING_CQE_F_MORE — wait for notification CQE

カーネル6.0以降と、NIC/ドライバーのサポートが必要です。利用できない場合はコピー方式にフォールバックします。

8. tokio-uring(Rust)
use tokio_uring::fs::File;

#[tokio_uring::main]
async fn main() -> std::io::Result<()> {
    let file = File::open("test.txt").await?;
    let buf = vec![0u8; 4096];
    let (res, buf) = file.read_at(buf, 0).await;
    println!("read {} bytes", res?);
    Ok(())
}
cargo add tokio-uring
9. io_uringとepollの比較
項目epollio_uring
システムコール操作ごとにepoll_wait + read/writeSQEをまとめて単一のsubmit
バッファー管理アプリが割り当てる提供バッファー
ゼロコピーsendfile、手動で実装SEND_ZCを標準搭載
複雑さ低い高い
カーネルバージョン2.6以降5.1以降(機能によって異なる)
Choose io_uring when
├── Syscall overhead is measurable bottleneck
├── High connection count with multi-shot
└── Kernel 6.x+ with needed op support

Stay on epoll when
├── Simple app, portability matters
└── Team familiarity outweighs gains
10. セキュリティ上の考慮事項
# Restrict unprivileged io_uring (some distros disable by default)
sysctl kernel.io_uring_disabled   # 0=enabled, 1=disabled, 2=allow registered
sysctl kernel.io_uring_group      # gid allowed when disabled=2

io_uringは攻撃対象領域となってきました。カーネルにパッチを適用し、信頼できないコードはサンドボックス内で実行してください。

よくある問題

症状原因対処法
prepで-EINVALが発生するカーネルがその操作をサポートしていないio_uring_get_probe()を確認する
wait_cqeでハングするsubmitが不足しているSQEの後にio_uring_submitを呼び出す
バッファーが返却されない提供バッファーが再追加されていない消費後にbuf_ring_addを呼び出す
SEND_ZCが完了しない2つ目のCQEが必要IORING_CQE_F_MOREがクリアされるまで待機する
epollより遅いバッチサイズが小さいSQEをまとめて処理し、SQPOLLを使用する
権限が拒否されるio_uringが無効になっているsysctlを設定するか、必要なケイパビリティを付与して実行する

関連スキル

  • skills/async-io/dpdk — ネットワーク向けのカーネルバイパス方式
  • skills/async-io/af-xdp — パケットI/O向けのXDPソケット経路
  • skills/observability/ebpf — io_uringイベントのトレース
  • skills/rust/rust-async-internals — tokio-uringの基盤となる非同期モデル
  • skills/profilers/strace-ltrace — epollとのシステムコール比較
  • skills/kernel/kernel-internals — カーネルI/Oサブシステムの概要

コメント