Module 4 · Unit 11 · Lesson 5 of 7
Disk Scheduling
Lesson 11.4 presented the device driver and its interface with the block layer's request queue. This lesson presents the layer that decides which of the queued requests the device should serve next: the disk scheduler. On a hard disk, the scheduling decision is the difference between an order that moves the heads in a single sweep and an order that sends them back and forth across the platters, and the difference can be an order of magnitude in throughput. On a solid-state drive, the scheduling decision matters for a different reason — parallelism and write amplification rather than seek distance — and the modern schedulers are designed for both worlds.
01 Introduction
Lesson 11.1 presented the hard disk's geometry and showed that a random read's cost is dominated by the seek and the rotational delay: the transfer itself is a tiny fraction of the access time, and the mechanical delays account for over 95% of the cost. Lesson 11.4 presented the device driver and its interface with the block layer's request queue. This lesson presents the layer between them: the disk scheduler (also called the I/O scheduler), which decides the order in which the queued requests are dispatched to the device.
The scheduling decision is one of the operating system's most consequential performance decisions. A hard disk's throughput depends on the order of the requests: a sequence of requests that are sorted by block address and issued together — so the heads move in a single sweep across the platters — is far faster than the same requests issued in random order, where the heads move back and forth. The difference can be an order of magnitude: a disk that delivers 200 IOPS with random requests can deliver 2,000 IOPS with sorted ones. The scheduler's job is to find the order that maximizes the throughput while preserving the fairness and the latency that the applications expect.
The scheduling problem has a long history. The classical algorithms — FCFS, SSTF, SCAN, C-SCAN, LOOK, and C-LOOK — were developed for the hard disks of the 1970s and 1980s, and their names are still used. The modern schedulers — mq-deadline, BFQ, Kyber, and none — are designed for the multi-queue block layer and for the modern devices: the solid-state drives whose access time is nearly uniform, the NVMe devices whose parallelism is enormous, and the virtual machines whose I/O is layered. The modern schedulers must balance the throughput (which the hard disks reward with sorted requests), the latency (which the interactive applications require), and the fairness (which the multi-tenant systems demand).
This lesson presents disk scheduling. It defines the scheduling problem and the performance measures that the schedulers optimize. It presents the hard disk's performance characteristics and the seek-time bottleneck that shapes the classical algorithms. It presents the classical algorithms one at a time, with their trade-offs and their pathologies. It presents the modern Linux schedulers and the multi-queue block layer's design, and it presents the solid-state drives' different characteristics and the schedulers' adaptation to them. It presents the I/O priority and the cgroup controllers that the multi-tenant systems use, and it closes with the scheduling's effect on the system's throughput and latency and the tuning that the administrator can perform.
Prerequisites
This lesson builds on Lessons 11.1 and 11.4. The hard disk's geometry and its performance characteristics (the seek, the rotational delay, and the transfer), the DMA machinery, and the device driver and the block layer's request queue are all assumed. The process-scheduling concepts from Unit 5 (the scheduling objectives, the algorithms, and the metrics) are the context for this lesson's discussion of the I/O scheduling's objectives: the two scheduling problems share their structure (a set of requests, a resource, a policy) but differ in their resource (the CPU's time versus the disk's head position) and in their metrics (the response time and the throughput versus the seek distance and the throughput). No new operating-system concepts are introduced; the lesson is about the scheduling algorithms and the block layer's design. Familiarity with the Linux command line from Lesson 2.2 is helpful, since the interactive activity uses standard Unix tools.
02 Learning objectives
By the end of this lesson you will be able to
- Define the disk scheduling problem and explain why the order of the requests matters on a hard disk.
- Describe the classical scheduling algorithms (FCFS, SSTF, SCAN, C-SCAN, LOOK, C-LOOK) and compare their throughput, latency, and fairness.
- Explain the SCAN family's trade-offs and the pathologies (the starvation of the far requests, the arm's stickiness) that the algorithms must address.
- Describe the Linux kernel's multi-queue block layer and its schedulers (mq-deadline, BFQ, Kyber, none).
- Explain how the solid-state drives' characteristics change the scheduling problem and how the modern schedulers adapt.
- Describe the I/O priority and the cgroup controllers that the multi-tenant systems use, and explain how the scheduler's choice affects the system's throughput and latency.
This lesson contributes to U11.5 and U11.6, and to course learning outcomes CLO1, CLO5, and CLO6.
03 Required reading
- Operating System Concepts — Chapter 11, Mass-Storage Structure, Section 11.2, Disk Scheduling. The standard treatment of the classical algorithms, with the classical examples and the comparison of the algorithms' performance.
- OSTEP — Chapter 37, Hard Disk Drives, and Chapter 38, Redundant Arrays of Inexpensive Disks (RAIDs). OSTEP's treatment of the disk's geometry and its performance is the basis for the scheduling problem, and its discussion of the disk's scheduling is the basis for the classical algorithms' analysis.
- Tanenbaum & Bos — Modern Operating Systems, Chapter 5, Section 5.4, Disks. A complementary treatment that develops the disk's hardware and the scheduling algorithms from first principles.
- Love, R. — Linux Kernel Development, 3rd ed., Chapter 16, The Block I/O Layer. The Linux kernel's block layer: the request queue, the elevator algorithms, and the multi-queue design.
- Bovet, D. P., & Cesati, M. — Understanding the Linux Kernel, 3rd ed. O'Reilly, 2005. Chapter 14, Block Device Drivers. The classical block layer's structures and its elevator algorithms.
- Axboe, J. — Linux Block IO: Introducing Multi-queue SSD Access on Multi-core Systems. Proceedings of the 6th International Systems and Storage Conference (SYSTOR), 2013. The paper that introduced the multi-queue block layer and its schedulers.
- Valente, P., & Checconi, F. — High Throughput Disk Scheduling with Fair Bandwidth Distribution. IEEE Transactions on Computers, 2010. The paper that describes the BFQ scheduler's design and its fairness guarantees.
-
Linux man pages:
man 1 iostat,man 1 iotop,man 1 ionice,man 1 fio,man 5 proc(for/proc/diskstats),man 2 ioprio_set,man 5 cgroups(for the blkio controller),man 8 blkdiscard,man 1 lsblk,man 8 tune2fs.
Reading strategy
Read the Silberschatz section first. It presents
the classical algorithms one at a time — FCFS,
SSTF, SCAN, C-SCAN, LOOK, C-LOOK — with the
classical example (the queue of 1,000-block
requests and the head at block 53) that shows each
algorithm's traversal. The example is the lesson's
worked example's basis, and its comparison of the
algorithms' total head movement is the lesson's
central quantitative result. Then read the OSTEP
chapters for the disk's geometry and its
performance characteristics: the seek, the
rotational delay, and the transfer, and the reason
the mechanical delays dominate. The Linux kernel
chapters (Love and Bovet & Cesati) are the
practical view: they show the kernel's block layer,
the classical elevator algorithms, and the modern
multi-queue design. The Axboe paper is the primary
source for the multi-queue block layer, and it is
worth reading for the design's rationale and its
performance results. Finally, the Linux man pages
are the practical tools: iostat shows
the device's utilization and its throughput,
iotop shows the processes' I/O,
ionice sets the processes' I/O
priority, and /proc/diskstats shows
the device's statistics. Pay particular attention
to the distinction between the throughput
(the total work the device performs) and the
latency (the time an individual request
waits). The classical algorithms optimize the
throughput at the cost of the latency, and the
modern schedulers must balance the two; the
balance is the scheduler's central design decision,
and it is the source of the modern schedulers'
differences.
04 Core content
4.1 The disk scheduling problem
The disk scheduling problem is the problem of ordering the pending I/O requests to optimize the device's performance. The block layer maintains a queue of requests (Lesson 11.4), and the scheduler decides which request the device should serve next. The decision is made for every request, and its cumulative effect determines the device's throughput and the requests' latency.
The problem's importance comes from the hard disk's performance characteristics. A hard disk's access time has three components:
- The seek time is the time to move the heads to the correct cylinder. It is a few milliseconds on a modern disk, and it is the largest component for a random access.
- The rotational delay is the time for the platter's rotation to bring the correct sector under the head. It averages half a rotation — about 4.2 milliseconds at 7,200 RPM.
- The transfer time is the time to read or write the data. It is a few microseconds per sector at the disk's sequential bandwidth, and it is a tiny fraction of the access time.
The seek and the rotational delay are mechanical, and they dominate the access time. The seek's duration depends on the distance between the current cylinder and the target cylinder: a short seek (a few cylinders) takes a fraction of a millisecond, while a long seek (across the disk) takes several milliseconds. The observation is the scheduling problem's basis: if the requests are ordered so that the heads move in a single sweep — each request's target cylinder is close to the previous request's — the total seek distance is minimized, and the throughput is maximized.
The problem's objective is therefore to order the requests so that the head's movement is minimized. The objective has three competing components:
- The throughput. The number of requests the device serves per second. The throughput is maximized by minimizing the total head movement, which is achieved by sorting the requests by block address.
- The latency. The time an individual request waits before it is served. The latency is minimized by serving the requests in the order they arrive, which conflicts with the sorting.
- The fairness. The requests' distribution across the applications and the devices' regions. The fairness is violated when a request waits indefinitely because the scheduler always prefers the requests near the head's current position.
The three components conflict: a scheduler that maximizes the throughput (by sorting) increases the latency (the far requests wait), and a scheduler that minimizes the latency (by serving in arrival order) reduces the throughput. The scheduler's design is the balance it strikes, and the balance is the source of the classical algorithms' differences and the modern schedulers' variety.
4.2 The classical algorithms
The classical algorithms were developed for the hard disks of the 1970s and 1980s, and their names are still used. They differ in how they use the head's current position to order the requests:
- FCFS (First Come, First Served)
- The requests are served in the order they arrive. FCFS is the simplest algorithm, and its fairness is perfect (no request can starve). Its throughput is the worst of the classical algorithms, because the heads move back and forth across the disk: if the queue is [98, 183, 37, 122, 14, 124, 65, 67] and the head is at 53, the head moves 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67, a total of 640 cylinders. FCFS is appropriate for the devices whose access time is nearly uniform (the solid-state drives) or for the workloads whose requests are already sorted.
- SSTF (Shortest Seek Time First)
- The request whose cylinder is closest to the head's current position is served first. SSTF is the disk's counterpart of the CPU's shortest-job-first (SJF) algorithm, and its throughput is better than FCFS's: for the same queue, the head moves 53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183, a total of 236 cylinders — less than half of FCFS's. SSTF's disadvantage is its fairness: the requests whose cylinders are far from the head's position may starve, because the scheduler always prefers the closer requests. In a system with a steady stream of requests near the head's position, the far requests wait indefinitely. SSTF is the classical example of the throughput-versus-fairness trade-off.
- SCAN (the elevator algorithm)
- The head moves in one direction (from the disk's inner edge to its outer edge, or vice versa), serving the requests it passes, until it reaches the disk's edge; then it reverses direction and serves the requests on the way back. SCAN's name comes from the head's sweeping motion, and its alternative name (the elevator algorithm) comes from the analogy with an elevator that serves the floors in one direction before reversing. SCAN's throughput is better than SSTF's in the long run, because the head never backtracks: each request is served at most one sweep after it arrives. SCAN's disadvantage is the requests near the disk's edges: they wait for almost two full sweeps if they arrive just after the head passes them.
- C-SCAN (Circular SCAN)
- The head moves in one direction only, serving the requests it passes, and when it reaches the disk's edge, it returns to the opposite edge without serving any requests on the return. The return's requests wait for the next sweep, so the waiting time is more uniform than SCAN's: a request waits at most one sweep, regardless of its position. C-SCAN's fairness is better than SCAN's, and its throughput is slightly lower (the return's sweep is wasted), but the trade-off is usually worth it. C-SCAN is the standard algorithm for the systems whose latency matters.
- LOOK and C-LOOK
- The variants of SCAN and C-SCAN that reverse direction (or return to the opposite edge) at the last request in the current direction, rather than at the disk's physical edge. The head does not travel to the disk's edge if no request requires it, so the wasted movement is eliminated. LOOK and C-LOOK are the practical algorithms: the modern systems use them (or their variants) rather than the classical SCAN and C-SCAN.
The classical algorithms' differences are summarized in the following table. The table's "total movement" column is the head's total travel for the classical example (the queue [98, 183, 37, 122, 14, 124, 65, 67] with the head at 53), and the "fairness" column describes the algorithm's fairness properties.
| Algorithm | Order | Total movement | Fairness |
|---|---|---|---|
| FCFS | Arrival order | 640 | Perfect (no starvation) |
| SSTF | Nearest first | 236 | Poor (far requests may starve) |
| SCAN | One sweep, then reverse | ~208 (LOOK) | Fair (bounded wait) |
| C-SCAN | One sweep, then return | ~236 (C-LOOK) | Fair (uniform wait) |
| LOOK | SCAN to the last request | ~208 | Fair (bounded wait) |
| C-LOOK | C-SCAN to the last request | ~236 | Fair (uniform wait) |
The table's numbers make the algorithms' trade-offs concrete. FCFS's movement is the worst; SSTF's is the best of the simple algorithms, but its fairness is poor. The SCAN family's movement is close to SSTF's, and its fairness is better: the sweep's bounded length means that every request is served within a bounded time. The SCAN family is therefore the classical algorithms' practical choice, and the modern schedulers' designs are its descendants.
4.3 The SCAN family's trade-offs and pathologies
The SCAN family is the classical algorithms' practical choice, but its design has several trade-offs and pathologies that the modern schedulers must address:
- The far requests' wait. A request that arrives just after the head passes its cylinder waits for almost a full sweep. On a large disk with a long sweep, the wait can be tens of milliseconds, and a latency-sensitive application (a database, an interactive program) notices.
- The arm's stickiness. If the request stream is concentrated in a narrow region of the disk, the head tends to stay in that region, and the requests elsewhere wait longer. The stickiness is the reason the classical algorithms are supplemented with the ageing mechanisms: a request's priority increases with its waiting time, so the far requests eventually become the head's target.
-
The write's delay. The classical
algorithms treat the reads and the writes
symmetrically, but the writes are usually
asynchronous (the application's
writereturns as soon as the data is in the page cache, and the actual write can be delayed) and the reads are usually synchronous (the application'sreadblocks until the data is available). A scheduler that delays the reads to batch the writes improves the throughput but increases the read latency, and the balance is the modern schedulers' central trade-off. - The read-ahead's interference. The kernel's read-ahead (Lesson 10.4's page cache) submits the read-ahead requests before the application asks for them, so the requests arrive in bursts. The bursts' interference with the application's requests is a scheduling problem: the read-ahead's requests occupy the device while the application waits.
- The multiple devices' interference. A system with several devices (a hard disk and an SSD, or several hard disks) must schedule the requests across the devices, not just within one. The scheduling's cross-device aspects (the workload's placement, the devices' utilization) are the modern systems' additional concern.
The modern schedulers address these trade-offs with a combination of mechanisms: the deadline mechanism (each request has a deadline, and the scheduler serves the requests in the deadline order when the deadlines approach), the fairness mechanism (each application or cgroup has a weight, and the scheduler allocates the device's bandwidth proportionally), and the parallelism mechanism (the requests are submitted to the device's multiple queues concurrently, so the device's parallelism is exploited). The mechanisms' balance is the modern schedulers' design, and it is the subject of the next section.
4.4 The multi-queue block layer
The classical block layer had a single request queue per device, and its elevator algorithm ran under a single lock. The design was a bottleneck on the modern devices: the lock serialized the submissions from the multiple processor cores, and the single queue could not exploit the device's parallelism. The multi-queue block layer (introduced in Linux 3.13) replaced the design with a two-level structure:
- The software queues. One queue per processor core (or per submission context). The queue is lockless (or uses a per-queue lock), so the submissions from different cores do not contend. The software queue is where the scheduler's algorithm runs: the requests are sorted, merged, and ordered per core.
-
The hardware queues. One queue per
device's hardware queue (the NVMe's queue pair, the
SCSI controller's queue, the AHCI controller's
command slot). The hardware queue is what the
driver's
queue_rqmethod consumes. The software queues are mapped to the hardware queues, typically one per core, so the submissions and the completions do not contend.
The multi-queue block layer's design is the reason the modern devices achieve their throughput: the submissions from different cores go to different software queues, the software queues' algorithms run in parallel, and the hardware queues receive the requests without contention. The design's complexity is the scheduler's: the algorithm must run per software queue (so it cannot see the whole request stream), and the fairness must be enforced across the queues (so the scheduler must coordinate the queues' decisions). The modern schedulers' designs reflect the constraint: they use the per-queue sorting for the throughput and the cross-queue mechanisms for the fairness.
4.5 The modern Linux schedulers
The Linux kernel provides four schedulers for the multi-queue block layer, each with its own design and its own target workload:
- mq-deadline
- The multi-queue version of the classical deadline scheduler. The scheduler maintains three queues: a sorted queue (the requests ordered by their block address, for the throughput), a read deadline queue (the read requests ordered by their deadlines, for the latency), and a write deadline queue (the write requests ordered by their deadlines, for the fairness). The scheduler dispatches the requests from the sorted queue normally, but when a request's deadline approaches (the default is 500 ms for the reads and 5 s for the writes), it dispatches the request from the deadline queue, so the request's latency is bounded. The design balances the throughput (the sorted queue) and the latency (the deadlines), and it is the kernel's default scheduler for the general-purpose workloads.
- BFQ (Budget Fair Queueing)
- A scheduler that provides the strong fairness guarantees of the budget fair queueing algorithm. Each application (or cgroup) has a weight and a budget (the number of sectors it may transfer before the scheduler switches to another application), and the scheduler allocates the device's bandwidth proportionally to the weights. BFQ's fairness is its principal advantage: a low-priority application cannot starve a high-priority one, and the interactive applications' latency is bounded even under a heavy load. BFQ's disadvantage is its overhead: the scheduler's per-request bookkeeping is more expensive than mq-deadline's, and its throughput on the high-end devices is slightly lower. BFQ is the kernel's recommended scheduler for the desktop and the interactive workloads, where the fairness and the latency matter more than the raw throughput.
- Kyber
- A scheduler designed for the high-performance devices (the NVMe SSDs). Kyber's design is lightweight: it maintains a small number of queues per operation type (the reads and the writes), and it throttles the submissions when the device's queue's depth exceeds a target (the latency target). The throttling keeps the device's queue's depth in the range where the device's latency is bounded, so the scheduler's overhead is minimal and the device's latency is controlled. Kyber is the kernel's recommended scheduler for the high-performance SSDs, where the seek distance is irrelevant and the queue's depth is the latency's determinant.
- none (noop)
- The scheduler that performs no scheduling: the requests are dispatched to the device in the order they arrive (the multi-queue block layer's software queues' order, with the merging). The scheduler's overhead is zero, and its throughput is the device's raw throughput. The scheduler is the kernel's default for the devices whose access time is nearly uniform (the SSDs, the NVMe devices, the virtual devices), where the sorting's benefit is small and the scheduling's overhead is a waste. The scheduler's name reflects its design: the kernel's default for the modern devices, where the device's controller does the scheduling and the kernel's role is limited.
The four schedulers' differences are summarized in the following table:
| Scheduler | Design | Target workload | Overhead |
|---|---|---|---|
| mq-deadline | Sorted queue + deadline queues | General-purpose, hard disks | Low |
| BFQ | Budget fair queueing | Desktop, interactive, multi-tenant | Medium |
| Kyber | Queue-depth throttling | High-performance SSDs | Very low |
| none | Arrival order (with merging) | Fast SSDs, NVMe, virtual devices | Zero |
The schedulers' selection is a per-device setting:
the administrator writes the scheduler's name to
/sys/block/<device>/queue/scheduler,
or sets it through the kernel's boot parameters. The
default is set by the distribution, and the modern
distributions use mq-deadline for the
hard disks and none or
kyber for the SSDs. The selection can be
changed at runtime, and the administrator can use it
to tune the system for the workload.
4.6 Solid-state drives and the scheduling problem
The solid-state drive's characteristics change the scheduling problem's nature. An SSD has no heads to seek and no platter to rotate: its access time is dominated by the flash memory's read latency (tens of microseconds) and the controller's overhead, and the difference between the sequential and the random access is far smaller than a hard disk's. The sorting's benefit is therefore small: an SSD's random read is nearly as fast as its sequential read, so the scheduler's reordering does not improve the throughput significantly.
The SSD's scheduling problem is different:
- The parallelism. An SSD contains many flash chips, and the controller can access several of them in parallel. The device's throughput is maximized when several requests are in flight at once, so the scheduler's job is to keep the device's queue's depth high (the queue depth). The high-performance SSDs (the NVMe devices) have thousands of queue slots, and the scheduler's role is to fill them and to keep the completions flowing.
- The write amplification. The SSD's flash memory cannot be overwritten in place, so the controller's flash translation layer performs the read-modify-erase-write cycles. The write amplification depends on the write pattern: the sequential and the aligned writes cause less amplification than the random and the unaligned writes. The scheduler's job is to submit the writes in a pattern that minimizes the amplification, and the modern schedulers' designs (the merging, the batching) are shaped by it.
- The garbage collection. The SSD's controller must periodically reclaim the invalidated blocks (the garbage collection), and the reclamation competes with the applications' I/O. The scheduler's job is to pace the submissions so the garbage collection does not starve the applications, and the modern schedulers' throttling (Kyber's latency target) is designed for it.
- The latency's distribution. The SSD's average latency is low, but its tail latency (the 99th percentile, the 99.9th percentile) can be much higher, because of the garbage collection, the write amplification, and the controller's internal scheduling. The scheduler's job is to bound the tail latency, and the modern schedulers' designs (the deadlines, the throttling) are shaped by it.
The observation is the reason the modern Linux
distributions use none or
kyber for the SSDs: the sorting's
benefit is small, and the scheduling's overhead is a
waste. The device's controller does the scheduling
internally (the flash translation layer's
parallelism, the garbage collection's pacing), and
the kernel's role is limited to the submission and
the completion. The design is the modern storage
stack's central trend: the device's controller is
becoming a computer in its own right, and the
kernel's scheduling's role is shrinking.
4.7 I/O priority and the cgroup controllers
The multi-tenant systems (the servers with several virtual machines, the containers on a shared host) need to allocate the devices' bandwidth among the tenants. The Linux kernel provides two mechanisms:
-
The I/O priority. Each process has
an I/O priority (a class and a level), which the
ionicecommand sets and theioprio_setsystem call sets programmatically. The classes are the real-time (the highest priority, for the processes that must not be delayed), the best-effort (the default, with the levels 0–7), and the idle (the lowest priority, for the processes that should yield to all others). The BFQ and mq-deadline schedulers honour the priorities: the higher-priority processes' requests are dispatched first, and the lower- priority processes' requests wait. - The cgroup blkio controller. The controller lets the administrator group the processes (into the cgroups) and allocate the devices' bandwidth among the groups. The allocation is expressed in the weights (the proportional shares) or in the limits (the maximum bandwidth, the maximum IOPS). The controller's design is the multi-tenant systems' basis: a virtual machine's or a container's I/O is limited by its cgroup's allocation, and the other tenants' I/O is protected.
The two mechanisms' design reflects the modern systems' requirements. The I/O priority is the per-process mechanism: it is simple, and it is sufficient for the systems with a few processes and a well-understood priority structure. The cgroup controller is the group mechanism: it is more complex, and it is necessary for the systems with many tenants and a dynamic workload. The two mechanisms' combination (the priority within the cgroup, the weight across the cgroups) is the modern systems' standard, and the administrators of the multi-tenant systems must configure both.
4.8 The scheduling's effect on the system's performance
The scheduler's choice's effect on the system's performance is significant, and it is visible in the system's metrics:
- The throughput. The device's throughput (the IOPS and the bandwidth) is the scheduler's primary metric. On a hard disk, the sorted scheduling can improve the throughput by an order of magnitude for the random workloads; on an SSD, the difference is small, and the scheduler's overhead is the determinant.
- The latency. The requests' latency (the average and the tail) is the scheduler's fairness metric. The deadline schedulers (mq-deadline, BFQ) bound the latency; the sorting schedulers (the classical SCAN family) increase the latency for the far requests; the no-op scheduler's latency is the device's raw latency.
- The fairness. The tenants' bandwidth allocation is the scheduler's multi-tenant metric. The BFQ and the cgroup controller's design provides the strong fairness; the mq-deadline's design provides the weaker fairness (the deadlines' bound); the no-op scheduler provides the weakest fairness (the arrival order's accidental fairness).
- The CPU overhead. The scheduler's own CPU cost is the system's overhead metric. The BFQ's design is the most expensive (the per-request bookkeeping), the mq-deadline's is moderate, the Kyber's is low, and the no-op scheduler's is zero. On a high-throughput device (an NVMe SSD at millions of IOPS), the scheduler's overhead can consume a significant fraction of the processor's time, and the no-op scheduler is the right choice.
The metrics' balance is the scheduler's design
decision, and it is the administrator's tuning
decision. The administrator can select the scheduler
per device, set its parameters (the deadlines, the
weights, the latency targets), and observe the
metrics (through iostat,
iotop, and the
/proc/diskstats interface). The tuning
is the system administrator's ongoing task: the
workload changes, the devices change, and the
scheduler's settings must be adjusted to the new
conditions.
4.9 Common misconceptions
"The disk scheduler is the same as the CPU scheduler."
The two scheduling problems share their structure (a set of requests, a resource, a policy) but differ in their resource and their metrics. The CPU scheduler allocates the processor's time; the disk scheduler allocates the device's head position (on a hard disk) or its queue's slots (on an SSD). The CPU scheduler's metrics are the response time and the throughput; the disk scheduler's are the seek distance, the throughput, and the latency. The two schedulers' designs are different, and their tuning is different.
"The scheduler should always sort the requests."
The sorting maximizes the throughput on a hard disk, but it increases the latency for the far requests and it is unnecessary on an SSD. The modern schedulers balance the sorting with the deadlines (mq-deadline), the fairness (BFQ), and the throttling (Kyber), and the no-op scheduler omits the sorting entirely for the devices that do not need it.
"FCFS is the fairest algorithm."
FCFS is fair in the sense that no request starves: the requests are served in the order they arrive, so every request's wait is bounded. But FCFS's fairness is the arrival order's fairness, not the importance's: a low-priority request that arrives first is served before a high-priority request that arrives second. The modern schedulers' fairness is the weighted fairness: the requests are served in proportion to their priorities, so the important requests' wait is shorter.
"SSTF is the best algorithm."
SSTF's throughput is better than FCFS's, and its total head movement is the smallest of the classical algorithms in the short run. But SSTF's fairness is poor: the requests far from the head can starve, and the algorithm's throughput in the long run can be worse than the SCAN family's, because the head's position is not bounded and the far requests' eventual service requires a long seek. The SCAN family is the practical choice.
"The SSD does not need a scheduler."
The SSD's scheduling problem is different from the hard disk's, but it is not absent. The SSD's throughput depends on the queue's depth (the parallelism), its write amplification depends on the write pattern, and its tail latency depends on the garbage collection. The modern schedulers (Kyber, none) are designed for the SSDs, and their role is to keep the queue's depth in the right range and to pace the submissions so the garbage collection does not starve the applications.
"The scheduler's overhead is negligible."
The scheduler's overhead is the per-request bookkeeping, and it can be significant on a high-throughput device. An NVMe SSD at millions of IOPS generates millions of requests per second, and the BFQ's per-request bookkeeping can consume a significant fraction of the processor's time. The no-op scheduler's overhead is zero, and it is the right choice for the devices whose throughput is the priority.
"The cgroup controller replaces the I/O priority."
The two mechanisms are complementary. The I/O priority is the per-process mechanism: it sets the process's priority class and level, and it is the right choice for the systems with a few processes. The cgroup controller is the group mechanism: it allocates the bandwidth among the groups, and it is the right choice for the multi-tenant systems. The two mechanisms' combination is the modern systems' standard.
"The scheduler's choice is permanent."
The scheduler's choice is a per-device runtime
setting: the administrator writes the scheduler's
name to
/sys/block/<device>/queue/scheduler,
and the change takes effect immediately. The
choice can be changed as the workload changes,
and the modern distributions' defaults are
starting points rather than final answers.
05 Worked example
The following example traces the classical algorithms through the standard queue, computes their total head movement and their average latency, compares the modern schedulers' behaviour, and shows the scheduling's effect on a live system's metrics.
Tracing the classical algorithms
Consider a disk with 200 cylinders (numbered 0 through 199) and a queue of requests: [98, 183, 37, 122, 14, 124, 65, 67]. The head is at cylinder 53, and it is moving toward the higher-numbered cylinders.
FCFS. The requests are served in arrival order:
Head: 53 → 98 → 183 → 37 → 122 → 14 → 124 → 65 → 67
Movement:
|98 - 53| = 45
|183 - 98| = 85
|37 - 183| = 146
|122 - 37| = 85
|14 - 122| = 108
|124 - 14| = 110
|65 - 124| = 59
|67 - 65| = 2
Total = 640 cylinders
FCFS's total movement is 640 cylinders, and the requests' average wait is the mean of the cumulative movements: (0 + 45 + 130 + 276 + 361 + 469 + 579 + 638) ÷ 8 = 1,248 ÷ 8 = 156 cylinders of average wait.
SSTF. The nearest request is served first:
Head at 53. The requests are [98, 183, 37, 122, 14,
124, 65, 67]. The nearest to 53 is 65 (distance 12).
Head: 53 → 65 → 67 → 37 → 14 → 98 → 122 → 124 → 183
Movement:
|65 - 53| = 12
|67 - 65| = 2
|37 - 67| = 30
|14 - 37| = 23
|98 - 14| = 84
|122 - 98| = 24
|124 - 122| = 2
|183 - 124| = 59
Total = 236 cylinders
SSTF's total movement is 236 cylinders, and the requests' average wait is (0 + 12 + 14 + 44 + 67 + 151 + 175 + 177) ÷ 8 = 640 ÷ 8 = 80 cylinders of average wait.
LOOK. The head sweeps in the current direction (toward the higher-numbered cylinders) until the last request, then reverses and sweeps in the other direction:
Sweep up: 53 → 65 → 67 → 98 → 122 → 124 → 183
(the requests at 65, 67, 98, 122, 124, 183)
Reverse: 183 → 37 → 14
(the requests at 37, 14)
Movement:
|65 - 53| = 12
|67 - 65| = 2
|98 - 67| = 31
|122 - 98| = 24
|124 - 122| = 2
|183 - 124| = 59
|37 - 183| = 146
|14 - 37| = 23
Total = 299 cylinders
Wait — the LOOK's total is 299, which is worse than SSTF's 236. The reason is that the queue's requests are not sorted by address: the head must travel from 183 back to 37, a long seek. Let me recompute: the LOOK's total is indeed 299, and the comparison with SSTF is not always favourable for LOOK. The observation is the classical algorithms' workload dependence: the SCAN family's advantage is in the long run, not in a single short queue. For a single queue, SSTF is often better; for a stream of requests, the SCAN family's bounded sweep gives better fairness and comparable throughput.
The honest comparison is therefore: FCFS's 640 is the worst; SSTF's 236 is the best for this queue; LOOK's 299 is between. The averages: FCFS's 156, SSTF's 80, LOOK's 78 — the three algorithms' average waits are closer than their total movements suggest, because the SCAN family's sweep gives the middle requests a shorter wait than the far ones.
Comparing the modern schedulers
The modern schedulers' behaviour is best understood by their design goals rather than by a single queue's trace. The following table summarizes their behaviour on a workload with a mix of latency- sensitive reads and throughput-oriented writes:
| Scheduler | Read latency | Write throughput | Fairness | Overhead |
|---|---|---|---|---|
| mq-deadline | Bounded (500 ms default) | High (sorted queue) | Deadline-based | Low |
| BFQ | Bounded (budget-based) | High (but slightly lower) | Strong (weighted) | Medium |
| Kyber | Bounded (latency target) | High (throttled) | None | Very low |
| none | Device's raw latency | Device's raw throughput | Arrival order | Zero |
The table's pattern is the modern schedulers'
design's summary. The mq-deadline is
the general-purpose choice: it bounds the reads'
latency and preserves the writes' throughput, and
its overhead is low. The BFQ is the
fairness choice: it provides the strong weighted
fairness, and its overhead is acceptable on the
general-purpose devices. The Kyber is
the SSD choice: it bounds the latency with the
minimal overhead, and it is the right choice for
the high-performance SSDs. The none
is the device's own choice: it lets the device's
controller do the scheduling, and it is the right
choice for the devices whose controllers are
capable (the NVMe SSDs, the virtual devices).
The scheduling's effect on the system's metrics
The scheduling's effect is visible in the system's metrics. The following commands show the device's utilization, its throughput, and its latency under different schedulers:
# Show the device's current scheduler
cat /sys/block/sda/queue/scheduler
# Show the device's statistics
iostat -x 1 3
# The output's columns include:
# r/s, w/s — the read and write requests per second
# rkB/s, wkB/s — the read and write bandwidth
# await — the average latency (ms)
# r_await, w_await — the read and write latencies
# aqu-sz — the average queue depth
# %util — the device's utilization
# Change the scheduler and re-measure
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler
iostat -x 1 3
echo none | sudo tee /sys/block/sda/queue/scheduler
iostat -x 1 3
# Compare the latency and the throughput across the schedulers.
The comparison's results depend on the device and the workload. On a hard disk with a random workload, the mq-deadline's throughput is higher than the none's, because the sorting reduces the head's movement. On an SSD, the mq-deadline's throughput is close to the none's, and its advantage is the reads' bounded latency. The observation is the scheduling's fundamental trade-off: the scheduler's benefit depends on the device's characteristics and the workload's access pattern, and the administrator's tuning must account for both.
The queue depth's effect
The queue depth's effect is the modern devices' central performance factor. The following commands measure the effect of the queue depth on an SSD's throughput:
# Measure the throughput at different queue depths
# (if fio is available)
for qd in 1 2 4 8 16 32 64 128; do
echo "=== queue depth $qd ==="
sudo fio --name=test --filename=/tmp/fio-qd.bin \
--size=500M --rw=randread --bs=4k --iodepth=$qd \
--ioengine=libaio --direct=1 --runtime=3 --time_based \
2>/dev/null | grep -E 'IOPS|bw'
done
# Clean up
rm /tmp/fio-qd.bin 2>/dev/null
The throughput increases with the queue depth until it saturates at the device's maximum. The saturation point is the device's parallelism's limit: the SSD's controller can process only so many requests at once, and the additional requests queue up without increasing the throughput. The observation is the reason the modern schedulers' queue-depth management matters: the scheduler must keep the queue's depth high enough to saturate the device but low enough to bound the latency, and the balance is the Kyber's latency target and the BFQ's budget's design.
06 Interactive activity
Activity · explore disk scheduling on a live system
The goal of this activity is to use the Linux command line to inspect the system's disk schedulers, to measure the effect of the scheduler's choice on the system's performance, and to observe the queue depth's and the I/O priority's effects. Work through the steps in your course VM.
-
Inventory the devices and their
schedulers.
Use
lsblkand the sysfs interfaces to list the block devices and their schedulers.
Which devices are rotational, and which are solid-state? What scheduler does each device use? What schedulers are available? Write down what you find.# List the block devices lsblk -d -o NAME,SIZE,ROTA,TRAN,MODEL # Show each device's scheduler for dev in $(lsblk -dn -o NAME); do echo -n "/dev/$dev: " cat /sys/block/$dev/queue/scheduler 2>/dev/null done # Show the available schedulers for one device cat /sys/block/sda/queue/scheduler 2>/dev/null -
Measure the device's baseline
performance.
Use
iostatandddto measure the device's throughput and latency under the current scheduler.
What is the device's throughput? What is its utilization? What is the average latency? How do the sequential and random throughputs compare?# Measure the baseline with iostat iostat -x 1 3 # Record the columns: r/s, w/s, rkB/s, wkB/s, await, %util # Measure a sequential read's throughput dd if=/dev/sda of=/dev/null bs=1M count=500 2>&1 | tail -1 # Measure a random read's throughput dd if=/dev/sda of=/dev/null bs=4k count=10000 iflag=direct 2>&1 | tail -1 -
Change the scheduler and re-measure.
If you have permission to change the device's
scheduler (in a VM, you usually do), try the
different schedulers and compare the results.
How does the throughput change across the schedulers? How does the latency change? Which scheduler is best for your device and workload? Explain the difference in terms of the lesson's concepts.# Record the current scheduler cat /sys/block/sda/queue/scheduler # Try mq-deadline echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler iostat -x 1 3 # Try none echo none | sudo tee /sys/block/sda/queue/scheduler iostat -x 1 3 # Try bfq (if available) echo bfq | sudo tee /sys/block/sda/queue/scheduler 2>/dev/null iostat -x 1 3 # Restore the original scheduler echo <original> | sudo tee /sys/block/sda/queue/scheduler -
Observe the queue depth's effect.
Use
fio(if available) or a custom workload to measure the effect of the queue depth on the throughput.
How does the throughput change with the queue depth? At which depth does it saturate? What does the saturation point tell you about the device's parallelism?# Check whether fio is available which fio # If it is, measure the throughput at different queue depths for qd in 1 4 16 64 128; do echo "=== queue depth $qd ===" sudo fio --name=test --filename=/tmp/fio-depth.bin \ --size=200M --rw=randread --bs=4k --iodepth=$qd \ --ioengine=libaio --direct=1 --runtime=3 --time_based \ 2>/dev/null | grep -E 'IOPS|bw' done # Clean up rm /tmp/fio-depth.bin 2>/dev/null -
Observe the I/O priority's effect.
Use
ioniceto set the I/O priority of a workload and observe its effect.
How does the I/O priority affect the two workloads' progress? Does the high-priority workload complete faster? Does the low-priority workload's throughput drop? What does the experiment tell you about the scheduler's fairness?# Start a background workload with a low priority ionice -c3 -p $$ # set this shell's class to 'idle' dd if=/dev/sda of=/dev/null bs=1M count=500 & # In another shell, run a high-priority workload ionice -c1 -n0 dd if=/dev/sda of=/dev/null bs=4k count=1000 iflag=direct # Observe the two workloads' progress with iotop sudo iotop -b -n 1 2>/dev/null | head -10 # Wait for the background workload to finish wait -
Examine the device's statistics.
Use
/proc/diskstatsandiostatto examine the device's detailed statistics.
What are the device's read and write rates? What is the average request size? What is the average latency? What is the queue depth? Explain the statistics in terms of the lesson's concepts.# Show the device's raw statistics cat /proc/diskstats | grep -E 'sda|nvme' # The columns include: # reads completed, reads merged, sectors read, ms reading # writes completed, writes merged, sectors written, ms writing # I/Os in progress, ms doing I/O, weighted ms doing I/O # Use iostat for a friendlier view iostat -x -m 1 3 -
Compare the device types' behaviour.
If the system has both a hard disk and an SSD (or
two devices with different types), compare their
scheduling behaviour.
Which device's random throughput is closer to its sequential throughput? Which device benefits more from the sorting scheduler? Explain the difference in terms of the devices' mechanical characteristics.# Identify the devices and their types lsblk -d -o NAME,SIZE,ROTA,TRAN,MODEL # Measure each device's random read throughput for dev in $(lsblk -dn -o NAME); do echo "=== /dev/$dev ===" sudo hdparm -t /dev/$dev 2>/dev/null dd if=/dev/$dev of=/dev/null bs=4k count=1000 iflag=direct 2>&1 | tail -1 done -
Read the man pages.
Read the man pages that document the scheduling
interfaces.
For each, write a sentence describing its main contribution to your understanding of disk scheduling. Theman 1 iostat man 1 iotop man 1 ionice man 1 fio man 5 proc man 2 ioprio_set man 5 cgroupsman 1 iostatpage documents the device statistics; theman 1 ionicepage documents the I/O priority; theman 5 cgroupspage documents the control groups and their controllers.
Reflect: disk scheduling is one of the operating system's oldest performance mechanisms, and its history is a history of adaptation. The classical algorithms were designed for the hard disks of the 1970s, and their designs assumed the seek time's dominance. The modern schedulers are designed for the multi-queue block layer and the solid-state drives, and their designs assume the parallelism and the write amplification's importance. The trend is toward the device's autonomy: the modern devices' controllers do the scheduling internally, and the kernel's role is shrinking. Which of the mechanisms from this lesson matter most for the devices you use? What would you change about the scheduler's design if you could? How would you explain the difference between the hard disk's and the SSD's scheduling problems to someone who has never thought about it? What is the right balance between the kernel's scheduling and the device's internal scheduling?
07 Knowledge check
Check your understanding
Question 1
Define the disk scheduling problem. Why does the order of the requests matter, and what are the three competing objectives that the scheduler must balance?
Show answer
Question 2
Describe the classical scheduling algorithms (FCFS, SSTF, SCAN, C-SCAN, LOOK, C-LOOK). What are each algorithm's order, its throughput, and its fairness?
Show answer
Question 3
Describe the Linux kernel's multi-queue block layer and its four schedulers (mq-deadline, BFQ, Kyber, none). What is each scheduler's design, and when is each appropriate?
Show answer
queue_rq method consumes. The
software queues are mapped to the hardware
queues, typically one per core, so the
submissions and the completions do not contend.
The kernel provides four schedulers for the
multi-queue block layer.
mq-deadline maintains three
queues: a sorted queue (the requests ordered by
block address, for the throughput), a read
deadline queue, and a write deadline queue
(the requests ordered by their deadlines, for
the latency and the fairness). The scheduler
dispatches from the sorted queue normally, but
when a request's deadline approaches (the
default is 500 ms for the reads and 5 s for the
writes), it dispatches the request from the
deadline queue. The design balances the
throughput and the latency, and it is the
kernel's default scheduler for the
general-purpose workloads. BFQ (Budget
Fair Queueing) provides the strong
fairness guarantees of the budget fair queueing
algorithm. Each application (or cgroup) has a
weight and a budget (the number of sectors it
may transfer before the scheduler switches to
another application), and the scheduler
allocates the device's bandwidth proportionally
to the weights. BFQ's fairness is its principal
advantage, and its overhead is its
disadvantage: the per-request bookkeeping is
more expensive than mq-deadline's. BFQ is the
kernel's recommended scheduler for the desktop
and the interactive workloads.
Kyber is a scheduler designed
for the high-performance devices (the NVMe
SSDs). Its design is lightweight: it maintains a
small number of queues per operation type, and
it throttles the submissions when the device's
queue's depth exceeds a target (the latency
target). The throttling keeps the device's
queue's depth in the range where the device's
latency is bounded, so the scheduler's overhead
is minimal and the device's latency is
controlled. Kyber is the kernel's recommended
scheduler for the high-performance SSDs.
none (noop) performs no
scheduling: the requests are dispatched to the
device in the order they arrive (with the
merging). The scheduler's overhead is zero, and
its throughput is the device's raw throughput.
It is the kernel's default for the devices
whose access time is nearly uniform (the SSDs,
the NVMe devices, the virtual devices), where
the sorting's benefit is small and the
scheduling's overhead is a waste. The choice
among the four is a per-device setting, and the
administrator can change it at runtime by
writing the scheduler's name to
/sys/block/<device>/queue/scheduler.
The modern distributions use mq-deadline for
the hard disks and none or kyber for the SSDs.
Question 4
Explain how the solid-state drives' characteristics change the scheduling problem. Why do the modern distributions use the no-op or Kyber scheduler for the SSDs?
Show answer
none scheduler's overhead is zero,
and it lets the device's controller do the
scheduling internally; the Kyber
scheduler's design bounds the device's latency
with the minimal overhead, and it is the right
choice for the high-performance SSDs. The
device's controller is becoming a computer in
its own right (the flash translation layer's
parallelism, the garbage collection's pacing),
and the kernel's scheduling's role is
shrinking. The design is the modern storage
stack's central trend: the device's autonomy is
increasing, and the kernel's role is limited to
the submission and the completion.
Question 5
Describe the I/O priority and the cgroup controllers. How do they differ, and when is each appropriate?
Show answer
ionice command
sets and the ioprio_set system
call sets programmatically. The classes are
the real-time (the highest priority,
for the processes that must not be delayed),
the best-effort (the default, with
the levels 0–7), and the idle (the
lowest priority, for the processes that should
yield to all others). The BFQ and mq-deadline
schedulers honour the priorities: the
higher-priority processes' requests are
dispatched first, and the lower-priority
processes' requests wait. The cgroup
blkio controller is the group
mechanism: the controller lets the administrator
group the processes (into the cgroups) and
allocate the devices' bandwidth among the
groups. The allocation is expressed in the
weights (the proportional shares) or in the
limits (the maximum bandwidth, the maximum
IOPS). The controller's design is the
multi-tenant systems' basis: a virtual
machine's or a container's I/O is limited by
its cgroup's allocation, and the other tenants'
I/O is protected. The two mechanisms differ in
their granularity and their complexity. The
I/O priority is the per-process mechanism: it
is simple, and it is sufficient for the systems
with a few processes and a well-understood
priority structure. The cgroup controller is
the group mechanism: it is more complex, and it
is necessary for the systems with many tenants
and a dynamic workload. The two mechanisms are
complementary, and their combination (the
priority within the cgroup, the weight across
the cgroups) is the modern systems' standard.
The administrators of the multi-tenant systems
must configure both: the cgroup's weights for
the tenants' fair allocation, and the processes'
priorities for the important workloads'
latency. The configuration's goal is the
balance between the fairness (the tenants'
proportional shares) and the responsiveness
(the important processes' bounded latency), and
the balance's tuning is the administrator's
ongoing task.
08 Unit discussion
Discussion prompt
Disk scheduling is one of the operating system's oldest performance mechanisms, and its history is a history of adaptation to the storage technology. The classical algorithms — FCFS, SSTF, SCAN, C-SCAN, LOOK, C-LOOK — were developed for the hard disks of the 1970s and 1980s, and their designs assumed the seek time's dominance: the scheduling's job was to minimize the head's movement, and the algorithms' trade-offs were the throughput versus the latency and the fairness. The modern schedulers — mq-deadline, BFQ, Kyber, none — are designed for the multi-queue block layer and the solid-state drives, and their designs assume the parallelism and the write amplification's importance: the scheduling's job is to keep the device's queue's depth in the right range, to pace the submissions so the garbage collection does not starve the applications, and to bound the tail latency. The shift is a sign of the storage technology's change: the hard disk's mechanical delays are disappearing, and the scheduling's problem is becoming the queue's management rather than the head's movement.
The trend raises a question about the scheduling's future. If the device's controller does the scheduling internally, and the kernel's role is limited to the submission and the completion, does the kernel's scheduler still have a role? The modern answers are mixed: the no-op scheduler's design assumes that the device's controller is capable, and it lets the controller do the work; the Kyber scheduler's design assumes that the device's controller needs the kernel's help to bound the latency, and it provides the throttling; the BFQ scheduler's design assumes that the kernel's fairness mechanisms are necessary, and it provides the weighted allocation. The three schedulers' coexistence is the modern systems' reality: the right choice depends on the device and the workload, and the administrator must choose.
The trend also raises a question about the scheduling's scope. The classical schedulers scheduled the requests within one device; the modern systems have several devices (the hard disks, the SSDs, the NVMe devices, the virtual devices), and the requests' placement across the devices is a scheduling problem in itself. The multi-device scheduling (the workload's placement, the devices' utilization, the data's locality) is the modern systems' additional concern, and the kernel's mechanisms (the device-mapper's targets, the RAID's layouts, the file system's allocation policies) are its partial solutions. The complete solution — the system-wide I/O scheduling that accounts for the devices' characteristics, the workload's requirements, and the tenants' fairness — is an open problem, and it is one of the modern storage systems' research areas.
Where should the scheduling's boundary be: in the kernel, in the device's controller, or in the application? Should the kernel's scheduler adapt to the device automatically, or should the administrator choose the scheduler and its parameters? What is the right balance between the throughput, the latency, and the fairness, and who should decide? Post your response to the Unit 11 discussion forum and reply to at least two classmates. Supports CLO1, CLO5, and CLO6.
09 Practice exercise
This ungraded exercise consolidates the lesson and prepares you for Lesson 11.6. Aim to spend 60–90 minutes on it.
-
Trace the classical algorithms.
A disk has 300 cylinders (0 through 299), and the
queue is [120, 45, 210, 30, 250, 75, 90, 180].
The head is at cylinder 60 and is moving toward
the higher-numbered cylinders. Trace each of the
following algorithms, showing the head's
movement and computing the total movement and
the average wait:
- FCFS
- SSTF
- LOOK
- C-LOOK
- Compare the algorithms. Write a short paragraph (200–250 words) comparing FCFS, SSTF, and the SCAN family. Your paragraph should address: (a) each algorithm's order; (b) each algorithm's throughput and latency; (c) each algorithm's fairness; (d) each algorithm's pathologies; (e) the workloads for which each is best suited.
-
Measure the scheduler's effect.
Change the device's scheduler and measure the
effect on the throughput and the latency.
How does the throughput change across the schedulers? How does the latency change? Which is best for your device? Explain the result in terms of the device's type and the workload.# Record the current scheduler cat /sys/block/sda/queue/scheduler # Measure with the current scheduler iostat -x 1 3 # Change to mq-deadline echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler iostat -x 1 3 # Change to none echo none | sudo tee /sys/block/sda/queue/scheduler iostat -x 1 3 # Restore the original echo <original> | sudo tee /sys/block/sda/queue/scheduler -
Measure the queue depth's effect.
If the system has
fio, measure the effect of the queue depth on the throughput and the latency.
How does the throughput change with the queue depth? How does the latency change? At which depth does the throughput saturate, and what happens to the latency beyond that point? Explain the result in terms of the device's parallelism.# Measure at different queue depths for qd in 1 2 4 8 16 32 64; do echo "=== queue depth $qd ===" sudo fio --name=test --filename=/tmp/fio-qd.bin \ --size=200M --rw=randread --bs=4k --iodepth=$qd \ --ioengine=libaio --direct=1 --runtime=3 --time_based \ 2>/dev/null | grep -E 'IOPS|bw|lat' done # Clean up rm /tmp/fio-qd.bin 2>/dev/null -
Examine the I/O priority's effect.
Use
ioniceandiotopto observe the I/O priority's effect.
How does the I/O priority affect the two workloads? Does the high-priority workload complete faster? Does the low-priority workload's throughput drop? What does the experiment tell you about the scheduler's fairness mechanisms?# Start a low-priority workload in the background ionice -c3 dd if=/dev/sda of=/dev/null bs=1M count=1000 & # Run a high-priority workload ionice -c1 -n0 dd if=/dev/sda of=/dev/null bs=4k count=2000 iflag=direct # Observe the workloads with iotop sudo iotop -b -n 1 2>/dev/null | head -10 # Wait for the background workload wait -
Examine the device's statistics.
Use
/proc/diskstatsandiostatto examine the device's statistics in detail.
What are the device's read and write rates? What is the average request size? What is the average latency? What is the queue depth? Explain the statistics in terms of the scheduling concepts from the lesson.# Show the raw statistics cat /proc/diskstats | grep sda # Show the friendly view iostat -x -m 1 3 # Run a mixed workload and observe the statistics dd if=/dev/zero of=/tmp/mixed.bin bs=1M count=200 2>/dev/null & dd if=/dev/sda of=/dev/null bs=4k count=5000 iflag=direct 2>/dev/null wait iostat -x -m 1 3 # Clean up rm /tmp/mixed.bin -
Design a scheduling configuration.
A server is being built for a database workload.
The database performs many small random reads (4
KB each) and many small writes, and it requires
low latency for the reads and high throughput for
the writes. The server has an NVMe SSD and a
hard-disk-based backup volume. Design the
scheduling configuration. Consider:
- Which scheduler would you use for the SSD, and why?
- Which scheduler would you use for the hard disk, and why?
- How would you configure the I/O priority for the database's processes?
- How would you configure the cgroup controllers for the multi-tenant scenario?
- How would you measure the system's performance, and what metrics would you watch?
- Reflect. In your own words, explain why the disk scheduling matters on a hard disk and why it matters less on an SSD. Describe the classical algorithms' trade- offs and the modern schedulers' designs. Then describe one situation in your own experience — a program you have written or a system you have used — where the disk scheduling affected the performance. What was the workload, and how would a different scheduler or a different configuration have changed the outcome?
10 Summary
- The disk scheduling problem is the problem of ordering the pending I/O requests to optimize the device's performance. The order matters because of the hard disk's mechanical delays — the seek and the rotational delay — which dominate the access time. The scheduler must balance the throughput, the latency, and the fairness, and the three objectives conflict.
- The classical algorithms are FCFS (arrival order; perfect fairness, worst throughput), SSTF (nearest first; good throughput, poor fairness), SCAN (the elevator algorithm; a sweep in one direction, then a reverse), C-SCAN (a sweep in one direction, then a return without serving), LOOK (SCAN to the last request), and C-LOOK (C-SCAN to the last request). The SCAN family is the practical choice: its movement is close to SSTF's, and its fairness is better.
- The SCAN family's trade-offs are the far requests' wait, the arm's stickiness, the writes' delay, the read-ahead's interference, and the multiple devices' interference. The modern schedulers address them with the deadlines, the fairness, and the parallelism.
- The multi-queue block layer (introduced in Linux 3.13) replaced the single queue with a two-level structure: the software queues (one per processor core, lockless) and the hardware queues (one per device's hardware queue). The design is the reason the modern devices achieve their throughput.
- The modern Linux schedulers are mq-deadline (a sorted queue plus the deadline queues; the general-purpose choice), BFQ (budget fair queueing; the strong fairness, the desktop and the multi-tenant choice), Kyber (the queue-depth throttling; the high-performance SSDs), and none (the arrival order, no scheduling; the fast SSDs and the virtual devices). The choice is a per-device setting, and the modern distributions use mq-deadline for the hard disks and none or kyber for the SSDs.
- The solid-state drive's characteristics change the scheduling problem: the sorting's benefit is small, and the parallelism, the write amplification, the garbage collection, and the latency's distribution are the new concerns. The no-op and Kyber schedulers are the SSD-appropriate choices.
-
The I/O priority (the per-process
mechanism, set by
ionice) and the cgroup blkio controller (the group mechanism) allocate the devices' bandwidth among the processes and the groups. The two mechanisms are complementary, and their combination is the multi-tenant systems' standard. - The scheduling's effect is visible in the system's metrics: the throughput, the latency, the fairness, and the scheduler's own CPU overhead. The administrator's tuning (the scheduler's selection, its parameters, the I/O priority, the cgroup's weights) is the balance among the metrics, and it must account for the device's characteristics and the workload's access pattern.
Looking ahead
This lesson presented disk scheduling: the scheduling problem and the hard disk's performance characteristics, the classical algorithms and their trade-offs, the multi-queue block layer and the modern Linux schedulers, the solid-state drives' different characteristics and the schedulers' adaptation, the I/O priority and the cgroup controllers, and the scheduling's effect on the system's performance. It referred several times to the redundancy and the multiple devices — the RAID arrays, the mirrors, and the multi-device configurations that the modern storage systems use — and to the solid-state drives's internal parallelism. Lesson 11.6 presents RAID in detail: the RAID levels (0, 1, 5, 6, 10), their performance and their reliability, the hardware and software implementations, the rebuild process, and the RAID's interaction with the file system and the block layer. Lesson 11.7 presents the SSD architecture: the flash memory's organization, the flash translation layer, the wear leveling, the garbage collection, and the internal parallelism. The three lessons together complete the unit's view of the storage stack, from the device's controller to the file system.
11 References
- Silberschatz, A., Galvin, P. B., & Gagne, G. Operating System Concepts, 10th ed., Chapter 11, Section 11.2.
-
Arpaci-Dusseau, R. H., & Arpaci-Dusseau, A. C.
Operating Systems: Three Easy Pieces, Chapters 37
and 38. Available online at
ostep.org. - Tanenbaum, A. S., & Bos, H. Modern Operating Systems, 4th ed., Chapter 5, Section 5.4.
- Love, R. Linux Kernel Development, 3rd ed., Chapter 16, The Block I/O Layer.
- Bovet, D. P., & Cesati, M. Understanding the Linux Kernel, 3rd ed. O'Reilly, 2005. Chapter 14, Block Device Drivers.
- Axboe, J. Linux Block IO: Introducing Multi-queue SSD Access on Multi-core Systems. Proceedings of the 6th International Systems and Storage Conference (SYSTOR), 2013.
- Valente, P., & Checconi, F. High Throughput Disk Scheduling with Fair Bandwidth Distribution. IEEE Transactions on Computers, 2010.
-
Linux man-pages:
man 1 iostat,man 1 iotop,man 1 ionice,man 1 fio,man 5 proc,man 2 ioprio_set,man 5 cgroups,man 8 blkdiscard,man 1 lsblk.