How to fix I/O spikes and swap usage on a VPS during nightly backups without adding disk
By Kevin Marcondes · Published on · 8 min read
Are nightly backups causing I/O spikes and swap usage on your VPS and you don’t want (or can’t) increase disk size? Here’s a focused diagnosis and practical actions to reduce I/O contention, limit concurrency and tune the system — including ionice/nice, bwlimit, snapshots and kernel parameters — while keeping backups reliable.
Symptoms: how to tell it's I/O and swap contention
During the backup window the system becomes sluggish, the load average climbs and common processes hang waiting for disk. Free memory falls and swap usage increases. Usually backups involve compression, copying large files or snapshots competing with the database and production services.
If that matches your situation, the goal is to smooth peaks and spread reads/writes over time without increasing storage capacity.
Quick diagnosis (10 minutes) to locate the bottleneck
Run these measurements while the backup is running. Look for high I/O queues, processes with heavy I/O and memory pressure that leads to swapping.
If your provider’s disk has a burst limit, it may be exhausted and generating high latency.
# Utilização detalhada do disco (filas, espera, %util)
iostat -xy 5 3
# Pressão de memória e swap (cs, si/so)
vmstat 5 5; free -h; swapon --show
# Processos que mais fazem I/O (root requerido)
iotop -oPa
# Por processo: escrita/leitura por segundo
pidstat -d 5 3
# Histórico, se sysstat estiver habilitado
sar -b 1 10
Common causes on VPS during backups
Most incidents are caused by a combination of factors. Identifying the origin points to the right mitigation.
- Backup reading and compressing everything at once (tar/gzip, restic/borg with high parallelism).
- rsync without bandwidth limits and many threads scanning the FS, causing cache churn.
- COW snapshots (e.g. LVM) kept for hours while the base keeps writing — increases copy-on-write I/O.
- Heavy compression (gzip -9 / xz) causing more read/write and CPU/I/O contention.
- Concurrency with other nightly routines (updatedb, logrotate with compression, ETLs, VACUUMs).
- VPS disk hitting the provider's performance/burst limit, raising latencies.
- High swappiness pushing pages to swap during cache and compression spikes.
Immediate fixes for tonight (without adding disk)
The goal is to smooth peaks. Limit the backup job's I/O and CPU, reduce concurrency and improve read/write efficiency.
Apply changes gradually and monitor impact; prioritize fixes that give the biggest benefit with the lowest risk.
- Force low I/O/CPU priority on the backup with ionice (idle class) and nice (+15 or +19).
- Limit rsync/restic/borg throughput (e.g. --bwlimit) to avoid aggressive scans.
- Reduce concurrency: run one task at a time; avoid scanning and compressing multiple directories in parallel.
- Exclude caches, temporary files and recently rotated logs from the backup set.
- Use lighter, faster compression (zstd at moderate level) to reduce I/O per byte.
- Schedule logrotate, VACUUM/ETL and backups in separate windows to avoid overlap.
# Exemplos (ajuste caminhos e limites ao seu ambiente)
# rsync: limitar banda, priorizar CPU/I/O baixos
ionice -c3 nice -n 15 rsync -aHAX --delete \
--bwlimit=20m --info=progress2 --exclude-from=/etc/backup.excludes \
/dados/ user@backup:/repositorio/host1/
# restic: reduzir concorrência e I/O
IONICE="ionice -c3" NICE="nice -n 15" \
$IONICE $NICE restic backup /dados \
--limit-bandwidth 20Mi \
--compression max --pack-size 16Mi \
--one-file-system
Robust strategy: quick snapshot + controlled incremental upload
Separating state capture (snapshot) from upload reduces the host’s time under heavy I/O. Use a short-lived snapshot and then perform an incremental upload with throttling.
With LVM snapshots, keep the snapshot as short as possible to reduce copy-on-write. Then perform incremental upload (restic/borg) with I/O and bandwidth limits.
See a full LVM + Restic + timers walkthrough in "LVM snapshots + Restic to S3 (Debian)".
| Action | Expected effect | Risk/Note |
|---|---|---|
| Short snapshot (minutes) | Minimizes COW and host I/O | Requires consistency planning (e.g. DB flush) |
| Incremental upload with limits | Spreads I/O over time | Backups take longer (wider window) |
| Moderate compression (zstd) | Less CPU per byte and steadier I/O | Slightly larger files than gzip -9 |
| Well-defined exclusions | Fewer files scanned and written | Be careful not to exclude required data |
| One heavy task at a time | Avoids internal competition | Orchestrate with timers/dependencies |
Kernel and filesystem tweaks to reduce swap and writeback
Use these with caution and test before applying in production. The goal is to avoid pushing memory to swap during transient peaks and to reduce aggressive flushes.
Set swappiness to a low/moderate value, adjust dirty ratios and consider noatime to reduce metadata writes.
- vm.swappiness between 10 and 30 usually prevents premature swapping on servers.
- vm.dirty_background_ratio and vm.dirty_ratio control when the kernel starts flushing dirty pages.
- noatime/relatime reduce metadata write traffic.
- Tuning readahead can avoid unnecessary reads in short sequential patterns.
# Teste temporariamente (até reboot)
sudo sysctl vm.swappiness=20
sudo sysctl vm.dirty_background_ratio=5
sudo sysctl vm.dirty_ratio=20
# Persistir (edite com cuidado)
echo -e "vm.swappiness=20\nvm.dirty_background_ratio=5\nvm.dirty_ratio=20" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Scheduling, orchestration and continuous visibility
Avoid overlapping nightly jobs. Use timers with randomness and dependencies. Measure continuously to confirm mitigations are effective.
Turn crons into systemd timers, use RandomizedDelaySec to spread load and WantedBy/After to order tasks. Practical guide: "Migrate cron to systemd timers."
Monitor disk/CPU/memory with Prometheus + Grafana; see the guide "Prometheus & Grafana with Docker Compose".
- Separate windows: logrotate/compression, VACUUM/ETL and backups.
- Concurrency limit per host: at most one heavy job.
- Alerts for disk latency, swap usage and I/O queue depth.
- Review decisions after 1–2 backup cycles with real data.
When the issue is the VPS disk (provider limits)
Some volumes have performance that depends on burst/IOPS provisioning. If the burst is exhausted, latency rises even for light workloads. Smoothing I/O helps, but you must understand the provider’s ceiling.
See cloud disk performance overviews: Amazon EBS and Google Persistent Disk performance.
- If the disk’s stable burst is low, increase the window (–bwlimit) to spread writes.
- Avoid multiple simultaneous I/O-heavy jobs; serialize backups and compressions.
- Consider separating the data disk and a temporary backup disk when possible.
Frequently asked questions
Does increased swap always mean lack of RAM?
Not necessarily. During cache and compression spikes the kernel may move less-used pages to swap even with available RAM, depending on swappiness and writeback pressure. Lowering swappiness, reducing concurrency and limiting I/O usually stabilizes the system without adding memory.
Will ionice and nice fix it alone?
They help prioritize critical services under contention, but they don't reduce the total data processed. Combine them with bandwidth limits (--bwlimit), lower concurrency, exclusions and lighter compression to smooth the backup I/O profile.
Is it safe to keep an LVM snapshot for hours?
The longer a snapshot exists, the more COW blocks are written, increasing I/O and the risk of filling the snapshot area. Prefer short snapshots followed by incremental upload. Monitor snapshot usage and size the COW area with headroom.
Should I disable swap to avoid slowness?
Disabling swap can cause OOM kills under memory spikes. It's better to reduce swappiness, limit concurrency and smooth I/O. A small, rarely used swap is acceptable. If swap is used constantly, investigate memory consumption and tune services.
Which compression should I use for nightly backups?
zstd at a moderate level usually provides good ratios with less CPU and I/O per byte compared to high-level gzip. Tune level and concurrency to keep disk latency low during the backup window.
Does local rsync need --bwlimit?
Even local rsync can aggressively scan metadata and heat the page cache, impacting other processes. Using --bwlimit plus low priority (ionice/nice) helps spread the work and reduce disk contention.
Want to stabilize your nightly backups without blowing up I/O?
Tell me about your setup. I can review your backup job, apply I/O limits, tune swappiness and orchestrate timers while keeping your current disk costs.
Discuss your caseSee also
- Intermittent 502 Bad Gateway in Docker Compose with Nginx & PHP‑FPM: how to diagnose and fix timeouts and connection overloads
- How to diagnose and capture packets for intermittent network issues between Docker containers on Debian
- How to detect and fix duplicate SKU inconsistencies between WooCommerce and your ERP without losing orders
- How to reduce build time and avoid duplicate artifacts in CI for large PHP monoliths