Optimization and Troubleshooting
A complete guide to optimizing MicroVM performance and solving the problems you will commonly encounter.
Boot Time Optimization
Disable Legacy Devices
# Fastest boot time (requires KVM + TSC_DEADLINE)
qemu-system-x86_64 \
-M microvm,x-option-roms=off,pit=off,pic=off,rtc=off,isa-serial=off \
-enable-kvm -cpu host -m 256m -smp 2 \
-kernel vmlinuz \
-append "console=hvc0 root=/dev/vda rw quiet" \
-nographic \
-chardev stdio,id=virtiocon0 \
-device virtio-serial-device \
-device virtconsole,chardev=virtiocon0 \
-drive id=rootfs,file=rootfs.img,format=raw,if=none,cache=none \
-device virtio-blk-device,drive=rootfs \
-netdev tap,id=net0,script=no,downscript=no \
-device virtio-net-device,netdev=net0
Kernel Optimization
# Add to the kernel cmdline
quiet loglevel=0 systemd.show_status=0
# Disable initramfs (if all modules are built-in)
# Build the kernel with built-in modules, not loadable modules
Filesystem Optimization
# Mount options for the rootfs
mount -o noatime,nodiratime,discard /dev/vda1 /
# Disable the journal (for a read-only rootfs)
tune2fs -O ^has_journal /dev/vda1
# or use ext2 (no journal)
mkfs.ext2 rootfs.img
Memory Optimization
QEMU Memory Tuning
# Use hugepages (Linux host)
echo 512 > /proc/sys/vm/nr_hugepages
qemu-system-x86_64 \
-M microvm -enable-kvm -cpu host \
-m 256m \
-mem-path /dev/hugepages \
...
# Disable swap in the guest
swapoff -a
Guest Memory Optimization
# Disable unused services
systemctl disable --now bluetooth
systemctl disable --now cups
systemctl disable --now avahi-daemon
# Clear page cache
echo 3 > /proc/sys/vm/drop_caches
# Optimize kernel memory
echo "vm.swappiness=10" >> /etc/sysctl.conf
echo "vm.dirty_ratio=60" >> /etc/sysctl.conf
echo "vm.dirty_background_ratio=2" >> /etc/sysctl.conf
sysctl -p
Disk I/O Optimization
QEMU Drive Options
# Optimal I/O settings
-drive id=rootfs,file=rootfs.img,format=raw,if=none,\
cache=none,aio=linux,discard=unmap,\
format=raw,serial=ROOTFS
# Virtio-blk with multi-queue
-device virtio-blk-device,drive=rootfs,num-queues=4
Guest I/O Optimization
# Use the right I/O scheduler
echo "none" > /sys/block/vda/queue/scheduler
# Optimize readahead
blockdev --setra 4096 /dev/vda
# Disable barriers (if the host has battery backup)
mount -o remount,nobarrier /
Network Optimization
QEMU Network Tuning
# Virtio-net with multi-queue
-device virtio-net-device,netdev=net0,mrg_rxbuf=on,indirect_desc=on
# TAP with multi-queue
-netdev tap,id=net0,ifname=tap0,script=no,downscript=no,queues=4
Guest Network Optimization
# TCP tuning
echo "net.core.rmem_max=16777216" >> /etc/sysctl.conf
echo "net.core.wmem_max=16777216" >> /etc/sysctl.conf
echo "net.ipv4.tcp_rmem=4096 87380 16777216" >> /etc/sysctl.conf
echo "net.ipv4.tcp_wmem=4096 65536 16777216" >> /etc/sysctl.conf
echo "net.core.netdev_max_backlog=5000" >> /etc/sysctl.conf
sysctl -p
Monitoring
Resource Monitoring
# CPU usage
top -bn1 | head -5
# Memory
free -h
# Disk I/O
iostat -x 1 5
# Network
iftop -i eth0
# or use dstat
dstat -cdnm 1
QEMU Monitoring
# QEMU monitor (Ctrl+A, C)
info status
info block
info network
info mem
# Stats
info status
info snapshots
Monitoring Script
#!/bin/bash
# Script: monitor-microvm.sh
echo "=== MicroVM Monitor ==="
echo "Time: $(date)"
echo ""
echo "--- CPU ---"
uptime
echo ""
echo "--- Memory ---"
free -h
echo ""
echo "--- Disk ---"
df -h /
echo ""
echo "--- Network ---"
ip -s link show eth0
echo ""
echo "--- Processes ---"
ps aux --sort=-%mem | head -10
echo ""
Troubleshooting
The VM Does Not Boot
# Check the kernel and rootfs
file vmlinuz
file rootfs.img
# Check the kernel cmdline
# Make sure root=/dev/vda is correct
# Check with the serial console
# Add earlyprintk=serial earlyprintk=ttyS0
No Network Connectivity
# Check the interface
ip link show
ip addr show
# Check the routing
ip route show
# Check DNS
cat /etc/resolv.conf
ping 8.8.8.8
# Check the QEMU network backend
# Make sure the netdev configuration is correct
High CPU Usage
# Check the processes using CPU
top -bn1 | head -20
# Check the QEMU process on the host
ps aux | grep qemu
# Disable unnecessary services
systemctl list-unit-files --type=service --state=enabled
systemctl disable <service>
Disk Full
# Check disk usage
df -h
# Find large files
du -sh /* | sort -rh | head -10
# Clean the package cache
apt clean # Debian
apk cache clean # Alpine
# Remove old logs
journalctl --vacuum-time=7d
find /var/log -name "*.gz" -delete
OOM (Out of Memory)
# Check the OOM logs
dmesg | grep -i "out of memory"
# Check memory usage
ps aux --sort=-%mem | head -10
# Reduce memory usage
# - Reduce application buffers
# - Disable swap (or add swap)
# - Use a lighter version of the application
Crash / Panic
# Enable kernel panic handler
echo 1 > /proc/sys/kernel/panic
# Or in the kernel cmdline
panic=1
# QEMU will exit on kernel panic with:
-no-reboot
Backup Strategy
Full Image Backup
# Backup full image
dd if=/dev/vda bs=4M | gzip > backup-$(date +%F).img.gz
# Restore
gunzip -c backup-2024-01-01.img.gz | dd of=/dev/vda bs=4M
Incremental Backup
# Using a QCOW2 backing file
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 overlay.qcow2
# Back up only the changes
qemu-img commit overlay.qcow2
Snapshot Management
# Create a snapshot
qemu-img snapshot -c snap1 rootfs.img
# List snapshots
qemu-img snapshot -l rootfs.img
# Restore snapshot
qemu-img snapshot -a snap1 rootfs.img
# Delete snapshot
qemu-img snapshot -d snap1 rootfs.img
Security Hardening
QEMU Security
# Run as non-root
# Requires capabilities for KVM
setcap cap_net_admin+ep /usr/bin/qemu-system-x86_64
# Disable QEMU monitor
# Add -monitor /dev/null
# Disable USB
# Add -device usb-none
Guest Security
# Disable root login via SSH
PermitRootLogin no
# Enable firewall
apt install ufw
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw enable
# Disable unused modules
blacklist nouveau
blacklist snd
blacklist pcspkr
Performance Benchmark
Boot Time Test
#!/bin/bash
# Script: benchmark-boot.sh
START=$(date +%s%N)
qemu-system-x86_64 \
-M microvm,pit=off,pic=off,rtc=off \
-enable-kvm -cpu host -m 256m -smp 2 \
-kernel vmlinuz \
-append "console=ttyS0 root=/dev/vda rw quiet reboot=t" \
-drive id=rootfs,file=rootfs.img,format=raw,if=none,cache=none \
-device virtio-blk-device,drive=rootfs \
-nographic -serial stdio \
-no-reboot 2>&1 | tail -1
END=$(date +%s%N)
DURATION=$(( (END - START) / 1000000 ))
echo "Boot time: ${DURATION}ms"
I/O Benchmark
# Install fio
apt install fio
# Sequential read
fio --name=seq-read --rw=read --bs=1M --size=100M --numjobs=1
# Random read/write
fio --name=rand-rw --rw=randrw --bs=4k --size=100M --numjobs=4
# IOPS test
fio --name=iops --rw=randread --bs=4k --size=100M --numjobs=4
Network Benchmark
# Bandwidth test
iperf3 -s # on the server
iperf3 -c 10.0.0.1 # on the client
# Latency test
ping -c 100 10.0.0.1
# HTTP benchmark
ab -n 10000 -c 100 http://localhost/
Best Practices
Production Checklist
- [ ] Use KVM for performance
- [ ] Disable legacy devices (PIT, PIC, RTC)
- [ ] Use virtio-mmio for all devices
- [ ] Set the memory exactly (do not over-allocate)
- [ ] Use cache=none for the disk
- [ ] Enable aio=linux for async I/O
- [ ] Setup monitoring (CPU, memory, disk, network)
- [ ] A backup strategy using snapshots
- [ ] Security hardening (firewall, SSH keys)
- [ ] Log rotation for disk space
Development Checklist
- [ ] Use user-mode networking for convenience
- [ ] Port forwarding for access from the host
- [ ] QCOW2 for development snapshots
- [ ] A shared folder with 9p (or virtio-fs)
- [ ] Debug with the serial console