Java Advance Concepts
Java Advance Concepts
Transactions/s [K/s]
arXiv:2512.04859v1 [[Link]] 4 Dec 2025
Bandwidth [GiB/s]
30
We study how modern database systems can leverage the Linux 300
376.4 30.5
5x
1x
2.0
io_uring interface for efficient, low-overhead I/O. io_uring is an 20
2.3
1.06x
200 1.10x
asynchronous system call batching interface that unifies storage 100
173.0 183.5 10 12.0 13.2
and network operations, addressing limitations of existing Linux 0 0
I/O interfaces. However, naively replacing traditional I/O interfaces libaio io_uring io_uring epoll io_uring io_uring
with io_uring does not necessarily yield performance benefits. To (Opt.) (Opt.)
Figure 1: Performance comparison between traditional I/O in-
demonstrate when io_uring delivers the greatest benefits and how
terfaces and io_uring in a buffer manager and network shuf-
to use it effectively in modern database systems, we evaluate it
fle. Naive use only yields modest gains, whereas designs that
in two use cases: Integrating io_uring into a storage-bound buffer
fully exploit io_uring more than double the performance.
manager and using it for high-throughput data shuffling in network-
bound analytical workloads. We further analyze how advanced
io_uring features, such as registered buffers and passthrough I/O,
production-grade database systems, incur system-call and context-
affect end-to-end performance. Our study shows when low-level
switch overhead, consuming a significant fraction of CPU cycles
optimizations translate into tangible system-wide gains and how
without saturating these devices [41]. These inefficiencies widen the
architectural choices influence these benefits. Building on these
hardware–software gap and make low-overhead I/O mechanisms
insights, we derive practical guidelines for designing I/O-intensive
central to modern database systems.
systems using io_uring and validate their effectiveness in a case
Challenges of user-space I/O. User-space I/O frameworks such
study of PostgreSQL’s recent io_uring integration, where applying
as DPDK, SPDK, and RDMA bypass the kernel and can deliver
our guidelines yields a performance improvement of 14%.
high performance on dedicated hardware [27, 35, 41]. However,
operating entirely in user space removes OS abstractions such as
PVLDB Reference Format:
Matthias Jasny, Muhammad El-Hindi, Tobias Ziegler, Viktor Leis, file systems and TCP networking, making integration difficult for
and Carsten Binnig. io_uring for High-Performance DBMSs: When and production databases that rely on them. These stacks also require
How to Use It. PVLDB, 19(1): XXX-XXX, 2026. exclusive control of SSDs or NICs [11, 18, 30], which may conflict
doi:[Link]/[Link] with deployments where devices must be shared. Consequently,
user-space I/O, despite its advantages, has not seen wide adoption
PVLDB Artifact Availability: and is used mainly in specialized, tightly controlled environments
The source code, data, and/or other artifacts have been made available at rather than general-purpose systems [11, 22].
[Link] io_uring features for efficient I/O. The Linux io_uring inter-
face [4] is a promising candidate for bridging the gap between
1 Introduction efficient I/O and the preservation of common kernel abstractions.
Modern hardware and the I/O bottleneck. Modern PCIe 5.0 It combines three key features, distinguishing it from earlier kernel
hardware, including NVMe SSDs such as the Kioxia CM7-R (2.45M I/O interfaces. First, a unified interface integrates storage, network,
IOPS) and NICs such as the ConnectX-7 (400 Gbit/s), sustains mil- and other system calls into one framework. Second, fully asyn-
lions of IOPS and hundreds of gigabits per second of throughput, chronous execution overcomes limitations of existing asynchronous
yet conventional I/O interfaces struggle to saturate them [23, 24, interfaces, allowing applications to perform useful work while I/O
34, 38, 40]. In particular, kernel-based I/O interfaces, as still used by operations complete in the background. Third, batched submission
and completion process multiple operations with a single system
This work is licensed under the Creative Commons BY-NC-ND 4.0 International call, amortizing system call overhead and context switches. These
License. Visit [Link] to view a copy of
this license. For any use beyond those covered by this license, obtain permission by
features make io_uring attractive for database systems that issue
emailing info@[Link]. Copyright is held by the owner/author(s). Publication rights large numbers of storage and network I/O operations.
licensed to the VLDB Endowment. Low-overhead I/O with io_uring? However, io_uring is not a
Proceedings of the VLDB Endowment, Vol. 19, No. 1 ISSN 2150-8097.
doi:[Link]/[Link] panacea. Simply replacing traditional I/O interfaces with io_uring
does not necessarily yield substantial performance benefits. As
User Space op3
Kernel Space Application Thread blocking
async worker pool Kernel Space
Fallback:
op4
SQ io_uring_enter() wait "worker-based"
(2c) ...
Ring async
Figure 1 shows, using io_uring off the shelf instead of libaio for
well with the demands of high-speed DBMSs. Below, we describe
storage I/O in a buffer manager, or instead of epoll for a network
these capabilities in more detail and their implications for DBMSs.
shuffle, only modestly improves performance (by 1.06× and 1.10×,
Unification of I/O with io_uring. Traditional DBMSs rely on
respectively). In contrast, when the system is explicitly designed
synchronous system calls such as read() and write(), which pro-
around io_uring’s capabilities (e.g., batching) and uses appropriate
vide a simple, uniform abstraction but scale poorly due to their
optimizations (e.g., registered buffers), the end-to-end performance
blocking behavior. To enable non-blocking network I/O, Linux in-
improvements become much more pronounced: 2.05× for the buffer
troduced epoll, which allows applications to monitor multiple
manager and 2.31× for the network shuffle.
sockets for readiness. For storage, libaio provided a separate API
These observations motivate our three research questions to
that in practice was mostly restricted to direct block I/O and often
guide DBMS system builders in using io_uring:
lacked true asynchronous execution. This fragmentation of asyn-
(1) When to use io_uring? Under which system conditions – espe-
chronous I/O interfaces forced developers to combine epoll and
cially high I/O-intensive scenarios – does io_uring provide the
libaio, leading to duplicated code paths and limited concurrency
greatest benefit?
between storage and network operations. io_uring eliminates the
(2) How to integrate io_uring? How should a DBMS architecture
need for such hybrid designs by unifying storage and network (as
incorporate io_uring to exploit its capabilities effectively?
well as other system calls) under a single fully asynchronous API.
(3) How to tune io_uring? Which io_uring features most strongly
Its capabilities continue to expand beyond I/O-related system calls
influence DBMS performance?
(e.g., madvise), moving toward a general-purpose asynchronous
Contributions and outline. To answer these questions, we present
execution model for Linux. The unified interface enables DBMSs to
the first analysis of io_uring across both storage- and network-
overlap network and disk I/O more efficiently within a single path,
bound workloads in database systems. We evaluate io_uring us-
simplifying system design and reducing context switching.
ing two complementary use cases supplemented with microbench-
Asynchronous architecture. At a high level, io_uring serves as
marks. First, we integrate io_uring into a transactional storage
a unified asynchronous layer atop existing kernel I/O subsystems,
engine on NVMe SSDs to examine storage-bound workloads (Sec-
such as the block layer for storage devices and the TCP/IP stack
tion 3). Second, we employ io_uring for data shuffling in a dis-
for networking. It is implemented in the Linux kernel (Figure 2,
tributed analytics engine on 400 Gbit/s networks, representing
right) and typically accessed through the liburing user-space li-
network-bound workloads (Section 4). From these case studies,
brary [9]. In contrast to epoll’s readiness-based polling approach,
we derive general principles for effective io_uring use and validate
io_uring employs a completion-based model, notifying applications
them by improving PostgreSQL’s io_uring backend to achieve more
after operations complete rather than when they become possible.
than 10% of additional speedup (Section 5).
It implements this model using two memory-mapped ring buffers
with configurable capacity: the Submission Queue (SQ) and the Com-
2 Background: Understanding io_uring
pletion Queue (CQ). These queues are shared between user space
io_uring was introduced into the Linux kernel in 2019 and has and the kernel, avoiding additional data copies when submitting
since been actively developed and optimized. Despite this progress, and completing requests. Applications enqueue I/O requests in the
there has been little work on understanding how to adapt it to the SQ, and their corresponding completions later appear in the CQ.
requirements of database systems. This section therefore provides Because completions may arrive out of order, each request carries
the background needed to understand how io_uring can be used in a user-defined identifier to match submissions and completions.
DBMSs and how its design influences performance. We highlight io_uring further supports request linking to enforce operation or-
two aspects that distinguish io_uring from existing I/O backends: dering for multiple elements in the SQ.
its application interface and its internal execution model, both of Batch processing. While epoll can report multiple readiness
which enable high performance for data-intensive systems. events, each I/O operation, such as read(), still requires its own
syscall. In contrast, io_uring enables applications to enqueue multi-
2.1 Interface of io_uring ple I/O requests in the SQ before triggering their submission with
Through its three key capabilities (unified I/O, asynchronous ex- a single io_uring_enter syscall. Similarly, multiple completions
ecution, and batching), io_uring provides an interface that aligns can be retrieved from the CQ in one step. This batching capability
2
amortizes syscall overhead and reduces context switches, allowing microbenchmark, issuing NOPs that were handled by io_worker
the kernel to process operations in bulk. Even modest batch sizes threads added an average overhead of 7.3 microseconds compared
(e.g., 16 operations) reduce the CPU cycles per operation by roughly to inline execution. This additional cost results from offloading to
5–6× compared to single-operation submission as shown below: a separate thread and synchronization between the worker and
syscall cost
submission context. Frequent fallback or a large number of active
Cycles per OP
1000 is amortized io_worker threads typically indicates suboptimal I/O patterns and
may warrant application-level redesign [5–7].
500 Avoiding preemptions for completion-handling. When an
0
asynchronous operation finishes, io_uring must run task_work in
1 2 4 8 16 32 64 128 256 the kernel to place the completion entry into the CQ (step 3 in
Batch Size Figure 3). By default, this task_work runs whenever the application
As we will show in our use case discussions, DBMSs often have transitions from user to kernel space. If the thread is busy (for exam-
opportunities to issue I/O requests in batches, for example, during ple, during a join or scan), the kernel may issue an inter-processor
buffer-pool eviction or group commits [32, 36, 37]. However, exces- interrupt (IPI) to process pending completions. This effectively pre-
sive batching can also introduce drawbacks; therefore, it must be empts the application, disrupts cache locality, increases jitter, and
tuned carefully to yield clear benefits. reduces batching efficiency. To mitigate these effects, io_uring offers
the COOP_TASKRUN flag (CoopTR), which reduces IPIs and allows
2.2 Inner Workings of io_uring applications to delay task_work. However, completions are still pro-
To effectively tailor DBMSs to io_uring, it is important to under- cessed on any kernel-user transition, including unrelated syscalls
stand how I/O requests are executed. In the following, we examine such as malloc(). Because preemptions have side effects, both
the internals of io_uring and discuss other important aspects. the default and cooperative modes are ill-suited for modern high-
Issuing I/O requests. io_uring supports two ways to issue I/O in performance DBMSs. The DEFER_TASKRUN flag (DeferTR) only runs
the kernel (step (1) in Figure 3). In the default mode, the application task_work on io_uring_enter calls, making it the recommended
thread (top left) calls io_uring_enter and transitions into kernel mode since it gives applications more control and eliminates un-
mode, where it processes submissions and completions. The syscall wanted preemptions. We therefore use it for the remainder of the
can either block until a specified number of completions are avail- paper unless stated otherwise.
able or return immediately. In contrast, when applications set up Other features for modern hardware. io_uring is designed to
io_uring with the SQPoll mode, they avoid user–kernel transitions fully exploit modern hardware capabilities, supporting a variety of
(syscalls) on the submission path by decoupling submission from additional features. These span both high-level application optimiza-
execution. A dedicated kernel thread (cf. Figure 3, bottom left) con- tions and low-level runtime tuning for efficient asynchronous I/O.
tinuously polls the SQ, issues I/O on behalf of the application, and Key features include buffer registration and pinning to reduce mem-
posts results to the CQ. When no new requests are submitted, the ory management overhead, multishot operations, polling modes,
SQPoll thread enters a sleep state after a configurable timeout. In a and advanced request scheduling. In the remainder of this paper,
dedicated microbenchmark, we measured that waking this thread we examine how database engines leverage these mechanisms to
introduces a non-trivial latency of roughly 30 microseconds. As implement efficient I/O.
our study later demonstrates, choosing the most beneficial execu-
tion strategy requires a thorough understanding of the application 3 Efficient Storage I/O with io_uring
architecture and workload characteristics.
Modern NVMe devices can sustain millions of IOPS, yet conven-
Execution paths in io_uring. I/O in io_uring can follow three
tional I/O stacks rarely reach this potential [23, 27]. To explore if
main paths as shown in Figure 3 (steps 2a-c):
and how io_uring can close this gap, we discuss our three research
(2a) Inline execution. When processing submissions, io_uring first at-
questions (when to use, how to integrate, and how to tune io_uring)
tempts to complete requests inline, for example, when reading from
in the context of a buffer-managed storage engine.
a socket that has data already available. Such operations execute
We follow a stepwise approach during its design to highlight
immediately and their completion is posted to the CQ.
how io_uring’s key capabilities impact system performance. After
(2b) Non-blocking execution. If an operation cannot be completed in-
our use case discussion, we use targeted microbenchmarks to iso-
line, its handling depends on its type. For pollable operations, such
late specific io_uring behaviors in the storage context and provide
as non-blocking socket reads, io_uring installs an internal event
insights for estimating achievable I/O gains.
handler (io_async_wake()) that is executed when the socket be-
comes readable (Figure 3, 2b). By default, io_uring waits indefinitely
for the operation unless a timeout via OP_LINK_TIMEOUT is set. 3.1 Use Case: Buffer-Managed Storage Engine
(2c) Blocking execution. Certain operations cannot be executed We use a buffer-managed storage engine as our primary use case be-
asynchronously; for instance, blocking filesystem calls, such as cause the buffer manager is a critical component in out-of-memory
fsync, or large storage reads. In such cases, io_uring delegates exe- database workloads, sitting directly on the I/O path of every transac-
cution to worker threads (io_worker). This fallback is slower and tion. It continuously orchestrates data movement between memory
incurs higher overhead than the native asynchronous paths. Appli- and high-performance SSDs, making it a crucial component for
cations can explicitly request this behavior using the IOSQE_ASYNC DBMSs as the main interface to the storage. Before diving into the
flag, which forces execution in a worker thread. In a dedicated details, we first outline the buffer manager’s core responsibilities
3
41 Synchronous I/O Asynchronous I/O +2nd Core
Buffer Pool (3) read
TX1 (1) Page Table (fixed size)
Throughput [tx/s]
500K 546.5
fix(41) PageId 1 27 1 33
X 400K
2.05x
376.4
PageId 27 300K
...
(4) 300.5
unfix(41) PageId 33 200K 216.6 237.8
173.0 183.5
TX10 Buffer Manager (2) evict 33 100K
16.5 16.5 19.1
(write) 0K
.
nc - fs u ll ll
Sy in g in g t a io r in
g
tch Bu thr Po Po
Legend: Buffer frame X Eviction candidate
Database page six
ur c. ur vic
io_ Syn io_ tchE
lib bers o_u bers +Ba bmit Reg
i i Fi Pa
ss
+IO +S
Q
Po a +F + S u + +
+B
Figure 4: Overview of the buffer-managed storage engine
Figure 5: YCSB throughput (100% uniform updates, one up-
design. Cold pages are evicted and written to disk freeing
date per transaction) under different buffer manager designs
space that is used to cache frequently accessed pages.
and I/O execution modes. io_uring features and design opti-
mizations are enabled incrementally from left to right, in-
creasing transaction throughput from 16.5 k to 546.5 k TPS.
and architecture (see Figure 4). A solid understanding of the appli-
cation characteristics is essential for exploiting io_uring effectively.
Buffer manager overview. A buffer manager caches frequently
accessed pages and loads or evicts them as needed. When a re- in a roughly 70% page fault probability under uniform updates with
quested page is not present in the buffer pool, a page fault triggers 4 KiB pages, producing an I/O-bound workload well suited for stor-
a read I/O to retrieve it from storage. If the buffer pool is full, the age analysis. For TPC-C, we use 1 and 100 warehouses to study the
buffer manager must select a page for eviction; if it is dirty, it is effects of a mostly in-memory vs. a mostly out-of-memory setting.
written back before its buffer frame is reused. Because these opera- System conditions. We evaluate several buffer manager configu-
tions lie on the critical transaction path, their efficiency is crucial rations on our 3.7 GHz AMD server (Kernel 6.15) with an array of
for sustaining high throughput. Although background tasks, such eight modern PCIe 5.0 NVMe SSDs (Kioxia CM7-R). The configura-
as checkpointing, also interact with the buffer manager and issue tions range from fully synchronous to batched and asynchronous
additional I/O, we ignore them for simplicity. variants to study how the workloads interact with system condi-
Buffer manager architecture. The buffer manager maintains a tions. All configurations utilize a single-threaded setup, in which
preallocated pool of buffer frames and a page table mapping logical one core handles transaction processing and I/O requests. This setup
page identifiers to frames, along with metadata such as reference isolates I/O behavior from concurrency effects, allowing more pre-
bits and dirty flags. It exposes two primitives [16]: fix(page_id) cise analysis of performance improvements. Later, in Sections 4
(1) checks whether the requested page resides in the buffer pool and 5.2, we extend the analysis to multithreaded configurations.
and loads it from storage (3) if not, evicting (2) another page if
necessary, while unfix(page_id) (4) releases the page and marks 3.3 Using io_uring in the Storage Engine
it dirty if modified. When the pool is full, a replacement policy Traditional buffer managers perform I/O through blocking system
selects victims. In this paper, we use clock-sweep [20], a common calls such as pread() and pwrite(), where each I/O request must
algorithm in DBMS: pages are marked during the first pass and, if complete before the thread can proceed. As a performance baseline,
still unreferenced on the second pass, dirty pages are written back we implement a synchronous buffer manager on top of io_uring
before the frame is reused. The storage engine includes a B-tree by submitting one request at a time and waiting for its completion,
index for tuple access and updates. When the working set fits in ensuring that the DBMS thread has at most one outstanding I/O.
memory, these operations complete without I/O; otherwise, page Although this baseline uses io_uring’s submission and completion
faults and evictions place I/O on the critical path, coupling buffer queues for consistency with later variants, it does not exploit its
management with application logic. asynchronous or batching features.
When io_uring does not help. This setup is the simplest form of
3.2 Workload & System Conditions I/O execution, where the transaction thread blocks on every page
As mentioned in Section 1, the question when to use io_uring – fault or for eviction. Consequently, throughput is directly tied to
when io_uring provides measurable performance gains – depends device latency, and using io_uring does not result in performance
on the given workload and system conditions. In this section, we gains. For the update-heavy YCSB workload mentioned earlier, our
present a simple back-of-the-envelope model to estimate the ex- posix-based and io_uring-based implementation reaches a single-
pected performance impact of various design choices, based on I/O threaded throughput of 16.5 k tx/s (Figure 5, Posix and io_uring).
cost and CPU utilization. These models show how engineers can Because in-memory updates are negligible compared to storage
predict expected gains from io_uring optimizations and validate latency, both implementations are I/O-latency bound.
their system implementation. Modeling the bottleneck. To validate the performance results,
Workload conditions. To capture the impact of different work- we use a simple latency-based model derived from the operation
load characteristics, we use two standard DBMS benchmarks: single- costs in Table 1. Assuming a 70% page fault rate and an average
statement, I/O-intensive YCSB-like transactions and the more com- read-plus-write latency of 70 + 12 = 82 𝜇s for our SSD device, the ex-
1
pected throughput is 0.7×82×10
plex, compute-bound TPC-C workload. The experiments use a small −6 ≈ 17.4 k tx/s. The estimate aligns
1 GB buffer pool. For YCSB, we load 10 million tuples (8-byte key, with the measured 16.5 k tx/s, confirming that I/O latency rather
128-byte value), which with index structures and metadata results than CPU or software overhead limits synchronous performance.
4
As a consequence, higher throughput can be achieved by reduc- synchronization. Considering such details is important for accurate
ing effective I/O latency or amortizing the latency of one request performance modeling, as shown later.
through batching. CPU, the new bottleneck. With up to 128 fibers, throughput rises
Table 1: I/O numbers used for performance modeling. by nearly an order of magnitude to 183 k tx/s (Figure 5, +Fibers).
Under the same asynchronous execution scheme, libaio reaches
Single Single Transaction Single Batch Batch
Read Write Execution Read Read Write 173 k tx/s, so we continue the analysis on io_uring, which provides
70 𝜇s 12 𝜇s 8264 clk 10200 clk 5400 clk 5700 clk higher throughput and exposes additional optimization opportu-
I/O Latency CPU Cycles nities. At this concurrency level, the system becomes CPU- rather
than latency-bound: concurrent fiber execution hides I/O latency
3.3.1 Using io_uring to Batch Writes
and the CPU is fully utilized. We therefore switch from a latency-
With synchronous I/O, performance is bound by I/O latency,
to a cycle-based model that accounts for per-transaction CPU cost.
since each page fault triggers a blocking writeback of a dirty page
Using hardware cycle counters (rdtsc), we measure transaction
before the next read can proceed. Although io_uring cannot mag-
logic (B-tree traversal and update) as 𝑐 tx = 8,264 cycles in an in-
ically reduce device latency, its batching feature can enable us to
memory run, and I/O processing (submission and completion) as
reduce the impact on the critical path.
𝑐 io = 𝑐 read-single +𝑐 write-batch = 15,900 cycles (Table 1). For a 3.7 GHz
Amortizing eviction cost. We leverage io_uring to introduce
core and a page fault rate of 𝑟 𝑝 𝑓 = 70%, the expected throughput
batched write submission for the buffer manager’s eviction path. In- clock frequency 9
3.7×10
is 𝑐𝑡𝑥 +𝑟 𝑝 𝑓 ×𝑐𝑖𝑜 = 8264+0.7×15900 ≈ 190.8 k tx/s, which matches
stead of evicting and writing one page at a time, the buffer manager
collects multiple victims and issues their writes together with a sin- the measured 183 k tx/s. This confirms that CPU overhead, rather
gle io_uring_enter() call. While execution remains synchronous than I/O latency, now dominates performance, as intended with
and reads and writes do not yet overlap, batching lowers submission asynchronous execution.
overhead and exploits device-level parallelism, demonstrating how
a minor architectural change can benefit from io_uring’s strengths. 3.3.3 Using io_uring to Batch Reads
Performance implications. Batching write operations improves In the initial asynchronous design, each fiber submits its I/O
performance by about 14%, reaching 19 k tx/s (compare Figure 5, request right before blocking and is woken up once the I/O com-
+BatchEvict) because submission overhead for eviction is amortized. pletes. This hides I/O latency by overlapping reads and writes but
Eviction writes are issued in batches, so their latency is incurred incurs syscall overhead for each I/O. We therefore introduce batched
once per batch rather than per eviction. This amortizes the cost read submission, which groups read requests from multiple fibers
across 𝑁 evictions and leaves the 70𝜇s read latency as the dominant before entering the kernel via io_uring_enter(). The batched
term in the latency model from the previous section. The expected submission amortizes syscall overhead and exploits device-level
1
throughput is 0.7×70×10 −6 ≈ 20.4 k tx/s. The measured and pre-
parallelism, reducing per-I/O cycle cost (Table 1) and improving
dicted results align closely, confirming that batching removes the CPU efficiency beyond latency hiding.
write latency from the latency-bound path and effectively mitigates Adaptive batching. Read batching improves throughput by low-
latency through amortization rather than elimination. ering per-I/O cost but may introduce queuing delays if the runtime
waits too long to collect requests, while very small batches negate
3.3.2 Using io_uring for Asynchronous I/O the amortization benefit. Our runtime therefore uses adaptive batch-
While batched writes amortize write latency, the buffer manager ing, adjusting the batch size based on the ratio of outstanding I/Os
still operates synchronously, blocking on page faults and leaving the to waiting fibers. When many I/Os are in flight, additional submis-
CPU idle during I/O. Multiple threads, as studied in Section 3.6, hide sions are deferred to increase amortization; when few are pending,
this latency but introduce synchronization and scheduling overhead. batches are flushed earlier to keep the CPU busy. This feedback
To hide latency in our single-threaded design, we therefore adopt mechanism maintains high device utilization while avoiding stalls
asynchronous transaction execution to overlap I/O and computation. from an empty ready queue.
Overlapping compute & I/O. io_uring’s completion-based model Impact of adaptive batching. Performance increases by about
integrates naturally with asynchronous runtimes such as coroutines 18%, from 183 k to 216 k tx/s (Figure 5, +BatchSubmit). Adding
or fibers. We extend the buffer manager with [Link] [2] for I/O cost for batched reads to the cycle model, 𝑐 io = 𝑐 read-batch +
cooperative scheduling, where each transaction runs as a fiber that 3.7×109
𝑐 write-batch = 11,100 cycles (Table 1), yields 8264+0.7×11100 ≈ 230 k tx/s
issues asynchronous I/O requests and yields on page faults. During
as expected throughput. The estimate aligns with the measured
this time, the io_uring-based runtime schedules other ready fibers,
216 k tx/s, confirming that adaptive read batching reduces CPU over-
keeping the CPU active.
head in the submission path and improves single-core efficiency.
Cooperative transaction execution. Fiber context switches cost
only tens of CPU cycles since they save and restore only regis-
ter state, providing efficient user-level concurrency suited for I/O- 3.4 Tuning io_uring for the Storage Engine
intensive workloads. When a suspended fiber’s I/O completes, it Utilizing io_uring’s key capabilities enabled us to implement an
is marked ready and resumed by the scheduler. Since all concur- asynchronous architecture whose performance is determined by
rency is cooperative, the B-tree implementation requires no locks CPU cycles spent on I/O processing. This forms the basis for apply-
or atomic operations between fibers. If a fiber resumes after an I/O ing io_uring’s low-level features to reduce I/O overheads. However,
delay and the data structure has changed, it restarts the B-tree tra- the effectiveness of io_uring’s features also depends strongly on
versal to ensure correctness and preserve isolation without explicit workload characteristics, as discussed next.
5
TPC-C - mostly in-memory TPC-C - mostly out-of-memory
vmcache [32], a state-of-the-art buffer manager. We reuse the asyn-
x
60K 5x chronous, batched-read configuration from the YCSB experiments
Throughput [tx/s]
.5x
35.5 19.2
Workload-dependent benefits. Figure 6 shows the results for
12
20K
TPC-C in a mostly in-memory and a mostly out-of-memory config-
10K
2.0
0K 0K uration. The io_uring-based buffer manager consistently outper-
ca
e o g fs u
ch libai urin Bu sthr P
g s +IO SQ
Po ll o ll
ca
e o g
g
fs u
ch libai urin Bu sthr Po Po
ll
s +IO SQ
ll
forms vmcache, achieving up to 12.5× higher throughput in the
vm io_ +Re +Pa vm io_ +Re +Pa
naive configuration. The primary reason is architectural: vmcache
+ +
Figure 6: TPC-C with 1 warehouse (left) and 100 warehouses
relies on blocking reads. Enabling advanced io_uring features fur-
(right) with the default transaction mix. io_uring outper-
ther improves throughput, although the relative gains depend on
forms libaio, vmcache uses blocking I/O that performs worst
the workload configuration. The memory-intensive TPC-C work-
if out-of-memory with 100 warehouses (storage-intensive).
load is largely compute-bound and many reads can be answered
from memory which limits the effect of I/O-path optimizations. In
3.4.1 Performance Evaluation with YCSB this case, +IOPoll performs slightly worse than the interrupt-driven
We cut per-I/O CPU cost by reducing three overheads: data move- baseline because polling wastes CPU cycles when I/O operations
ment (using registered buffers), storage stack (NVMe passthrough), are sporadic. +SQPoll provides no benefit for the same reason. In
and submission/completion handling (SQPoll & IOPoll). the out-of-memory setting, I/O activity rises significantly due to the
Registered buffers reduce copies. io_uring allows user-space increased cost of page loads and evictions, making optimizations
buffers to be registered once during initialization, avoiding per- more impactful.
request page pinning and kernel-user copies. The kernel then per-
forms DMA directly into user memory, eliminating these overheads. 3.5 Take-aways and Summary
For our YCSB workload, this zero-copy optimization improves When to use io_uring. Our buffer manager study shows that
throughput by about 11%, reaching 238 k tx/s (Figure 5, +RegBufs). io_uring yields meaningful gains for I/O-intensive workloads with
NVMe passthrough skips abstractions. To access NVMe de- many page faults, such as YCSB and TPC-C configurations where a
vices directly, io_uring provides the OP_URING_CMD opcode, which substantial fraction of reads miss the buffer pool and involve SSD
issues native NVMe commands via the kernel to device queues. By page loads and evictions. In compute-heavy (i.e., mostly in-memory)
bypassing the generic storage stack, passthrough reduces software- settings, the I/O path contributes little to overall cost, and io_uring
layer overhead and per-I/O CPU cost. This yields an additional 20% optimizations have correspondingly smaller impact.
gain, increasing throughput to 300 k tx/s (Figure 5, +Passthru). How to integrate it. A key insight of our study is that io_uring
IOPoll avoids interrupts. With IOPOLL, completion events are must be integrated as part of an end-to-end architectural design
polled directly from the NVMe device queue, either by the appli- rather than as a drop-in replacement. Using io_uring key features
cation or by the kernel SQPOLL thread (cf. Section 2), replacing (batching, asynchronous execution) enabled us to shift the bottle-
interrupt-based signaling. This removes interrupt setup and han- neck from device latency to CPU cycles and make the cost of I/O
dling overhead but disables non-polled I/O, such as sockets, within processing explicit, as verified by our model-based analysis.
the same ring. When using filesystems, IOPOLL requires explicit sup- How to tune it. Once the architecture exposes enough asynchro-
port and is typically available only for direct block-device access via nous I/O, low-level io_uring features can reduce per-operation CPU
O_DIRECT. As shown in Figure 5 (+IOPoll, right), completion polling overhead. However, our study revealed that the tuning benefits de-
provides an additional 21% throughput gain, reaching 376 k tx/s - pend strongly on the workload: substantial improvements arise
single-threaded. As we will show later, it also reduces latency for when I/O dominates execution time, while CPU-bound or cache-
I/O-intensive workloads (cf. Figure 9). resident workloads gain little.
SQPoll eliminates syscalls. In SQPOLL mode, a dedicated kernel
thread continuously polls the submission queue, allowing applica- 3.6 Detailed Analysis of io_uring
tions to enqueue I/O requests without calling io_uring_enter()
for each submission. This dedicates one CPU core to polling but The results in the previous section showed that realizing perfor-
eliminates most syscall and submission overheads. The kernel mance gains depends on both the system architecture and workload
thread handles I/O completions and places them into the comple- characteristics. In this section, we conduct targeted microbench-
tion queue for later consumption by the application. For our buffer marks to isolate and quantify the effects of individual mechanisms
manager (Figure 5, +SQPoll), throughput increases by about 32% to for system builders in depth and also study effects of multi-threading.
546k tx/s, corresponding to the cost previously spent in syscall and Batching effects on SSD latency. In the buffer manager design,
kernel-side processing. we used io_uring’s batching to hide I/O latency for writes and amor-
tize syscall overhead for reads. However, batching can also increase
3.4.2 Performance Evaluation with TPC-C latency variance, which is problematic for workloads requiring pre-
Unlike YCSB, which issues short, independent transactions domi- dictable response times. To quantify this effect, we vary batch sizes
nated by random I/O, TPC-C models an OLTP system with interact- for write requests to a single SSD via io_uring, fixing throughput at
ing transactions and a larger share of in-memory computation. This 1.5 MIOPS to stay below the device limit and isolate batching behav-
workload thus evaluates how io_uring optimizations perform in a ior. As shown in Table 2, small batches (e.g., size 8) keep latencies
less I/O-bound, more CPU-intensive setting. As a baseline, we use mostly below 25 µs, at the cost of slightly higher syscall frequency.
6
Method: libaio Default/RegRing/RegFDs +RegBufs +Passthru +IOPoll Optimizations: Default/RegRing/RegFDs +RegBufs +Passthru +IOPoll
Read Write io-worker
8M 1.00 active
Throughput [IOPS]
Read
6M 0.30 copy and scales better
15M
Cycles/Byte [log]
3.51x
4M 3.37x 0.10
10M From here, IPoll saturates
SSD and busy-spins
5M 2M 0.03
io-worker
0M 1.00 Auto-offload to worker- active
1 2 4 8 16 32 64 1 2 4 8 16 32 64 pool adds overheads
Worker threads [log]
Write
0.30
Figure 7: Scale-out performance for random 4 KiB reads &
0.10
writes between libaio and io_uring with incremental opti- From here, IPoll saturates
SSD and busy-spins
mizations. io_uring consistently outperforms libaio. Fur- 0.03
4KiB 8KiB 16KiB 32KiB 64KiB 128KiB 256KiB 512KiB 1024KiB
ther io_uring optimizations increase throughput by 3.4–3.5×. Block Size [log]
Figure 8: Single thread SSD performance with increasing
block sizes. Performance degrades with I/O workers, NVMe-
Larger batches reduce submission overhead but cause higher vari- passthrough is only supported until 512KiB.
ance; with batch size 128, latency spikes up to 200 µs occur as bursts
from multiple workers can temporarily overload the SSD queue
with many outstanding I/Os. Thus, even below I/O saturation, batch
size strongly influences latency distribution. For latency-sensitive and on some consumer SSDs even without O_DIRECT. Third, when
DBMSs, overly aggressive batching is counterproductive. block sizes exceed 512 KiB (max_segments) asynchronous workers
are again used internally for I/O. While large blocks improve effi-
Table 2: Impact of batch size on SSD write latency (8 workers). ciency and fully utilize PCIe 5 bandwidth, surpassing these software
Batch size: 1 8 32 64 128 256 or hardware limits causes worker fallback, reintroducing latency
Latency ⊘ [µs] 11.51 24.22 60.62 116.40 200.85 317.51 and CPU overhead in io_uring.
Latency 𝜎 [µs] ±0.95 ±1.71 ±3.91 ±12.17 ±7.47 ±33.88 The durable write problem. Durable writes are essential for data-
base systems, particularly for write-ahead logging and checkpoint-
Multi-threaded Performance. The buffer manager in the pre-
ing, yet remain costly. The standard approach, fsync, is blocking in
vious section used a single-threaded setup. We now increase the
io_uring and thus executed by fallback worker threads. Moreover,
number of threads to analyze how io_uring behaves under paral-
fsync cannot be issued by rings configured for IOPoll and must
lelism. We use one ring-per-thread for io_uring and also include
be used from a separate ring or as a traditional syscall. These con-
libaio for comparison. As shown in Figure 7, io_uring consistently
straints motivate alternatives such as opening files with O_SYNC,
outperforms libaio for both random reads and writes and exhibits
which delegates durability to the kernel, or using NVMe flushes via
near-linear scalability with the number of threads. At higher core
passthrough commands. Figure 9 compares these methods on con-
counts, the operating system’s storage stack becomes the dominant
sumer and enterprise SSDs. Enterprise SSDs with DRAM caches and
bottleneck. The benefit of io_uring optimizations increases with
Power Loss Protection (PLP) achieve microsecond-level latencies,
scale: registered buffers (+RegBufs) reduce CPU overhead, while
whereas consumer SSDs remain dominated by intrinsic millisecond-
NVMe passthrough (+Passthru) and IOPoll in particular deliver
scale fsync cost, masking worker-thread latencies. Not pinning the
substantial throughput improvements of 3.4–3.5× saturating the
fsync I/O worker to the local chiplet (+Chiplet) increases latency by
SSD array with 18 and 6 cores, respectively.
about 5%. O_SYNC-based writes perform poorly, more than twice as
Increasing block sizes. Larger block sizes for I/O can further
slow as explicit writes followed by fsync. NVMe passthrough with
amortize CPU costs when the workload allows coarser-grained ac-
explicit flush commands offers a truly asynchronous durability path
cess. We therefore evaluate how block size affects SSD performance
but requires raw device access. Linking a write and fsync in io_uring
by measuring CPU cycles per byte for reads and writes while vary-
offers no improvement over issuing them sequentially in the ap-
ing the I/O block size in a single-threaded setup. Figure 8 shows that
plication. For enterprise SSDs, durability is managed by the device
larger blocks substantially reduce CPU cost per byte, as syscall and
itself, eliminating the need for fsync. Passthrough writes with IOPoll
I/O stack overheads are amortized. With sufficiently large requests,
reduce latency by about one microsecond, showing the benefit of
a single core saturates the PCIe 5 SSD array, reaching up to 90 GiB/s
bypassing the storage stack in latency-sensitive workloads. While
for reads and 50 GiB/s for writes, close to hardware limits. This
passthrough with flush is the most efficient asynchronous option,
point is reached for writes at 128 KiB and reads at 256 KiB with
its lack of filesystem support restricts it to flash-optimized data-
+Passthru and +IOPoll enabled.
base systems. Implementing durable writes in io_uring therefore
Large blocks can backfire. However, exceeding certain thresh-
requires careful configuration to avoid performance pitfalls.
olds triggers asynchronous worker threads, signaling fallback to
slower I/O paths as discussed in Section 2.2. First, if the block size
exceeds max_hw_sectors_kb (which can be 128 KiB if the IOMMU 4 Efficient Network I/O with io_uring
were enabled), workers are spawned even at low I/O depth, as a After analyzing storage, we now focus on the networking aspects
single request surpasses the maximum DMA size. Second, with of io_uring. High-speed interconnects with link rates in the range
O_DIRECT, workers appear once the number of batched requests of 400 Gbit/s are now a commodity in modern data centers and
exceeds nr_requests (1023 on bare metal, 127 in our cloud VM), cloud deployments [1, 40]. We investigate how distributed DBMSs
7
Consumer SSD Enterprise SSD Node
Default IOPOLL Default IOPOLL Worker
4
io-worker active
9
Scan Copy
100GiB
io_uring
Latency [ms]
Latency [us]
3 in Morsels Connections
oni
1.05x
tit
to other
r
Pa
6 Send Buffers
2
Multiple Worker Nodes
3 Threads with
Probe Build ...
1 Table
local "rings".
0
1.68 1.76 1.69 1.65 4.02 1.69 1.59 0
10.55 10.49 6.50 5.69 (thread-local) Recv Buffers
c r c ru c/ c ru e r u e r u
yn ) the t yn l) th h yn nc syn al) sth sh r it sth r it sth
Fs ked +o iple Fs nua ass lus enS Sy F n u a s lu W as W as
l( in Ch (m
a P +F p rite
OW (m
a P +F P P Figure 10: Overview of the shuffle architecture with scan
Figure 9: Durable writes with io_uring. Left: Writes and fsync & probe table. Workers use morsel-driven parallelism and
are issued via io_uring or manually linked in the application. handle scanning, probe table building and network I/O.
Right: Enterprise SSDs do not require fsync after writes.
7x
cv x
ecv
40GiB/s Re
2.1
60
346.7
339.3
338.1
300GiB/s
d
C 1.5 1.
n
CR
+Z
Se
286.1
280.6
d
30GiB/s
+Z
240.7
Se
200GiB/s
cv
1.0
+Z
C lt
Re
20GiB/s C nd +Z lt fa
u
+Z Se fau De 100GiB/s 0.5
10GiB/s
C t
+Ze fau l De
D 0B/s 0.0
0B/s
C lt
C lt
C lt
C lt
cv
cv
cv
cv
+Z end
+Z end
+Z end
+Z end
+Z fau
+Z fau
+Z fau
+Z fau
Re
Re
Re
Re
1 2 4 8 16 32 1 2 4 8 16 32 1 2 4 8 16 32
S
De
De
De
De
C
C
Worker threads
Figure 11: Per-node egress bandwidth for a six node shuffle Figure 12: Memory bandwidth for the data shuffle in Fig. 11
with different tuple sizes using up to 32 worker threads. (32 Workers). Left: absolute bandwidth; right: Bandwidth
reduction normalized by achieved network throughput.
throughput. With larger tuples, the insertion rate decreases, reduc- Tuple size [log]
ing memory pressure and allowing the system to achieve higher Figure 13: Speedup of io_uring and zero-copy send epoll vs.
bandwidths. However, even for larger tuples, the system reaches at plain epoll for data shuffling across six nodes and different
most 30 GiB/s per node (Figure 11, red), well below the 400 Gbit/s tuple sizes. Zero-copy receive is only available with io_uring.
link rate, indicating that the workload is not I/O-bound.
4.4 Tuning io_uring for Network I/O above. Figure 12 shows measurements for both the default and zero-
As with storage, io_uring also provides multiple network optimiza- copy configurations. On the left, we present the system memory
tions to reduce per-I/O overhead. In the following, we discuss our bandwidth, calculated as the sum of read and write traffic from
findings on how to best use them for efficient network shuffling. hardware performance counters. For both workloads, peak sys-
Reducing memory pressure. In the Linux networking stack, send tem bandwidth approaches 400 GiB/s. Zero-copy configurations
and receive operations typically copy data between user-space and typically show equal or higher absolute memory bandwidth, pri-
kernel buffers. While these copies are negligible at moderate speeds, marily due to their higher network throughput, which increases
they become costly at high network speeds, as even a single extra overall memory traffic. To account for this effect, we normalize
copy can consume precious memory bandwidth. To address this, the measured bandwidth by the achieved network throughput. The
io_uring supports zero-copy operations, eliminating redundant data normalized plot (cf. Figure 12, right) shows that using zero-copy
copies between kernel and user space. Zero-copy send transmits for send and receive reduces effective memory bandwidth by about
data directly from pinned user-space buffers, avoiding intermediate half, as expected, since data copies are eliminated in both directions.
copies. Zero-copy receive, a more recent io_uring addition, writes End-to-end comparison with epoll. Similar to the buffer man-
received data directly into registered user-space memory. It requires ager, we compare our optimized io_uring-enabled implementation
NIC support to separate the TCP header (still handled by the kernel) to state-of-the-art approaches. For the shuffle, we use epoll as a
from the payload, so it may not be available on all network devices. baseline, a readiness-based I/O interface commonly used in existing
Zero-copy I/O reduces memory load. As shown in Figure 11, systems. Figure 13 shows the speedup of different io_uring variants
enabling zero-copy send (green) and zero-copy receive (blue) yields and an epoll-based zero-copy send implementation against a naive
visible throughput improvements across different tuple sizes com- epoll baseline without optimizations. We vary tuple sizes (smaller
pared to the default setting. For 4 KiB tuples, link bandwidth is tuples result in more random inserts into the probe table per byte
saturated with only 16 workers per node when both zero-copy transferred) and scale up to sixteen workers to avoid link satura-
paths are active, achieving full bidirectional 400 Gbit/s utilization tion and ensure a fair comparison. Without zero-copy, epoll is only
with modest CPU usage. However, for 64B tuples, zero-copy receive marginally slower than io_uring despite issuing more system calls.
does not provide additional benefits beyond zero-copy send. We This behavior stems from both implementations transferring tuples
suspect that contention between NIC traffic and CPU-driven ran- in large 1 MiB chunks, which amortizes syscall and I/O-path over-
dom memory accesses, along with resulting stalls, diminishes the head. With zero-copy send, io_uring achieves substantially better
potential gains. Since zero-copy receive is a recent kernel addition, performance, with the gap widening as the number of workers
a deeper investigation is left for future work. increases. Unlike epoll, io_uring also supports zero-copy receive,
Analyzing memory bandwidth. To understand why shuffle per- further improving performance and providing up to a 2.5× speedup.
formance is limited without zero-copy operations, we analyze sys- Overall, io_uring offers a more efficient and unified interface for
tem memory bandwidth during the scale-out experiment described network I/O, supporting batching, and zero-copy send and receive.
9
Per Node Egress Bandwidth
Latency [us]
Latency [us]
13.19
13.06
12.98
12.96
12.94
12.93
12.74
12.69
12.67
12.00
Runtime: 6.3s
Runtime: 4.6s
Node A
11.25
10 10
10.89
10.89
10.85
12GiB/s
10.66
10.42
10.41
10.33
10.33
9.37
Node B
8GiB/s 5 5
4GiB/s
Node A 0 0
0B/s
+R gR lt
+R gR lt
+R gR lt
+R gR lt
I
eg Ds
+N fs
eg Ds
+N fs
eg Ds
+N fs
eg Ds
+N fs
+R egF g
+R egF g
+R egF g
+R egF g
AP
AP
AP
AP
e au
e au
e au
e au
in
in
in
in
Bu
Bu
Bu
Bu
0.0 2.0 4.0 6.0 0.0 2.0 4.0 6.0
+R Def
+R ef
+R Def
+R Def
D
Timestamp [s]
UDP (End-to-End) TCP (End-to-End)
Figure 14: Careful tuning of the networking setup is required Figure 15: UDP and TCP latency ping-pong with 8 -byte mes-
to achieve equal bandwidth sharing. Workload: 100 GiB table sages and incrementally enabled optimizations. NAPI polling
shuffle between 2 nodes using eight workers (no probe table). reduces latency for DeferTR, but increases it with SQPoll.
4.5 Take-aways and Summary Reducing latency with io_uring. Network latency is crucial for
distributed latency-sensitive database protocols, such as transaction
When to use io_uring. Our shuffle use case shows that io_uring
coordination or replication, where microsecond-level delays accu-
provides benefits in high-throughput settings where memory band-
mulate at scale. We measure one-way and round-trip latencies for
width becomes a bottleneck. In the setup with large tuples, where
TCP and UDP using 8-byte messages to capture the minimum cost
probe table inserts are rare, and workers mainly stream tuples and
of message delivery. Both modes - deferred taskrun (DeferTR) and
perform simple partitioning, zero-copy networking enables us to
SQPoll - are evaluated, along with optimizations such as registered
saturate 400 Gbit/s links with relatively few cores. For smaller tuple
file descriptors, registered buffers, and NAPI (the networking coun-
sizes, random memory accesses during hash-table inserts dominate
terpart of IOPoll). As shown in Figure 15, SQPoll achieves lower
and limit the achievable throughput; network-path optimizations
latency than DeferTR, but the advantage disappears once NAPI is
have a relatively less significant impact but are still important for
enabled. DeferTR with NAPI yields the best overall latency, outper-
achieving optimal bandwidth.
forming SQPoll, while registered buffers have a negligible impact
How to integrate it. Treating io_uring as a drop-in replacement
for small messages and increase latency slightly. When the NIC
in a traditional I/O-worker design is inadequate. Instead, io_uring
queue is pinned to a remote chiplet, cross-chiplet interrupt handling
requires a ring-per-thread design that overlaps computation and
increases latency by 14 % for UDP and 21 % for TCP. With NAPI
I/O within the same thread. Together with careful placement of
enabled, however, remote queues cause only a negligible increase of
workers across CPU chiplets and an optimized networking stack,
less than 1 %. For reference, a DPDK-based implementation reaches
this architecture keeps cores busy and exposes sufficient concurrent
7 µs, providing a lower bound for userspace networking.
I/O for io_uring to be effective.
Send path optimizations. As shown in Figure 15, registered
How to tune it. Once the engine operates asynchronously with
buffers have little effect for very small messages, in contrast to
large batched transfers, tuning io_uring can reduce data move-
their positive impact in the storage setting (Section 3.4.1). To better
ment and CPU overhead per I/O. Registered buffers and zero-copy
understand which optimizations are most effective for different
send/receive eliminate kernel-user copies, reducing memory band-
database workloads, we vary the transfer size and report the effec-
width consumption per unit of network throughput by ≈ 2×.
tive cycle cost per transmitted byte. Figure 16 (left) shows a clear
threshold around 1 KiB: below this size, zero-copy send performs
4.6 Detailed Analysis of io_uring worse than plain io_uring due to buffer-management overheads,
In this section, we focus on important aspects of io_uring for tuning whereas for larger messages registered buffers amortize this cost
network interfaces of database systems, which we could not cover and consistently reduce per-byte CPU time. Registering rings and
before through targeted microbenchmarks. file descriptors yields only marginal improvements but introduces
Impact of network-stack configuration. To quantify the effect no observable drawbacks. Overall, zero-copy with registered buffers
of suboptimal network settings on io_uring performance, we con- is the most efficient configuration for large messages, achieving up
duct a microbenchmark using the shuffle workload. The experiment to 3.5× fewer cycles per transmitted byte than default io_uring.
transfers 100 GiB bidirectionally between two machines, each run- Receive path optimizations. We observe analogous thresholds
ning eight worker threads, and measures end-to-end throughput for the receive path (Figure 16, right). Multishot receive operations
over time. In the default configuration, we disable Nagle’s algorithm repeatedly generate completions from a single submission and are
(TCP_NODELAY) and pin NIC queues to CPU cores. Despite these set- most efficient for workloads with small messages. Once message
tings, persistent flow imbalance occurs, with one peer dominating sizes exceed roughly 1 KiB, zero-copy receive becomes more effi-
the bandwidth and starving the other (Figure 14), resulting in a total cient, and for very large messages (e.g., 13 KiB and above) even
runtime of 6.3 s. Such behavior masks potential io_uring gains at the normal single-shot receive path outperforms multishot due to
the system level. For the shuffle evaluation above we therefore used reduced per-message overheads. io_uring can also draw receive
a tuned network stack. Specifically, using fairer queue discipline buffers from a kernel-managed pool (RingBufs), but these perform
(qdisc) and configuring socket buffers for 400 Gbit/s according to worse than user-supplied buffers and are only useful in multishot
[31] balance bandwidth utilization. As shown in Figure 14, the total scenarios. Exact thresholds vary with capabilities and available
runtime is reduced by over 25%, from 6.3s to 4.6s. offloads of the NIC, but the overall pattern remains consistent.
10
Optimizations: Default/RegRing/RegFDs ZeroCopy ZeroCopy+RegBufs Optimizations: Default/RegRing/RegFDs +RingBufs +Multishot +ZeroCopy
100.0 100.0
ZeroCopy Threshold ZeroCopy Threshold Multishot Threshold
Cycles/Byte [log]
Cycles/Byte [log]
ZeroCopy becomes
10.0 more efficient 10.0 Normal Recv over-
Receive
Send
takes Multishot Recv
ZeroCopy has
1.0 higher overhead 2.90x fewer cycles 1.0
ZeroCopy Recv over-
takes Multishot Recv 3.54x fewer cycles
0.1 0.1
64B 256B 1024B 4KiB 16KiB 64KiB 256KiB 1024KiB 64B 256B 1024B 4KiB 16KiB 64KiB 256KiB 1024KiB
Buffer Size [log] Buffer Size [log]
Figure 16: Impact of incremental io_uring optimizations on the cycle cost for a single TCP connection. The best-performing
configuration depends on the shown thresholds. Registered file descriptors offer minimal benefit and are therefore omitted.
Optimizing kernel execution for sockets. Recall how io_uring (Section 2). SQPoll can improve performance when dedicating a
executes task_work inside the kernel. By default, it first attempts polling core is amortized, and latency or IOPS targets justify the
to complete an I/O operation inline in non-blocking mode and additional CPU cost. Falling back to io_workers should be avoided
falls back to internal polling only if the call returns -EAGAIN (see by ensuring that all operations, including fsync and large I/Os, can
Figure 3). For socket operations, this speculative attempt can be execute fully asynchronously (cf. Figure 8). Tuning the execution
wasteful when the application already knows the socket is empty mode to the underlying hardware helps avoid costly effects, such
(for receive) or full (for send), causing unnecessary kernel work. as cross-chiplet traffic or non-local interrupt handling (Section 4.3).
Such cases commonly occur in RPC-style communication, where (4) Use io_uring optimizations. io_uring offers a range of gen-
the response is expected only after the request. To handle this effi- eral, storage-specific, and networking-specific optimizations for
ciently, io_uring provides the RECVSEND_POLL_FIRST flag, which I/O-intensive systems. Carefully selecting these optimizations can
skips the speculative attempt and directly uses the poll set. Using reduce the per-I/O cycle cost. Some optimizations, such as regis-
PollFirst reduces the number of instructions executed and kernel tered FDs or fixed buffers for 4 KiB page-aligned storage I/O, do
work, resulting in up to 1.5× reduction in CPU cycles spent. not negatively impact performance (see Section 3.4.1). However,
mechanisms like zero-copy or multishot receive are only effective
5 Insights for System Builders when payloads exceed device-specific thresholds (cf. Figure 16).
Other optimizations, such as NVMe passthrough or IOPoll, apply
In our study, we focused on three research questions: when to use
only when no filesystem or a compatible filesystem is used.
io_uring, how to integrate it, and how to tune it. Exploring these
questions provided key insights for effectively using io_uring in
database systems. We summarize these insights as actionable guide-
lines for engineers, and then validate their practicality by applying 5.2 Optimizing PostgreSQL using Guidelines
them to enhance PostgreSQL’s I/O performance.
PostgreSQL recently added support for io_uring in version 18, en-
abling asynchronous I/O for data and WAL access [19]. We use
5.1 Guidelines this integration to illustrate how our guidelines can be used in
Based on our system case studies, we draw four practical guidelines a production-grade engine and where PostgreSQL’s architecture
for using io_uring effectively in database systems: imposes constraints.
(1) Determine if I/O is a system bottleneck. When I/O accounts GL (1): Determine if I/O is a system bottleneck. Even without
for only a small fraction of execution time, as in CPU-bound or tuning io_uring parameters or enabling additional features, Post-
cache-resident workloads, potential io_uring gains are limited. Our greSQL’s new io_uring backend achieves up to 3× higher perfor-
use cases in Section 3 and Section 4 show that io_uring is most mance in I/O-intensive workloads than the previous synchronous
effective when it reduces or amortizes the CPU cost of I/O opera- design based on blocking calls and OS readahead [19]. This shows
tions, or when it lowers the memory bandwidth consumption. As that I/O has been a dominant bottleneck and validates guideline (1)
demonstrated in the buffer manager case study, simple latency or in a real system: once I/O is identified as limiting, adopting io_uring
cycle models help to model such bottlenecks. yields measurable gains. This baseline forms the starting point for
(2) Align the architecture with io_uring capabilities. io_uring the guideline-driven improvements in Figure 17. We use 1–8 back-
enables asynchronous execution, system call batching, and a uni- end workers scanning a 32 GiB cold table via direct I/O to show
fied interface for storage and network I/O. Our buffer manager how PostgreSQL’s I/O bottleneck improves.
(Section 3.1) shows that architectural changes, such as overlapping GL (2): Align the architecture with io_uring capabilities. Post-
I/O and computation via asynchronous execution or amortizing greSQL already partially aligns with guideline (2). Backend pro-
per-I/O cost through batching, can yield large improvements. The cesses overlap computation and I/O by issuing multiple asynchro-
network shuffle (Section 4.1) shows how applications can use the nous reads and writes, aligning with io_uring’s batching capability.
ring-per-thread architecture to scale beyond a single core and enable However, PostgreSQL uses a multi-process model in which a back-
internal io_uring optimizations. end may wait on I/O submitted through rings owned by other
(3) Choose and tune the execution mode deliberately. The rec- processes. Rings are therefore not exclusively used by a single is-
ommended io_uring configuration uses DeferTR with single-issuer suer, which prevents using DeferTR, as it requires per-thread ring
for predictable task execution and controlled completion reaping ownership. A more io_uring-friendly design would use one ring
11
1 Worker 2 Workers 4 Workers 8 Workers Storage interfaces and NVMe systems. Initial systematic com-
Speedup vs. Baseline
15% 14.29%
24.81s
14.36%
13.00s
parisons of io_uring with established interfaces such as libaio and
SPDK were conducted using the fio benchmark to evaluate typical
11.86% 11.46%
6.96s 3.57s
10%
7.29% 7.52% storage workloads [13]. Ren and Trivedi extended this analysis
6.12% 26.43s 5.88% 13.83s 6.03%
5% 26.72s 14.04s
4.99%
7.42s
7.35s 4.11% 4.40% for Intel Optane SSDs, characterizing microarchitectural behavior,
3.82s 3.81s
Baseline: 28.35s Baseline: 14.87s Baseline: 7.79s Baseline: 3.97s
instruction-level overheads, and Linux block I/O scheduler perfor-
0%
fs ll ll fs ll ll fs ll ll fs ll ll mance [39]. In the context of database systems, Haas et al. explored
gBu +IOPo+SQPo RegBu +IOPo+SQPo RegBu +IOPo+SQPo RegBu +IOPo+SQPo
+Re + + + io_uring and other asynchronous I/O mechanisms for NVMe SSD
Figure 17: PostgreSQL speedup from io_uring optimizations.
arrays. They identified improvements in throughput and latency
Sharing the SQPoll kernel thread between rings has negligi-
associated with various io_uring features [21–23].
ble performance impact. Improvements remain limited by
Application-level and system integrations. Several works in-
the filesystem and PostgreSQL’s multi-process architecture.
tegrated io_uring into production systems to evaluate application-
specific benefits. Chen et al. applied io_uring to Redis, reporting
significant reductions in overhead for medium and large payloads
[12]. Durner et al. used io_uring to accelerate cloud object stor-
per thread with exclusive ownership and no cross-process shar-
age access, achieving lower latency and higher throughput [15].
ing. PostgreSQL also relies on filesystems for data storage, which
However, systematic analyses of network-specific aspects and end-
prevents low-level optimizations for guideline (4), such as NVMe
to-end effects on distributed systems remain absent.
passthrough and IOPoll. Filesystem traversal adds CPU overhead
Security and advanced feature analyses. From a security per-
and constrains effective utilization of modern storage hardware.
spective, He et al. proposed RingGuard, an eBPF-based framework
GL (3): Choose and tune the execution mode deliberately.
that monitors and restricts io_uring operations to prevent kernel-
Given PostgreSQL’s architecture, DeferTR cannot be used with-
level vulnerabilities. It extends eBPF with new io_uring-specific
out substantial refactoring. We therefore configure io_uring with
hooks and verifier logic, enforcing safety policies at runtime while
CoopTR as the next-best alternative. CoopTR disables kernel-driven
maintaining low overhead [25]. The most comprehensive explo-
task_work preemptions but still processes completions on each
ration of io_uring features to date is the work by Ingimarsson,
kernel-user transition, providing more predictable execution while
who integrated basic functionality into RocksDB [26]. However, de-
remaining compatible with PostgreSQL’s process model. Still fol-
tailed evaluations of advanced io_uring features, such as registered
lowing guideline (3), we extend the backend to support SQPoll by
buffers for zero-copy operations and linked requests to minimize
enabling the respective setup flag during ring creation and allowing
system calls, are still lacking.
multiple backend processes to share a single SQPoll kernel thread.
Our research addresses these gaps, offering detailed empirical
For WAL durability, PostgreSQL invokes fsync() directly (or via
evaluations in the context of data-intensive workloads and provid-
O_DATASYNC) rather than through io_uring, consistent with guide-
ing practical guidelines to use io_uring’s capabilities effectively.
line (3). This avoids spawning io_workers for blocking fsync() calls
and keeps the critical path fully asynchronous.
7 Conclusion and Outlook
GL (4): Use io_uring optimizations. We apply guideline (4) by
enabling io_uring optimizations that fit PostgreSQL’s access pat- The modern Linux io_uring interface provides powerful mecha-
terns and architectural constraints. We register the entire buffer nisms for efficient asynchronous I/O, but achieving measurable
pool as fixed buffers, eliminating PostgreSQL’s heuristic of enabling gains requires more than simply enabling its features. Our case
IO_ASYNC after four outstanding I/Os. Given PostgreSQL’s 8 KiB studies show that performance depends on understanding system
page size, this optimization aligns with the findings from Figure 8. In bottlenecks and integrating io_uring into the overall design, includ-
Figure 17, fixed buffers alone provide a 4–6% improvement. Because ing leveraging asynchronous execution to hide latency, batching to
we use ext4, we additionally enable IOPoll, improving performance amortize kernel interactions, and applying targeted optimizations
up to 7.5% over the baseline. Combined with SQPoll, total through- to reduce CPU cost per byte. We further used focused microbench-
put improves by 11–15% over upstream PostgreSQL, despite the marks to highlight trade-offs and subtleties of specific optimizations,
architectural constraints discussed above. such as the effects of buffer size on zero-copy and the importance
Summary. Applying the guidelines yields consistent improve- of aligning polling strategies with hardware and workload char-
ments even in a mature DBMS. Although PostgreSQL already in- acteristics. From this analysis, we distilled practical guidelines for
corporates optimizations such as coalescing small reads and using I/O-intensive systems and validated them through an integration
OS readahead, and although its process model and filesystem de- into PostgreSQL, improving table-scan throughput by 11-15% over
pendence limit the applicability of several io_uring features, the its baseline io_uring implementation. As io_uring continues to
remaining optimizations still yield measurable gains. Despite these evolve, it offers a path towards scalable I/O in Linux. Adopting it
factors, we observe speedups of 11–15% for the scan workload. today also makes systems future-ready, allowing applications to
benefit from new capabilities, such as recently added zero-copy
receive and upcoming features, without requiring architectural
6 Related Work changes.
Although io_uring is a relatively recent addition to the Linux kernel,
it has already been studied in various contexts, primarily focusing
on storage I/O and its impact on data-intensive systems.
12
References [23] Gabriel Haas and Viktor Leis. 2023. What Modern NVMe Storage Can Do,
and How to Exploit It: High-Performance I/O for High-Performance Storage
[1] 2025. Amazon EC2 Instances. [Link] Engines . Proceedings of the VLDB Endowment 16, 9 (May 2023), 2090–2102.
Accessed: 2025-11-27. [Link]
[2] 2025. [Link] framework. [Link] [24] Haochen He, Erci Xu, Shanshan Li, Zhouyang Jia, Si Zheng, Yue Yu, Jun Ma, and
[3] 2025. MySQL 8.4 Reference Manual. [Link] Xiangke Liao. 2023. When Database Meets New Storage Devices: Understanding
[Link] and Exposing Performance Mismatches via Configurations. Proc. VLDB Endow.
[4] Jens Axboe. 2019. Efficient I/O with io_uring. [Link] 16, 7 (2023), 1712–1725. [Link]
Accessed: 2025-10-17. [25] Wanning He, Hongyi Lu, Fengwei Zhang, and Shuai Wang. 2023. RingGuard:
[5] Jens Axboe. 2020. Re: io_uring is slower than epoll (issue #189 comment). GitHub Guard Io_uring with eBPF. In Proceedings of the 1st Workshop on eBPF and Kernel
issue comment on the liburing repository. Extensions (eBPF ’23). Association for Computing Machinery, New York, NY, USA,
[6] Jens Axboe. 2021. Re: unexpected high count of io_worker threads by using the 56–62. [Link]
IOSQE _ASYNC flag (issue #349 comment). GitHub issue comment on the liburing [26] Brynjar Ingimarsson. 2024. Exploring the Performance of the Io_uring Kernel I/O
repository. Interface. Master’s thesis. Universiteit van Amsterdam, Amsterdam.
[7] Jens Axboe. 2024. Re: EAGAINs impacting the performance of io_uring (issue #1175 [27] Matthias Jasny, Muhammad El-Hindi, Tobias Ziegler, and Carsten Binnig. 2025.
comment). GitHub issue comment on the liburing repository. A Wake-Up Call for Kernel-Bypass on Modern Hardware. In Proceedings of the
[8] Jens Axboe. 2025. io_uring and networking in 2023. [Link] 21st International Workshop on Data Management on New Hardware, DaMoN
liburing/wiki/io_uring-and-networking-in-2023#task-work 2025, Berlin, Germany, June 22-27, 2025. ACM, 14:1–14:5. [Link]
[9] Jens Axboe. 2025. io_uring library liburing. [Link] 3736227.3736235
Accessed: 2025-10-17. [28] Theo Jepsen, Alberto Lerner, Fernando Pedone, Robert Soul é, and Philippe
[10] Altan Birler, Tobias Schmidt, Philipp Fent, and Thomas Neumann. 2024. Simple, Cudré-Mauroux. 2021. In-Network Support for Transaction Triaging. Proc. VLDB
Efficient, and Robust Hash Tables for Join Processing. In Proceedings of the 20th Endow. 14, 9 (2021), 1626–1639. [Link]
International Workshop on Data Management on New Hardware, DaMoN 2024, [29] Anuj Kalia, Michael Kaminsky, and David G. Andersen. 2019. Datacenter RPCs
Santiago, Chile, 10 June 2024, Carsten Binnig and Nesime Tatbul (Eds.). ACM, can be General and Fast. In 16th USENIX Symposium on Networked Systems
4:1–4:9. [Link] Design and Implementation, NSDI 2019, Boston, MA, February 26-28, 2019, Jay R.
[11] Matthew Butrovich, Karthik Ramanathan, John Rollinson, Wan Shen Lim, Lorch and Minlan Yu (Eds.). USENIX Association, 1–16. [Link]
William Zhang, Justine Sherry, and Andrew Pavlo. 2023. Tigger: A Database org/conference/nsdi19/presentation/kalia
Proxy That Bounces With User-Bypass. Proc. VLDB Endow. 16, 11 (2023), 3335– [30] Daehyeok Kim, Amir Saman Memaripour, Anirudh Badam, Yibo Zhu,
3348. [Link] Hongqiang Harry Liu, Jitu Padhye, Shachar Raindel, Steven Swanson, Vyas
[12] Le-Gao Chen, Yanzhi Li, Tipporn Laohakangvalvit, and Midori Sugaya. 2024. Sekar, and Srinivasan Seshan. 2018. Hyperloop: group-based NIC-offloading to
Asynchronous I/O Persistence for In-Memory Database Servers: Leveraging accelerate replicated transactions in multi-tenant storage systems. In Proceedings
io_uring to Optimize Redis Persistence. In CLOUD Computing - CLOUD 2024 - of the 2018 Conference of the ACM Special Interest Group on Data Communication,
17th International Conference, Held as Part of the Services Conference Federation, SIGCOMM 2018, Budapest, Hungary, August 20-25, 2018, Sergey Gorinsky and
SCF 2024, Bangkok, Thailand, November 16-19, 2024, Proceedings (Lecture Notes in János Tapolcai (Eds.). ACM, 297–312. [Link]
Computer Science, Vol. 15423), Yang Wang and Liang-Jie Zhang (Eds.). Springer, [31] Microsoft Learn. 2024. Optimize network throughput for Azure virtual machines.
11–20. [Link] [Link]
[13] Diego Didona, Jonas Pfefferle, Nikolas Ioannou, Bernard Metzler, and Animesh optimize-network-bandwidth#achieving-consistent-transfer-speeds-in-linux-
Trivedi. 2022. Understanding Modern Storage APIs: A Systematic Study of Libaio vms-in-azure. Accessed: 2025-10-17.
, SPDK, and Io_uring. In Proceedings of the 15th ACM International Conference on [32] Viktor Leis, Adnan Alhomssi, Tobias Ziegler, Yannick Loeck, and Christian
Systems and Storage (SYSTOR ’22). Association for Computing Machinery, New Dietrich. 2023. Virtual-Memory Assisted Buffer Management. Proc. ACM Manag.
York, NY, USA, 120–127. [Link] Data 1, 1 (2023), 7:1–7:25. [Link]
[14] Aleksandar Dragojevic, Dushyanth Narayanan, Miguel Castro, and Orion Hod- [33] Viktor Leis, Peter Boncz, Alfons Kemper, and Thomas Neumann. 2014. Morsel-
son. 2014. FaRM: Fast Remote Memory. In Proceedings of the 11th USENIX driven parallelism: a NUMA-aware query evaluation framework for the many-
Symposium on Networked Systems Design and Implementation, NSDI 2014, Seat- core age. In International Conference on Management of Data, SIGMOD 2014,
tle, WA, USA, April 2-4, 2014, Ratul Mahajan and Ion Stoica (Eds.). USENIX Snowbird, UT, USA, June 22-27, 2014, Curtis E. Dyreson, Feifei Li, and M. Tamer
Association, 401–414. [Link] Özsu (Eds.). ACM, 743–754. [Link]
sessions/dragojevi%C4%87 [34] Viktor Leis and Christian Dietrich. 2024. Cloud-Native Database Systems and
[15] Dominik Durner, Viktor Leis, and Thomas Neumann. 2023. Exploiting Cloud Ob- Unikernels: Reimagining OS Abstractions for Modern Hardware. Proc. VLDB
ject Storage for High-Performance Analytics. Proceedings of the VLDB Endowment Endow. 17, 8 (2024), 2115–2122. [Link]
16, 11 (July 2023), 2769–2782. [Link] [35] Feng Li, Sudipto Das, Manoj Syamala, and Vivek R. Narasayya. 2016. Accelerating
[16] Wolfgang Effelsberg and Theo Härder. 1984. Principles of Database Buffer Relational Databases by Leveraging Remote Memory and RDMA. In Proceedings
Management. ACM Trans. Database Syst. 9, 4 (1984), 560–595. [Link] of the 2016 International Conference on Management of Data, SIGMOD Conference
1145/1994.2022 2016, San Francisco, CA, USA, June 26 - July 01, 2016, Fatma Özcan, Georgia
[17] Alessandro Fogli, Bo Zhao, Peter R. Pietzuch, Maximilian Bandle, and Jana Giceva. Koutrika, and Sam Madden (Eds.). ACM, 355–370. [Link]
2024. OLAP on Modern Chiplet-Based Processors. Proc. VLDB Endow. 17, 11 2882903.2882949
(2024), 3428–3441. [Link] [36] Vivek R. Narasayya, Ishai Menache, Mohit Singh, Feng Li, Manoj Syamala, and
[18] Joshua Fried, Gohar Irfan Chaudhry, Enrique Saurez, Esha Choukse, Íñigo Goiri, Surajit Chaudhuri. 2015. Sharing Buffer Pool Memory in Multi-Tenant Relational
Sameh Elnikety, Rodrigo Fonseca, and Adam Belay. 2024. Making Kernel Bypass Database-as-a-Service. Proc. VLDB Endow. 8, 7 (2015), 726–737. [Link]
Practical for the Cloud with Junction. In 21st USENIX Symposium on Networked 10.14778/2752939.2752942
Systems Design and Implementation, NSDI 2024, Santa Clara, CA, April 15-17, [37] Lam-Duy Nguyen, Adnan Alhomssi, Tobias Ziegler, and Viktor Leis. 2025. Mov-
2024, Laurent Vanbever and Irene Zhang (Eds.). USENIX Association, 55–73. ing on From Group Commit: Autonomous Commit Enables High Throughput and
[Link] Low Latency on NVMe SSDs. Proc. ACM Manag. Data 3, 3 (2025), 191:1–191:24.
[19] PostgreSQL Global Development Group. 2025. PostgreSQL 18 Released. https: [Link]
//[Link]/about/news/postgresql-18-released-3142/ [38] NVIDIA. 2021. NVIDIA ConnectX-7 Datasheet. [Link]
[20] The PostgreSQL Global Development Group. 2005. PostgreSQL 8.4.22 Documen- dam/en-zz/Solutions/networking/infiniband-adapters/infiniband-connectx7-
tation - Appendix E. Release Notes. [Link] [Link]
[Link]. [39] Zebin Ren and Animesh Trivedi. 2023. Performance Characterization of Modern
[21] Gabriel Haas, Adnan Alhomssi, and Viktor Leis. 2025. Managing Very Large Storage Stacks: POSIX I/O, Libaio, SPDK, and Io_uring. In Proceedings of the 3rd
Datasets on Directly Attached NVMe Arrays . In Scalable Data Management for Workshop on Challenges and Opportunities of Efficient and Performant Storage
Future Hardware, Kai-Uwe Sattler, Alfons Kemper, Thomas Neumann, and Jens Systems. ACM, Rome Italy, 35–45. [Link]
Teubner (Eds.). Springer Nature Switzerland, Cham, 223–240. [Link] [40] Bowen Wu, Wei Cui, Carlo Curino, Matteo Interlandi, and Rathijit Sen. 2025.
1007/978-3-031-74097-8_9 Terabyte-Scale Analytics in the Blink of an Eye. CoRR abs/2506.09226 (2025).
[22] Gabriel Haas, Michael Haubenschild, and Viktor Leis. 2020. Exploiting Directly- [Link] arXiv:2506.09226
Attached Nvme Arrays in DBMS. In 10th Conference on Innovative Data Systems [41] Xinjing Zhou, Viktor Leis, Xiangyao Yu, and Michael Stonebraker. 2025. OLTP
Research, CIDR 2020, Amsterdam, the Netherlands, January 12-15, 2020, Online Through the Looking Glass 16 Years Later: Communication Is the New Bottle-
Proceedings. [Link]. neck. In 15th Annual Conference on Innovative Data Systems Research (CIDR’25).
13
io_uring might not significantly enhance database system performance in CPU-bound or memory-resident workloads where I/O operations account for a minimal fraction of execution time. In these cases, potential performance gains from io_uring, which rely on reducing CPU costs from I/O operations, are limited .
The performance gains from io_uring depend heavily on workload characteristics. I/O-intensive workloads with significant page faults can see substantial improvements due to reduced I/O latency. Conversely, compute-heavy or mostly in-memory workloads see limited impact from io_uring optimizations since the I/O path contributes minimally to performance in such scenarios .
In implementing io_uring in a storage engine, the architectural design must support asynchronous I/O processes and mechanisms to amortize I/O latency through batching, aligning with io_uring's capabilities. The storage workload dictates the use of io_uring optimizations; I/O-bound workloads gain significantly from reduced latencies, while CPU-bound workloads may see less improvement due to the lesser role of I/O in overall costs .
In network socket activities, io_uring defaults to completing I/O operations inline in non-blocking mode, resorting to internal polling only if necessary. The RECVSEND_POLL_FIRST flag, however, optimizes this process by bypassing unnecessary speculative operations when the socket's state is known, which results in a 1.5× reduction in kernel cycles used .
Using io_uring in database systems improves performance for I/O-intensive workloads by enabling asynchronous execution and batching of I/O operations. This reduces effective I/O latency and shifts bottlenecks from device latency to CPU cycles, thereby enhancing throughput. Configurations utilizing io_uring can achieve meaningful gains particularly when workloads have high page fault probabilities and are I/O-latency bound, such as YCSB and certain TPC-C configurations .
Effective integration of io_uring in system design necessitates aligning architecture with io_uring capabilities, such as enabling asynchronous execution, batching system calls, and using a unified interface for storage and network I/O. Additionally, architectural changes that allow overlapping I/O and computation or amortizing costs can bring significant improvements .
io_uring reduces the cycle cost for a single TCP connection by implementing optimizations like the RECVSEND_POLL_FIRST flag, which avoids unnecessary speculative attempts for socket operations. This reduces cycles spent in kernel processing, improving efficiency by decreasing the number of executed instructions. However, this requires a well-understood socket state to avoid inefficiency if the I/O call is wrongly skipped .
Enabling io_uring's SQPoll feature in a buffer manager configuration allows the application to enqueue I/O requests without incurring syscall overhead for each submission, as it dedicates a CPU core to polling. This increases throughput by about 32%, as it reduces the cost previously spent in syscall and kernel-side processing, improving overall efficiency .
io_uring is particularly effective for certain configurations of the TPC-C benchmark because it optimizes asynchronous and batched I/O operations. In settings where the workload is mostly out-of-memory, the increased I/O activity and costs due to page loads and evictions make optimized I/O execution to significantly improve performance, achieving up to 12.5× higher throughput compared to synchronous implementations .
Recent studies provide four key guidelines for using io_uring in database systems: identifying I/O as the bottleneck, aligning system architecture with io_uring's capabilities, carefully choosing and tuning execution modes, and leveraging io_uring optimizations such as asynchronous execution, batching, and reducing per-operation CPU overhead when beneficial .