The Kernel Reorders Your Writes for the Disk’s Benefit
I remember sitting in a windowless server room during my first industry residency, staring at a dashboard where latency spikes were climbing like a fever chart. My supervisor insisted we just “throw more NVMe drives at the problem,” a classic piece of expensive, misguided advice that ignored the fact that our software was suffocating the hardware. People love to treat storage as a magic black box that just works, but when you actually dive into the mechanics of block devices and io scheduling, you realize that the bottleneck is rarely just the raw speed of the silicon. It is almost always the friction caused by how the operating system decides to order, batch, and dispatch those requests.
I’m not here to give you a theoretical lecture on queue depths or to hand you a list of textbook definitions you could find in a half-baked Wikipedia entry. Instead, I want to pull back the curtain on how these systems actually behave when they are under load. We are going to look at the specific trade-offs between throughput and latency, and I will show you why a scheduler that looks perfect in a research paper might actually destroy your performance in a production environment.
Table of Contents
Decoding the Block Layer Architecture and Request Flows

To understand how data actually moves, you have to look at the block layer architecture as a sophisticated translation service. When an application asks to write a file, it isn’t talking to the hardware; it’s talking to a high-level abstraction. The kernel takes these high-level requests and begins a process of transformation, turning what looks like a simple stream of bytes into a structured set of commands that the hardware can actually digest. This isn’t just a hand-off; it is a heavy-duty orchestration where the kernel attempts to bridge the gap between the lightning-fast CPU and the relatively sluggish reality of physical storage.
At the heart of this process is disk request queue management. Instead of blindly passing every single command to the controller the moment it arrives, the kernel holds them in a staging area. This allows the system to look ahead at the pending workload and rearrange the order of operations. By grouping adjacent sectors or prioritizing certain types of traffic, the system performs storage throughput optimization by reducing the overhead of constant, fragmented access. It is a delicate balancing act: if you queue too much, you increase latency; if you queue too little, you leave your hardware’s potential on the table.
The Friction Between Cpu Demands and Disk Reality

The fundamental problem is a massive mismatch in speed and physics. Your CPU operates in nanoseconds, executing billions of instructions while it waits for data. Meanwhile, even the fastest storage devices operate on a timescale that feels like an eternity to a processor. If every single tiny read or write request from an application hit the hardware exactly as it was issued, the system would choke on its own overhead. We aren’t just moving data; we are managing a constant state of tension between a high-speed requester and a relatively sluggish responder.
This is where disk request queue management becomes necessary. We can’t just pass requests through blindly; we have to buffer, sort, and sometimes merge them to make the movement efficient. If you are dealing with a mechanical drive, you’re trying to minimize the physical movement of a heavy actuator arm. If you’re on flash, you’re managing internal parallelism. The goal of storage throughput optimization isn’t just to move data faster, but to ensure the CPU isn’t sitting idle because the storage stack is too busy being disorganized.
Five Lessons from the Trenches of I/O Management
- Stop treating all block devices like they are the same. If you apply a scheduler designed for the mechanical latency of a spinning disk—like one that spends a lot of time reordering requests to minimize head seek time—to a modern NVMe drive, you aren’t just wasting cycles; you are actively bottlenecking the hardware’s ability to handle massive parallelism.
- Watch your queue depth closely. It is tempting to think that a deeper queue always means better throughput, but in many real-world scenarios, an excessively deep queue leads to “bufferbloat” at the block level, where your latency spikes so high that the application effectively hangs while waiting for a single request to clear the backlog.
- Understand that “zero latency” is a lie we tell in papers. In reality, I/O is always a trade-off between throughput and responsiveness. If you tune your system to maximize the amount of data moved per second (throughput), you are almost certainly going to see an increase in the time it takes for any individual, small request to complete (latency).
- Don’t ignore the CPU cost of scheduling. While complex algorithms can theoretically optimize the order of operations, the act of calculating that “optimal” order requires CPU cycles. On high-speed storage, the overhead of a sophisticated scheduler can actually become a larger bottleneck than the I/O itself, which is why “none” or “mq-deadline” are often better choices for high-performance SSDs.
- Profile your actual workload before you start tweaking `/sys/block/`. A database workload, which relies heavily on small, random writes and strict durability, requires a completely different scheduling philosophy than a media streaming service that is essentially just moving massive, contiguous chunks of data. Tuning for the wrong pattern is just expensive guesswork.
The Mechanics of the Friction
I/O scheduling isn’t about making the disk “faster” in a vacuum; it is about managing the fundamental mismatch between how a CPU thinks (instantaneous, random access) and how a physical storage medium operates (latency-bound, sequential-preferring).
The “best” scheduler is entirely dependent on your hardware’s physical properties; applying a scheduler designed to minimize seek time on a spinning platter to an NVMe drive is a mistake that adds unnecessary CPU overhead without any actual performance gain.
To truly understand system performance, you have to look past the throughput numbers and examine the request flow—specifically how the block layer attempts to batch and reorder commands to prevent the hardware from spending more time moving its own parts than actually moving data.
Beyond the Abstraction
We have spent this time peeling back the layers of the block layer, moving from the high-level intent of a process down to the messy, physical reality of how bits actually land on a medium. It is easy to view I/O as a magic, instantaneous event, but as we have seen, it is actually a constant struggle of negotiating latency. Whether you are tuning a scheduler to minimize seek times on a legacy drive or trying to prevent queue starvation on a high-speed NVMe device, the goal remains the same: managing the mismatch between how fast a CPU can think and how slow a storage device can actually react. If you ignore these mechanical constraints, your software will eventually hit a wall that no amount of clever coding can bypass.
As you move forward, I encourage you to stop treating your storage stack as a black box. When a system slows down or a database begins to stutter, don’t just throw more RAM at the problem; look down at the request queues and the scheduling logic. Understanding these mechanisms won’t make your code run faster by itself, but it will give you the clarity to see exactly where the friction is occurring. Real engineering isn’t about mastering the abstractions; it is about knowing exactly when those abstractions are about to fail you.