<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Beyond the Stacks]]></title><description><![CDATA[Beyond the Benchmarks. Into Real-World Infrastructure.
Exploring cloud, distributed systems, GPU computing, and AI infrastructure through real production challe]]></description><link>https://beyondthestacks.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6adb877df6f60b8802f04339/f8fcac9b-7881-4bf4-b6a9-5a8bf7b94710.png</url><title>Beyond the Stacks</title><link>https://beyondthestacks.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 04 Nov 2026 20:06:27 GMT</lastBuildDate><atom:link href="https://beyondthestacks.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Your Linux Server Is Not Running Out of Memory — A 2026 Guide to RAM, Swap, and AI Workloads]]></title><description><![CDATA[Linux deliberately fills almost all your RAM with cache. The "139 MB free" you're panicking about is the kernel doing exactly what it should. Swap is more…]]></description><link>https://beyondthestacks.hashnode.dev/your-linux-server-is-not-running-out-of-memory-a-2026-guide-to-ram-swap-and-ai-workloads</link><guid isPermaLink="true">https://beyondthestacks.hashnode.dev/your-linux-server-is-not-running-out-of-memory-a-2026-guide-to-ram-swap-and-ai-workloads</guid><category><![CDATA[ram]]></category><category><![CDATA[swap]]></category><category><![CDATA[ai-workloads]]></category><dc:creator><![CDATA[Pawan Kumar Singh]]></dc:creator><pubDate>Sat, 24 Oct 2026 09:01:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb877df6f60b8802f04339/bd330d3f-f43c-4f36-90b1-8fe8aa7c14c2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p>Linux deliberately fills almost all your RAM with cache. The "139 MB free" you're panicking about is the kernel doing exactly what it should. Swap is more nuanced in 2026 than "always off" — disk swap remains dangerous, but zram and AI training frameworks have changed the conversation. Here's the honest, updated picture.</p>
</blockquote>
<hr />
<h2>The Alarm That Isn't One</h2>
<p>You SSH into a production server. You run <code>free -m</code>. You see this:</p>
<pre><code class="language-plaintext">               total        used        free      shared  buff/cache   available
Mem:           15727       15588         139           0       12261       12187
Swap:           3071         302        2769
</code></pre>
<p>Your heart skips. <strong>15.5 GB used. Only 139 MB free.</strong></p>
<p>You open a ticket. You ping the team. You consider rebooting.</p>
<p>Stop. The server is fine.</p>
<p>That output is one of the most consistently misread things in Linux operations. And in 2026 — with AI inference servers, vector databases, and GPU-backed workloads now running on Linux boxes that were never part of the traditional sysadmin curriculum — getting this wrong is more expensive than ever.</p>
<p>Let's break it apart, update the assumptions that have aged out, and build an accurate picture of Linux memory in the world we actually operate in today.</p>
<hr />
<h2>How Linux Actually Uses RAM</h2>
<p>Linux never lets RAM sit idle.</p>
<p>Whenever free memory exists, the kernel uses it to speed up the system by filling it with two things:</p>
<ul>
<li><strong>Buffers</strong> — filesystem metadata: directory entries, inode tables, permission bits. What the kernel needs to navigate the filesystem without touching the disk.</li>
<li><strong>Page Cache</strong> — the actual contents of files and block devices read from or written to disk recently. Every file opened, every binary loaded, every config file parsed at startup — kept in cache as long as RAM permits.</li>
</ul>
<p>The kernel's reasoning: RAM is roughly <strong>1,000 times faster</strong> than even the best NVMe SSD for the kind of small, random reads that swap and file access involve. If the kernel can serve a read from RAM instead of storage, it will.</p>
<p>This is not a bug. It is a fundamental design principle of the Linux VM subsystem, and it is why Linux outperforms other operating systems on I/O-heavy workloads.</p>
<hr />
<h2>Reading <code>free -m</code> Correctly in 2026</h2>
<p>Modern Linux systems running <code>procps-ng</code> (current standard across Ubuntu, RHEL, Debian, Arch) show:</p>
<pre><code class="language-plaintext">               total        used        free      shared  buff/cache   available
Mem:           15727        3291         121           0       12315       12187
Swap:           3071         302        2769
</code></pre>
<h3>The Only Column That Matters: <code>available</code></h3>
<table>
<thead>
<tr>
<th>Column</th>
<th>Value</th>
<th>What It Means</th>
</tr>
</thead>
<tbody><tr>
<td><code>total</code></td>
<td>15727 MB</td>
<td>Physical RAM installed</td>
</tr>
<tr>
<td><code>used</code></td>
<td>3291 MB</td>
<td>RAM consumed by running applications</td>
</tr>
<tr>
<td><code>free</code></td>
<td>121 MB</td>
<td>RAM doing absolutely nothing</td>
</tr>
<tr>
<td><code>buff/cache</code></td>
<td>12315 MB</td>
<td>Page cache + buffers — reclaimable immediately when apps need it</td>
</tr>
<tr>
<td><code>available</code></td>
<td>12187 MB</td>
<td>What a new process can actually use right now</td>
</tr>
</tbody></table>
<p><code>available</code> <strong>is the only number worth reading.</strong> It accounts for reclaimable cache. 12.1 GB is available. The server is healthy.</p>
<blockquote>
<p><strong>Rule:</strong> Ignore <code>free</code>. Read <code>available</code>. Alert on <code>available</code>, not <code>free</code>.</p>
</blockquote>
<h3>The Old Format (Still Alive in Older Systems)</h3>
<p>Older <code>free</code> versions showed this layout — and many tutorials still reference it:</p>
<pre><code class="language-plaintext">              total   used   free  shared  buffers   cached
Mem:          15727  15588    139       0       33    12228
-/+ buffers/cache:   3326  12401
Swap:          3071    302   2769
</code></pre>
<p>In this format, <code>used</code> on Line 1 includes buffers and cache, making the server look critically full. The real number was always on the <code>-/+ buffers/cache:</code> line — 12401 MB free. Modern <code>free</code> collapsed this into the <code>available</code> column. If you're on an old system: ignore Line 1's <code>free</code>, read Line 2's <code>free</code>.</p>
<hr />
<h2>Why a Healthy Server Always Looks "Full"</h2>
<p>Linux follows one principle: <strong>unused RAM is wasted performance.</strong></p>
<p>The page cache grows aggressively over time. On a server running for weeks:</p>
<ul>
<li>Shared libraries loaded by every process are mapped once and shared across all of them</li>
<li>Nginx static files serve from cache, bypassing disk entirely</li>
<li>MySQL's hot table pages live in cache alongside InnoDB buffer pool</li>
<li>PostgreSQL reads benefit from a second caching layer at the kernel level</li>
</ul>
<p>When a new process needs memory, the kernel evicts least-recently-used cache pages and hands that RAM over immediately — transparently, without the application noticing.</p>
<p><strong>A server with large genuinely free RAM is a server whose kernel is doing less than it should.</strong> High <code>buff/cache</code> is a sign of a well-utilized server, not a stressed one.</p>
<hr />
<h2>RAM in 2026: The Hardware Reality Has Shifted</h2>
<p>This context matters for everything that follows about swap.</p>
<p>When swap was designed in the early Unix era, servers had 32–256 MB of RAM. RAM cost thousands of dollars per megabyte. Swap was a genuine engineering solution to a real hardware constraint — a way to run programs larger than physical memory allowed.</p>
<p>That world does not exist anymore.</p>
<p><strong>RAM pricing today:</strong></p>
<table>
<thead>
<tr>
<th>Configuration</th>
<th>Common Use Case</th>
<th>Approximate Cost</th>
</tr>
</thead>
<tbody><tr>
<td>32–64 GB DDR5</td>
<td>Web/app server, dev VM</td>
<td>$60–150</td>
</tr>
<tr>
<td>128–256 GB DDR5</td>
<td>Database server, ML dev box</td>
<td>$200–500</td>
</tr>
<tr>
<td>512 GB–1 TB DDR5 ECC</td>
<td>LLM inference, large in-memory DB</td>
<td>$800–2,500</td>
</tr>
<tr>
<td>1.5–2 TB (ECC RDIMM)</td>
<td>Frontier AI inference, HPC</td>
<td>$3,000–6,000</td>
</tr>
</tbody></table>
<p>Cloud follows the same trend. AWS, GCP, and Azure offer memory-optimized instances at 256 GB, 512 GB, and 1.5 TB as standard catalogue options today.</p>
<p>The cost of adding 16 GB of RAM to a cloud instance is now less than one hour of an on-call engineer's time spent debugging a swap-induced incident.</p>
<p><strong>Storage is fast — but the latency gap with RAM has not closed:</strong></p>
<table>
<thead>
<tr>
<th>Storage Type</th>
<th>Random 4K Read Latency</th>
</tr>
</thead>
<tbody><tr>
<td>DDR5 RAM</td>
<td>~60–80 nanoseconds</td>
</tr>
<tr>
<td>NVMe Gen5 (local)</td>
<td>~70–100 microseconds</td>
</tr>
<tr>
<td>AWS EBS gp3 (cloud)</td>
<td>~500–1,000 microseconds</td>
</tr>
<tr>
<td>AWS EBS io2 (provisioned)</td>
<td>~100–200 microseconds</td>
</tr>
</tbody></table>
<p>NVMe Gen5 can push 14 GB/s of sequential throughput. That is impressive. But swap does not use sequential throughput — it uses random small-block reads of cold pages scattered across the device. At that access pattern, even Gen5 NVMe is <strong>1,000 times slower than DDR5 RAM</strong>. Cloud-attached block storage is 5,000–10,000 times slower.</p>
<p>That gap has not meaningfully closed in 30 years, and it will not close because it is a physical property of the two technologies, not an engineering limitation.</p>
<hr />
<h2>The Number That Should Worry You: Disk Swap in Use</h2>
<pre><code class="language-plaintext">Swap:   3071    302   2769
</code></pre>
<p><strong>302 MB of disk swap is active.</strong> On a traditional web or database server, this is a warning sign.</p>
<h3>Why Disk Swap Degrades Servers</h3>
<p>When the kernel starts swapping to disk, it triggers a cascade:</p>
<ol>
<li>Cold pages are written to the swap partition — disk I/O starts competing with application I/O.</li>
<li>When those pages are needed again, they must be read back — more disk I/O.</li>
<li>While processes wait for disk, they hold locks, connections, and queued requests.</li>
<li>Load average climbs. More processes queue. More swap I/O is triggered.</li>
<li>The disk I/O queue backs up. Everything slows — not just the swapping process.</li>
<li>MySQL queries start timing out. Nginx workers exhaust. API latency jumps from milliseconds to seconds.</li>
</ol>
<p>The server does not crash cleanly. It degrades while appearing operational — which makes diagnosis slower and the incident longer.</p>
<p><strong>Disk swap does not prevent a crash. It often converts a fast, clean OOM kill into a prolonged, ambiguous system-wide degradation.</strong></p>
<hr />
<h2>Where the "Always Disable Swap" Assumption Needs Updating</h2>
<p>Here is where the 2026 picture gets more nuanced than older advice.</p>
<h3>zram: Swap That Lives in RAM</h3>
<p><strong>zram</strong> is a compressed RAM-based block device used as swap. Instead of writing cold pages to disk, zram compresses them and stores them in RAM. When those pages are needed, they are decompressed — still entirely in RAM, no disk I/O involved.</p>
<p>This changes the tradeoff significantly:</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Disk Swap</th>
<th>zram</th>
</tr>
</thead>
<tbody><tr>
<td>Latency</td>
<td>1,000–10,000x slower than RAM</td>
<td>2–5x slower than RAM (compression overhead)</td>
</tr>
<tr>
<td>I/O competition</td>
<td>Competes with application disk I/O</td>
<td>No disk I/O whatsoever</td>
</tr>
<tr>
<td>Useful for</td>
<td>Almost nothing in production</td>
<td>Memory pressure with cold pages, desktop systems, container nodes</td>
</tr>
</tbody></table>
<p>zram is now enabled by default on <strong>Ubuntu 22.04+, Fedora 33+, and Android</strong> (which has used it since Android 4.4). It is a legitimate solution for handling occasional memory pressure without the catastrophic disk I/O cascade.</p>
<p>For production servers, zram does not replace proper RAM sizing — but if you are constrained and cannot disable all swap, replacing disk swap with zram is a meaningful upgrade:</p>
<pre><code class="language-bash"># Install and configure zram (Ubuntu/Debian)
apt install zram-tools

# Or manual setup
modprobe zram
echo lz4 &gt; /sys/block/zram0/comp_algorithm   # lz4 = fast; zstd = better compression
echo 8G &gt; /sys/block/zram0/disksize
mkswap /dev/zram0
swapon -p 100 /dev/zram0                      # Higher priority than disk swap
</code></pre>
<p><strong>Bottom line on zram:</strong> It is not a substitute for RAM, but it is a far safer fallback than disk swap. If you cannot disable swap entirely, replace disk swap with zram.</p>
<h3>AI Training: The Exception Where Offloading Makes Sense</h3>
<p>For AI <strong>training</strong> workloads specifically, the conversation around swap has taken a different turn — but not because disk swap is good. Because purpose-built NVMe offloading frameworks have emerged.</p>
<p>DeepSpeed's <strong>ZeRO-Infinity</strong> and <strong>ZeRO-3 with CPU offload</strong> deliberately move optimizer states and parameters to CPU RAM and NVMe storage during training. PyTorch's <code>OffloadOptimizer</code> does the same. These frameworks:</p>
<ul>
<li>Know exactly when a tensor is needed and prefetch it with sufficient lead time</li>
<li>Use high-bandwidth sequential I/O patterns, not random-access swap</li>
<li>Are aware of the latency tradeoff and schedule around it</li>
<li>Were designed specifically for the memory requirements of multi-hundred-billion parameter models</li>
</ul>
<p>This is <strong>fundamentally different from OS-level swap.</strong> The OS swapper has no idea what data it is evicting or when it will be needed. ZeRO-Infinity knows. The I/O is predictable and pipelined.</p>
<p><strong>If you are running AI training with DeepSpeed or FSDP with CPU/NVMe offload, that is a deliberate architectural choice — not swap as a safety net.</strong> The OS-level swap partition should still be off. These frameworks manage their own offloading independently.</p>
<hr />
<h2>Swap and AI Inference: Still Catastrophic</h2>
<p>For AI <strong>inference</strong> — serving models to users — the original advice holds without qualification.</p>
<p>Running a large language model requires keeping model weights resident in memory. The numbers are not small:</p>
<table>
<thead>
<tr>
<th>Model</th>
<th>Host RAM (FP16)</th>
<th>Host RAM (4-bit)</th>
</tr>
</thead>
<tbody><tr>
<td>Llama 3.2 3B</td>
<td>~6 GB</td>
<td>~2 GB</td>
</tr>
<tr>
<td>Llama 3.3 70B</td>
<td>~140 GB</td>
<td>~40 GB</td>
</tr>
<tr>
<td>DeepSeek R1 70B</td>
<td>~140 GB</td>
<td>~40 GB</td>
</tr>
<tr>
<td>Qwen 2.5 72B</td>
<td>~144 GB</td>
<td>~41 GB</td>
</tr>
<tr>
<td>Llama 3.1 405B</td>
<td>~810 GB</td>
<td>~230 GB</td>
</tr>
</tbody></table>
<p>When a request arrives, the inference engine reads through model weights layer by layer — in RAM, at RAM speed, sequentially. If any portion of those weights has been paged to disk:</p>
<ul>
<li>Each inference call triggers disk reads across potentially gigabytes of model data</li>
<li>A request that normally takes 50–300 ms now takes 30–120 seconds</li>
<li>Tokens stream in with multi-second gaps or time out entirely</li>
<li>The GPU sits idle waiting for weights that are stuck behind disk I/O</li>
</ul>
<p>vLLM, Ollama, llama.cpp, and TGI all load models at startup and expect those pages to stay resident indefinitely. None of them were designed to work around OS-level swap.</p>
<p><strong>The KV cache parallel:</strong> The attention KV cache that LLM inference engines maintain per-request — storing previously computed key-value pairs so the model does not re-process the entire context on every new token — is conceptually identical to the Linux page cache. Both exist to keep recently computed or accessed data in fast memory rather than recomputing or re-reading it. If you understand why page cache eviction is bad, you understand why KV cache eviction to disk destroys inference performance.</p>
<h3>Vector Databases</h3>
<p>Qdrant, Weaviate, Milvus, and Chroma load their HNSW or IVF indexes into RAM at startup. These indexes scale with corpus size — hundreds of gigabytes for production AI systems. Any swap activity touching index data sends similarity search latency from single-digit milliseconds to multi-second responses, eliminating the performance advantage of vector search entirely.</p>
<p><strong>On any server running AI inference or vector search: disk swap off, no exceptions.</strong></p>
<hr />
<h2>Containers and Kubernetes: The Right Defaults</h2>
<p>Kubernetes disables swap on nodes by default. This is intentional.</p>
<p>When a container exceeds its memory limit, the OOM killer terminates it — fast, clean, and immediately restartable by Kubernetes. This is predictable. Resource guarantees work as specified.</p>
<p>Swap breaks this model: a container that is swap-thrashing does not OOM-kill. It degrades — and it degrades the entire node, affecting all pods across all workloads, in a way that violates the isolation guarantees resource limits are supposed to provide.</p>
<p>Kubernetes 1.28 introduced alpha <code>NodeSwap</code> support with <code>LimitedSwap</code> mode — allowing swap only for memory exceeding a container's <em>request</em> (not its <em>limit</em>). Even this carefully constrained form is still alpha and not recommended for production nodes running latency-sensitive workloads.</p>
<p><strong>The container ecosystem's default position: swap off on production nodes.</strong> Not because swap is universally evil, but because its failure mode is incompatible with the predictability that container orchestration depends on.</p>
<hr />
<h2>What To Do</h2>
<h3>1. Understand Your Actual Memory Footprint First</h3>
<pre><code class="language-bash"># The authoritative number: available memory for new processes
free -m

# Per-process memory sorted by RSS
ps aux --sort=-%mem | head -20

# Shared vs private memory per process (more accurate than ps)
smem -s rss -r | head -20

# Real-time view
htop    # Press M to sort by memory
btop    # Modern alternative, better visualization
</code></pre>
<p>If <code>available</code> is above 10–15% of <code>total</code>, your server is healthy regardless of what <code>used</code> shows.</p>
<h3>2. Disable Disk Swap on Production Servers</h3>
<pre><code class="language-bash"># Check what swap is configured
swapon --show

# Disable immediately
swapoff -a

# Verify
free -m   # Swap line should show: 0  0  0

# Make permanent: edit /etc/fstab and comment out the swap line
# UUID=xxxx-xxxx   none   swap   sw   0   0
# becomes:
# #UUID=xxxx-xxxx  none   swap   sw   0   0
</code></pre>
<p>Do this only after confirming <code>available</code> memory is sufficient. If applications genuinely consume close to all physical RAM, disabling swap causes OOM kills — which is still a cleaner failure mode than swap thrashing, but requires either reducing application memory or adding RAM.</p>
<h3>3. Replace Disk Swap with zram If You Need a Fallback</h3>
<pre><code class="language-bash"># Ubuntu 22.04+ (zram-tools package)
apt install zram-tools

# Check it is configured
swapon --show
# Should show /dev/zram0 with partition type zram

# Manual configuration for other distros
modprobe zram
echo lz4 &gt; /sys/block/zram0/comp_algorithm
echo 8G &gt; /sys/block/zram0/disksize
mkswap /dev/zram0
swapon -p 100 /dev/zram0
</code></pre>
<h3>4. Tune vm.swappiness</h3>
<pre><code class="language-bash"># Minimize kernel's eagerness to swap (0 = last resort before OOM kill)
sysctl -w vm.swappiness=0

# Persist across reboots
echo "vm.swappiness=0" | tee /etc/sysctl.d/99-production.conf
sysctl -p /etc/sysctl.d/99-production.conf
</code></pre>
<p>For zram-only setups where you still want some swap pressure relief, <code>vm.swappiness=10</code> or <code>vm.swappiness=20</code> is a reasonable compromise — enough to let zram handle cold pages, not enough to start thrashing.</p>
<h3>5. Size RAM Correctly for Your Workload</h3>
<table>
<thead>
<tr>
<th>Workload</th>
<th>Sizing Rule</th>
</tr>
</thead>
<tbody><tr>
<td>MySQL/MariaDB</td>
<td><code>innodb_buffer_pool_size</code> = 60–70% of RAM on a dedicated DB server</td>
</tr>
<tr>
<td>PostgreSQL</td>
<td><code>shared_buffers</code> = 25% RAM; <code>effective_cache_size</code> = 75% RAM</td>
</tr>
<tr>
<td>Redis</td>
<td><code>maxmemory</code> explicit; total RAM = maxmemory + OS + 20% headroom</td>
</tr>
<tr>
<td>LLM inference (e.g., 70B Q4)</td>
<td>~40 GB model + 8–16 GB KV cache headroom per request batch</td>
</tr>
<tr>
<td>Vector DB (Qdrant, Weaviate)</td>
<td>Full index size + 30% headroom; measure RSS under load</td>
</tr>
<tr>
<td>Node.js / Python workers</td>
<td>Profile RSS per worker under load × max worker count</td>
</tr>
</tbody></table>
<h3>6. Monitor the Metrics That Matter</h3>
<pre><code class="language-bash"># Real-time swap activity
vmstat 2
# si = pages swapped IN/s (reading from swap)
# so = pages swapped OUT/s (writing to swap)
# Any sustained non-zero = active problem

# Memory pressure events
cat /proc/meminfo | grep -E "MemAvailable|SwapFree|SwapCached"
</code></pre>
<p><strong>Monitoring alert thresholds (Prometheus node_exporter metrics):</strong></p>
<table>
<thead>
<tr>
<th>Metric</th>
<th>Warning</th>
<th>Critical</th>
</tr>
</thead>
<tbody><tr>
<td><code>node_memory_MemAvailable_bytes</code></td>
<td>&lt; 15% of total</td>
<td>&lt; 5% of total</td>
</tr>
<tr>
<td><code>node_memory_SwapUsed_bytes</code></td>
<td>&gt; 0 on inference/DB</td>
<td>&gt; 512 MB anywhere</td>
</tr>
<tr>
<td><code>node_vmstat_pswpin</code></td>
<td>&gt; 0 sustained</td>
<td>&gt; 100/s</td>
</tr>
<tr>
<td><code>node_vmstat_pswpout</code></td>
<td>&gt; 0 sustained</td>
<td>&gt; 100/s</td>
</tr>
</tbody></table>
<hr />
<h2>Quick Reference</h2>
<pre><code class="language-plaintext">               total        used        free      shared  buff/cache   available
Mem:           15727        3291         121           0       12315       12187
Swap:           3071           0        3071
</code></pre>
<table>
<thead>
<tr>
<th>Question</th>
<th>Where to Look</th>
<th>Healthy Value</th>
</tr>
</thead>
<tbody><tr>
<td>Is my server running out of memory?</td>
<td><code>available</code> column</td>
<td>&gt; 10% of <code>total</code></td>
</tr>
<tr>
<td>How much do apps actually consume?</td>
<td><code>used</code> (modern <code>free</code>)</td>
<td>Workload-dependent</td>
</tr>
<tr>
<td>Is the kernel caching efficiently?</td>
<td><code>buff/cache</code></td>
<td>Higher is better</td>
</tr>
<tr>
<td>Is disk swap being hit?</td>
<td><code>Swap: used</code></td>
<td>0 on prod</td>
</tr>
<tr>
<td>Is swap causing harm right now?</td>
<td><code>vmstat 2</code> → <code>si</code>/<code>so</code></td>
<td>0</td>
</tr>
</tbody></table>
<hr />
<h2>Updated Myth vs Reality (2026 Edition)</h2>
<table>
<thead>
<tr>
<th>Old Assumption</th>
<th>2026 Reality</th>
</tr>
</thead>
<tbody><tr>
<td>"15 GB used means the server is overloaded"</td>
<td>12 GB of that is reclaimable cache. <code>available</code> is 12 GB. Server is fine.</td>
</tr>
<tr>
<td>"Disk swap is a safety net"</td>
<td>Disk swap is a 1,000x latency degradation. It extends incidents, not prevents them.</td>
</tr>
<tr>
<td>"Swap is always off — no exceptions"</td>
<td>Disk swap: off. zram: a legitimate modern alternative for memory pressure relief. AI training frameworks: intentional NVMe offloading is different from OS swap.</td>
</tr>
<tr>
<td>"NVMe is fast enough to make swap tolerable"</td>
<td>NVMe Gen5 is 1,000x slower than DDR5 for random reads. The gap has not closed.</td>
</tr>
<tr>
<td>"AI servers need more RAM so swap helps"</td>
<td>AI inference requires model weights fully resident in RAM. Any swapping of model pages makes inference functionally unusable.</td>
</tr>
<tr>
<td>"Kubernetes handles swap carefully now"</td>
<td>Kubernetes 1.28 added alpha swap support with tight constraints. Default is still off. Not recommended for latency-sensitive production workloads.</td>
</tr>
<tr>
<td>"Swap is the same as it was in 2010"</td>
<td>zram (RAM-compressed swap) has changed the low-end tradeoff. Disk swap remains as harmful as ever.</td>
</tr>
</tbody></table>
<hr />
<h2>The Closing Point</h2>
<p>Linux memory management is not broken. The kernel's aggressive use of every available byte for caching is one of the reasons Linux dominates production infrastructure globally — including the servers running the AI models you interact with daily.</p>
<p>The page cache and the KV cache in LLM inference follow the same principle: keep hot, recently accessed data in fast memory so you never pay the cost of recomputing or re-reading it. When you understand one, you understand the other.</p>
<p>For disk swap: the economics that justified it in the 1990s — RAM was scarce and expensive — are gone. RAM is cheap, abundant, and on the servers running modern AI workloads, absolutely non-negotiable. Disk swap on an LLM inference server is not a safety net. It is a guarantee that your server will appear operational while being completely unusable.</p>
<p>For zram: it is a real improvement over disk swap and a valid choice for development machines, constrained VMs, and container nodes that occasionally see memory pressure. It is not a substitute for provisioning enough RAM for your workload.</p>
<p>The <code>available</code> column in <code>free -m</code> tells you what is actually happening. Everything else is the kernel working as designed.</p>
<hr />
<p><em>This article draws from real production experience managing Linux infrastructure for high-traffic applications, updated with current AI infrastructure operational patterns.</em></p>
<hr />
<p><strong>Tags:</strong> <code>linux</code> <code>sysadmin</code> <code>devops</code> <code>performance</code> <code>memory-management</code> <code>ai</code> <code>llm</code> <code>infrastructure</code> <code>kubernetes</code> <code>backend</code> <code>mlops</code></p>
<p><strong>Cover image suggestion:</strong> A terminal split-view — left showing <code>free -m</code> with the <code>available</code> column highlighted, right showing <code>ollama</code> or <code>vllm</code> loading a model — dark background, clean monospace font.</p>
]]></content:encoded></item><item><title><![CDATA[When a Small Error Brings Down an AI Training Workload: Lessons from Lustre]]></title><description><![CDATA[How network anomalies, kernel dependencies, and storage integration complexity can turn a high-performance system into an operational challenge. A network…]]></description><link>https://beyondthestacks.hashnode.dev/when-a-small-error-brings-down-an-ai-training-workload-lessons-from-lustre</link><guid isPermaLink="true">https://beyondthestacks.hashnode.dev/when-a-small-error-brings-down-an-ai-training-workload-lessons-from-lustre</guid><category><![CDATA[lustre]]></category><category><![CDATA[network]]></category><category><![CDATA[ai training]]></category><dc:creator><![CDATA[Pawan Kumar Singh]]></dc:creator><pubDate>Fri, 23 Oct 2026 17:01:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6adb877df6f60b8802f04339/9f162b9a-fbdf-4ce2-bce3-b8de45b0e32e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>How network anomalies, kernel dependencies, and storage integration complexity can turn a high-performance system into an operational challenge.</em></p>
<p>A network interface can be up. Servers can respond to ping. Storage drives can have plenty of available bandwidth.</p>
<p><strong>Yet an AI training workload can come to a complete standstill.</strong></p>
<p>We experienced this firsthand while deploying and operating Lustre, the open-source parallel file system widely used in HPC and AI infrastructure.</p>
<p>What began as a high-performance storage deployment eventually became an extended exercise in troubleshooting network anomalies, kernel-driver compatibility, metadata recovery, and filesystem availability.</p>
<p>The most difficult part wasn't just identifying the technical issues. It was dealing with repeated interruptions to customer workloads and the growing loss of confidence in the storage platform.</p>
<p>Eventually, we had to reconsider our approach and move toward an alternative storage solution.</p>
<p>Here are some of the lessons that experience taught me.</p>
<hr />
<h2>1. When Everything Looked Healthy, but Training Kept Failing</h2>
<p>Our objective was to deliver high-performance shared storage for GPU-intensive AI training workloads.</p>
<p>The environment had enterprise NVMe storage, high-speed networking, dedicated object storage servers, and three Lustre metadata server nodes.</p>
<p>On paper, the infrastructure had significant performance headroom.</p>
<p>But once production workloads started running, we began experiencing serious instability:</p>
<ul>
<li>Compute nodes with Lustre mounts would stop responding to filesystem operations.</li>
<li>AI training jobs would hang or fail.</li>
<li>Metadata requests would time out, and clients would lose connections to metadata targets.</li>
<li>Our engineering team repeatedly had to intervene on metadata services to restore normal operations.</li>
</ul>
<p>What made this particularly frustrating was that storage drives were utilizing less than 10% of their available bandwidth during some of the observed failures.</p>
<p>The bottleneck wasn't an obvious shortage of raw disk throughput.</p>
<p><strong>Something deeper in the infrastructure stack was preventing the distributed filesystem from operating reliably.</strong></p>
<h2>2. The Small Network Errors That Raised Big Questions</h2>
<p>During troubleshooting, we began examining the network interfaces more closely.</p>
<p>One observation revealed approximately <strong>2,500 Forward Error Correction (FEC) symbol errors per second</strong>.</p>
<p>Across different storage nodes, some interfaces had accumulated hundreds of millions or billions of symbol errors, along with smaller numbers of uncorrectable FEC blocks.</p>
<p>At the same time, Lustre reported RPC timeouts and lost connections to metadata targets.</p>
<p>One recurring message looked like this:</p>
<pre><code class="language-text">Lustre: Request sent has timed out for slow reply

Lustre: Connection to MDT0001 was lost;
in-progress operations using this service
will wait for recovery to complete.
</code></pre>
<p>These messages indicated that Lustre clients were experiencing metadata request timeouts and losing connectivity to a metadata target. Affected filesystem operations could remain blocked while the target recovered.<br /><br />Our investigation also found that Lustre's own networking utility, <code>lctl ping</code>, failed from multiple clients with input/output errors.</p>
<p><code>lctl ping &lt;MDS_NID&gt; failed to ping &lt;MDS_NID&gt;: Input/output error</code></p>
<p>These observations made the network stack a major area of concern.</p>
<p>However, an important distinction is necessary.</p>
<p>FEC is designed to correct transmission errors. Large corrected-error counters alone don't prove packet loss or application failure. Uncorrectable errors, error-rate trends, and correlation with transport failures are more meaningful indicators.</p>
<p>We had evidence of network anomalies and Lustre communication failures, but establishing a single definitive cause for every incident would have required further investigation.</p>
<blockquote>
<p><strong>The lesson:</strong> An error that appears insignificant when measured at one infrastructure layer can have a much larger operational impact when it affects a distributed application.</p>
</blockquote>
<h3>Recovery Was Successful. The Customer Experience Wasn't.</h3>
<p>In one incident, Lustre reported the following metadata target recovery statistics:</p>
<table>
<thead>
<tr>
<th>Recovery metric</th>
<th>Observed value</th>
</tr>
</thead>
<tbody><tr>
<td>Connected clients</td>
<td>317</td>
</tr>
<tr>
<td>Completed recovery</td>
<td>317/317</td>
</tr>
<tr>
<td>Recovery duration</td>
<td>344 seconds</td>
</tr>
<tr>
<td>Replayed requests</td>
<td>9</td>
</tr>
</tbody></table>
<p>The recovery completed successfully.</p>
<p>But nearly six minutes of metadata recovery is significant when applications are waiting on filesystem operations.</p>
<p>With AI training workloads running across GPU nodes, intermittent storage stalls and repeated recovery events can translate into lost execution time, failed jobs, and operational disruption.</p>
<p>This highlighted a distinction that became central to our experience:</p>
<blockquote>
<p><strong>A storage system can recover successfully at the infrastructure level and still fail its customers at the application level.</strong></p>
</blockquote>
<p>Having multiple metadata servers also doesn't automatically guarantee uninterrupted operations. Lustre's recovery mechanisms are designed to preserve consistency and restore service, but clients may still experience delays while affected metadata targets recover.</p>
<hr />
<h2>3. The Kernel Compatibility Challenge We Encountered Earlier</h2>
<p>Interestingly, the difficulties began before production.</p>
<p>During the initial deployment, we encountered compatibility issues between our network interface drivers and the Linux kernel environment required by the Lustre servers.</p>
<p>Unlike applications implemented entirely in user space, Lustre relies heavily on Linux kernel modules.</p>
<p>Traditional Lustre server deployments, particularly those using the ldiskfs backend, may use patched or specially qualified Linux kernel versions. ZFS-based Lustre server configurations and Lustre clients have different kernel requirements.</p>
<p>Our storage environment required a kernel and driver combination that wasn't directly compatible with the NIC drivers available to us.</p>
<p>Under tight delivery timelines, we compiled and adapted the drivers to proceed.</p>
<p>This allowed the deployment to move forward, but it exposed a broader architectural concern.</p>
<h3>Compatibility Is a Property of the Complete Stack</h3>
<p>Consider the dependencies involved:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6adb877df6f60b8802f04339/da42a51f-3f9d-4b0a-9b0b-62642b67ac5f.png" alt="" style="display:block;margin:0 auto" />

<p>Each layer has its own versions, compatibility requirements, and failure characteristics.</p>
<p>A driver upgrade that works on a standard Linux server may not be straightforward on a storage server running a specific kernel configuration.</p>
<p>Similarly, a network interface that works reliably for ordinary virtualization traffic hasn't necessarily been validated for sustained, latency-sensitive distributed storage operations.</p>
<p>In our case, the same class of hardware had passed preliminary tests in a virtualization environment.</p>
<p>But those tests didn't reproduce the actual Lustre workload.</p>
<p>We also observed RPC-level errors involving <code>MDS_BATCH</code> operations, illustrating another possible compatibility concern between Lustre client and server implementations.</p>
<p>Similar messages have been documented in upstream Lustre compatibility issues. That doesn't establish that we encountered the same software defect, but it demonstrates why version qualification matters.</p>
<p><strong>The lesson was clear: hardware compatibility isn't just about whether a component works. It's about whether the entire stack works together under the intended production workload.</strong></p>
<h2>4. The Hidden Cost of Open-Source Infrastructure</h2>
<p>I've spent much of my career working with open-source infrastructure, and I remain a strong advocate for it.</p>
<p>Linux, Kubernetes, Ceph, Lustre, and many other open-source technologies have demonstrated remarkable capabilities at scale.</p>
<p>But there's an important difference between having access to powerful technology and operating it as a reliable customer-facing service.</p>
<p>Open source provides flexibility, transparency, and control.</p>
<p>What it doesn't automatically provide is a fully validated combination of hardware, firmware, drivers, kernel versions, networking components, and production workloads.</p>
<p>Documentation and community knowledge exist, but troubleshooting a particular combination of modern hardware and software can still require significant engineering effort.</p>
<p>When a failure crosses multiple layers, the investigation becomes particularly challenging.</p>
<p>The network may pass basic connectivity tests. Hardware diagnostics may appear normal. Individual storage services may eventually recover.</p>
<p>Yet the overall system can remain unreliable.</p>
<p>Someone still has to own the complete integration problem.</p>
<blockquote>
<p><strong>The hidden cost of open-source infrastructure is not necessarily licensing. It's the engineering effort required to validate, integrate, troubleshoot, upgrade, and maintain the entire solution.</strong></p>
</blockquote>
<p>For organizations with strong HPC expertise and established hardware qualification processes, managing this complexity may be perfectly reasonable.</p>
<p>For customer-facing cloud infrastructure, however, that complexity must be considered alongside reliability expectations and operating costs.</p>
<hr />
<h2>5. Are User-Space Storage Architectures Changing the Equation?</h2>
<p>This experience also influenced how I evaluate newer enterprise high-performance storage platforms.</p>
<p>Lustre is a kernel-integrated distributed filesystem. Several newer software-defined storage systems take a different approach by moving substantial portions of their performance-critical data planes into user space.</p>
<p>Technologies such as DPDK and SPDK allow storage software to optimize packet processing and device access through techniques such as polling, batching, and reduced context switching.</p>
<p>These approaches can provide greater control over I/O processing and reduce certain kernel dependencies.</p>
<p>However, <strong>user-space execution doesn't eliminate hardware compatibility challenges.</strong></p>
<p>Network interfaces, firmware, drivers, operating systems, and storage clients still need appropriate qualification.</p>
<p>Some enterprise storage platforms also retain kernel-based client components even when their server-side data plane primarily operates in user space.</p>
<p>The more meaningful distinction is often the maturity of the overall product and its integration ecosystem.</p>
<table>
<thead>
<tr>
<th>What matters</th>
<th>Why it matters</th>
</tr>
</thead>
<tbody><tr>
<td>Validated hardware configurations</td>
<td>Reduces unexpected integration risks</td>
</tr>
<tr>
<td>Software and driver compatibility</td>
<td>Makes upgrades and lifecycle management more predictable</td>
</tr>
<tr>
<td>Integrated observability</td>
<td>Helps identify failures across multiple infrastructure layers</td>
</tr>
<tr>
<td>Recovery behavior</td>
<td>Determines the actual effect of failures on applications</td>
</tr>
<tr>
<td>End-to-end support ownership</td>
<td>Reduces responsibility fragmentation during incidents</td>
</tr>
</tbody></table>
<p>Enterprise support alone is not a guarantee of reliability, and Lustre itself is available through commercially supported implementations.</p>
<p>But validated configurations, integrated tooling, and a clear support model can materially reduce the burden on infrastructure teams.</p>
<p>For me, this changed the way I evaluate storage platforms.</p>
<p><strong>Peak throughput is only one part of the equation. Operational reliability and integration complexity deserve equal attention.</strong></p>
<h2>6. The Customer Experience Is the Ultimate Benchmark</h2>
<p>Perhaps the hardest lesson from this experience wasn't technical.</p>
<p>As infrastructure engineers, we naturally want to isolate the failing component. Was the issue in the hardware, driver, kernel, network transport, metadata service, or an unexpected interaction between them?</p>
<p>These distinctions are essential for troubleshooting. But customers experience the infrastructure as a single service.</p>
<p><strong>They don't care which component failed. They care that their AI training workloads stopped working.</strong></p>
<p>Every interruption meant stalled training jobs, underutilized GPU resources, delayed work, and growing frustration.</p>
<p>Despite significant engineering effort, repeated filesystem disruptions gradually affected customer confidence. Eventually, we made the difficult decision to move toward an alternative storage solution.</p>
<p>That doesn't mean Lustre is fundamentally unsuitable for high-performance computing. It remains a proven technology used in some of the world's most demanding HPC environments.</p>
<p>But it reinforced an important lesson:</p>
<blockquote>
<p><strong>A technically capable solution isn't necessarily the right operational fit for every production environment.</strong></p>
</blockquote>
<p>Sometimes, maintaining customer trust requires reconsidering the architecture rather than continuing to troubleshoot an increasingly complex integration.</p>
<hr />
<h2>What I Would Do Differently</h2>
<p>Looking back, five lessons stand out.</p>
<p><strong>1. Validate hardware using real workloads.</strong></p>
<p>Successful ping tests, basic throughput benchmarks, and generic virtualization testing are not sufficient qualification for distributed storage.</p>
<p><strong>2. Treat kernel, drivers, firmware, and storage software as one compatibility unit.</strong></p>
<p>The complete stack must be tested and maintained as a validated combination.</p>
<p><strong>3. Monitor reliability at the application level.</strong></p>
<p>A healthy interface or a successfully recovered metadata target doesn't necessarily mean applications were unaffected.</p>
<p><strong>4. Evaluate operational maturity alongside performance.</strong></p>
<p>Observability, recovery behavior, upgrade complexity, documentation, and support ownership matter as much as benchmark numbers.</p>
<p><strong>5. Know when to reconsider the architecture.</strong></p>
<p>Engineering persistence is important, but so are customer confidence, service reliability, and long-term operational sustainability.</p>
<h2>Final Thoughts</h2>
<p>Our experience reinforced a principle that applies to nearly every distributed infrastructure platform:</p>
<blockquote>
<p><strong>Reliability is not a property of an individual component. It's a property of the entire system.</strong></p>
</blockquote>
<p>A healthy SSD doesn't guarantee a healthy filesystem.</p>
<p>A reachable server doesn't guarantee reliable distributed communication.</p>
<p>Multiple metadata servers don't guarantee uninterrupted application access.</p>
<p>And a powerful open-source technology doesn't automatically guarantee seamless integration with every hardware and software combination.</p>
<p>As AI infrastructure evolves toward faster networks, denser NVMe storage, and more powerful GPU clusters, performance expectations will continue to increase.</p>
<p>But the most important question isn't simply how much throughput a system can deliver.</p>
<p>It's how consistently that system can support real customer workloads, under failures, upgrades, and everyday operational complexity.</p>
<p><strong>Sometimes, the biggest improvement isn't another round of tuning. It's recognizing when the architecture needs to change.</strong></p>
<hr />
<p><em>Written from personal experience designing, deploying, and operating high-performance infrastructure for AI workloads. Technical observations have been generalized and identifying information omitted.</em></p>
<h3>References and Further Reading</h3>
<ul>
<li><a href="https://www.lustre.org/getting-started-with-lustre/">Lustre: Getting Started</a></li>
<li><a href="https://wiki.lustre.org/Compiling_Lustre">Lustre Wiki: Compiling Lustre</a></li>
<li><a href="https://wiki.lustre.org/Lustre_Recovery_Overview">Lustre Recovery Overview</a></li>
<li><a href="https://www.dpdk.org/">DPDK Project</a></li>
<li><a href="https://spdk.io/">Storage Performance Development Kit (SPDK)</a></li>
</ul>
]]></content:encoded></item></channel></rss>