<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Iotop · XB Field Notes</title><link>https://www.xbcatm.com/tags/iotop/</link><description>Illustrated field notes on HTTP, DNS, TLS, Caddy, SSH, releases, and recovery.</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://www.xbcatm.com/tags/iotop/index.xml" rel="self" type="application/rss+xml"/><item><title>iotop shows which process is burning the disks</title><link>https://www.xbcatm.com/posts/linux-iotop-io-waiter/</link><pubDate>Wed, 15 Mar 2028 00:00:00 +0000</pubDate><guid>https://www.xbcatm.com/posts/linux-iotop-io-waiter/</guid><description>iotop watches per process IO by reading kernel accounting, so you can blame a specific pid for a busy disk.</description><content:encoded>&lt;p&gt;A disk that spikes with no obvious writer is hard to chase; iotop maps throughput straight back to the task doing the damage. System-wide tools show the symptom — high await, saturated utilization — but never the suspect: fifty processes share the disk and the average blames all of them equally. The question that ends the investigation is always per-process — who, how much, since when — and iotop answers exactly that, live, from kernel counters no application can hide from.&lt;/p&gt;
&lt;p&gt;Keep it beside the system-wide view rather than instead of it. iostat or vmstat says the disk is the bottleneck; iotop names the process making it so. Together they compress a storage mystery into a two-command diagnosis: confirm the resource, identify the consumer.&lt;/p&gt;
&lt;h2 id="per-process-counters"&gt;Per-process counters&lt;/h2&gt;
&lt;p&gt;iotop reads per-process IO from the kernel, so live read and write rates map to a pid rather than a nameless load average. Run it with &lt;code&gt;-o&lt;/code&gt; to show only processes that are actually doing IO. The default view splits reads from writes and shows swap-in percentage alongside throughput, which separates the genuinely disk-hungry from the merely present — a process with high DISK READ but zero writes is scanning, one with writes is producing, and the distinction decides whether you throttle, relocate, or kill.&lt;/p&gt;
&lt;p&gt;Note what the counters actually measure: bytes passing through the IO layer per process, including buffered writes not yet on disk. A process can show huge write rates while the disk looks idle (page cache absorbing) or modest rates while the disk saturates (many small synchronous writes). Read iotop together with device utilization: process-side blame plus device-side saturation is the complete picture, and either half alone misleads.&lt;/p&gt;
&lt;h2 id="see-whatever-sweeps-the-disk"&gt;See whatever sweeps the disk&lt;/h2&gt;
&lt;p&gt;Sort by bandwidth and the offender stands out, whether it is a log hoarder, an indexer, or a runaway backup. Follow the pid to the exact process (and often the file) before acting. The usual lineup: an unrotated log written at debug level, a reindex job scheduled against peak hours, a backup writing to the same spindle it reads from, a container layer unpack looping on a corrupt image. Each has a different fix — rotate, reschedule, separate, prune — and killing the process treats the symptom while the cause reschedules itself for tomorrow.&lt;/p&gt;
&lt;p&gt;Resolve the pid to its full context before touching anything: command line, working directory, open files via lsof, parent process. A java process burning writes might be ten applications behind one PID namespace; the fix belongs to the right one. Attribution first, action second — every storage war story that ends in regret skipped the first step.&lt;/p&gt;
&lt;h2 id="watch-before-you-act"&gt;Watch before you act&lt;/h2&gt;
&lt;p&gt;iotop observes rather than changes anything, so you can investigate the culprit before deciding what to throttle, move, or kill. Pair it with strace or lsof on the pid to pin the file and the syscall. The combination is decisive: iotop says process 18412 writes 400 MB/s, lsof says the writes go to one growing log file, strace shows O_APPEND writes of 4 KB — diagnosis complete, and the fix (log level, rotation, async appender) is obvious instead of debated.&lt;/p&gt;
&lt;p&gt;Record the baseline while healthy so the incident comparison means something. A five-minute iotop batch capture on a normal day — &lt;code&gt;-b -n 60&lt;/code&gt; to a file — gives you &amp;ldquo;normal for this host&amp;rdquo; in numbers: which processes usually lead, what rates are ordinary. Without it, every spike looks unprecedented; with it, most incidents classify in seconds as &amp;ldquo;the indexer, again, an hour early.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="when-it-breaks"&gt;When it breaks&lt;/h2&gt;
&lt;p&gt;The classic meta-failure is permission blindness: run without privileges and iotop shows question marks instead of process details, or hides other users&amp;rsquo; processes entirely — and the actual offender, running as another user, stays invisible. Run with the necessary privileges (root or the right capabilities) from the start, or the tool exonerates exactly the processes you cannot see. An investigation that &amp;ldquo;found nothing&amp;rdquo; with unprivileged iotop found nothing about your own processes only.&lt;/p&gt;
&lt;p&gt;The second failure is sampling illusion on bursty IO: a process doing violent one-second bursts every minute looks innocent in a 5-second average and guilty in a 1-second one, or vice versa. Vary the delay interval when the numbers and the symptoms disagree, and prefer accumulated totals (&lt;code&gt;-a&lt;/code&gt;) over instantaneous rates for &amp;ldquo;who hurt the disk over the last hour&amp;rdquo; questions. The right aggregation answers the question asked; the default answers whichever question its interval assumes.&lt;/p&gt;
&lt;h2 id="check-it-quickly"&gt;Check it quickly&lt;/h2&gt;
&lt;p&gt;Capture who does IO, with context, non-interactively:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;iotop -b -n 5 -o -d 2 | head -n 30
pid=$(iotop -b -n 1 -o | awk &amp;#39;NR&amp;gt;5 {print $1}&amp;#39; | head -n 1); ls -l /proc/$pid/exe; cat /proc/$pid/cmdline | tr &amp;#39;\0&amp;#39; &amp;#39; &amp;#39;
iostat -x 1 3 | grep -E &amp;#34;Device|sd|nvme&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The batch capture ranks offenders without a terminal UI, the pid resolution names the top writer&amp;rsquo;s binary, and iostat confirms the device side is actually saturated.&lt;/p&gt;
&lt;h2 id="sources"&gt;Sources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man8/iotop.8.html"&gt;iotop man page&lt;/a&gt;, Official iotop reference, checked 2026-06-01.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://man7.org/linux/man-pages/man8/vmstat.8.html"&gt;vmstat man page&lt;/a&gt;, documents system-wide CPU and IO-wait reporting, checked 2026-09-05.&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item></channel></rss>