Un servidor bare metal ejecuta el sistema operativo directamente sobre el hardware físico, mientras que una máquina virtual (VM) comparte ese hardware con otras a través de un hipervisor como KVM. La diferencia de rendimiento existe, pero es mucho menor de lo que se suele pensar en CPU y bastante mayor en latencia de disco y red, y depende sobre todo de cómo esté configurado el hipervisor. En esta guía verás de dónde sale la sobrecarga de la virtualización, cómo medirla tú mismo en Ubuntu 24.04 con herramientas estándar y qué criterios usar para elegir entre un servidor dedicado y un VPS.
Resumen rápido
| Aspecto | Bare metal | VM con KVM (virtio) |
|---|---|---|
| CPU (cálculo puro) | 100 % del hardware | Muy cercano al nativo con cpu host, sobrecarga típica de pocos puntos porcentuales |
| Memoria | Acceso directo | Traducción de direcciones en dos niveles, algo más de coste en fallos de TLB |
| Disco (IOPS aleatorias, latencia) | Latencia mínima del dispositivo | Añade el camino virtio y el almacenamiento del host, se nota más en E/S pequeña y aleatoria |
| Red | Tasa de línea de la NIC | Buen caudal con virtio y vhost-net, algo más de latencia y de CPU por paquete |
| Previsibilidad | Total, no hay vecinos | Depende del sobreaprovisionamiento del host (steal time) |
| Aprovisionamiento | Minutos u horas | Segundos o pocos minutos |
| Escalado vertical | Cambio de hardware | Cambio de plan, a veces en caliente |
| Snapshots y migración | Requiere herramientas propias | Integrados en el hipervisor |
| Acceso a hardware (GPU, NVMe, IPMI) | Completo | Solo mediante passthrough, si el proveedor lo ofrece |
Las cifras exactas varían con el hardware, la versión del kernel, el tipo de almacenamiento y la carga del host. Por eso, más que fiarte de tablas genéricas, conviene que midas tu propia carga en ambos entornos, como se explica más abajo.
De dónde sale la sobrecarga de la virtualización
Entender el origen de la sobrecarga ayuda a saber qué cargas la van a notar y cuáles no.
- CPU: gracias a las extensiones de virtualización (Intel VT-x, AMD-V), el código del invitado se ejecuta de forma nativa. El coste aparece en las salidas al hipervisor (VM exits) provocadas por interrupciones, E/S o ciertas instrucciones privilegiadas. Un programa que solo calcula casi no las provoca.
- Memoria: con EPT (Intel) o NPT (AMD) cada acceso a memoria que falla en la TLB necesita recorrer dos tablas de páginas, la del invitado y la del host. Las cargas con mucho acceso aleatorio a grandes volúmenes de memoria (bases de datos en memoria, cachés) son las que más lo notan. Las huge pages reducen este efecto.
- Disco: cada operación pasa por el controlador virtio del invitado, el proceso QEMU o vhost del host y el almacenamiento que haya debajo (disco local, LVM, Ceph, NFS). En operaciones de 4 KB con mucha concurrencia, esa latencia añadida pesa más que en lecturas secuenciales grandes.
- Red: con virtio-net y vhost-net el caudal es alto, pero cada paquete atraviesa un puente o un switch virtual en el host. Se nota en cargas de muchos paquetes pequeños y en la latencia de cola (p99).
- Vecinos ruidosos: si el host tiene más vCPU asignadas que núcleos físicos, tu VM puede tener que esperar para ejecutarse. Ese tiempo se ve dentro de la VM como steal time.
Requisitos previos
Para reproducir las mediciones de esta guía necesitas:
- Un servidor bare metal y un VPS, ambos con Ubuntu 24.04 LTS, idealmente con un número de núcleos y RAM parecidos. Por ejemplo, un servidor dedicado y un VPS de CubePath.
- Un usuario no root con privilegios
sudoen cada uno. - Un segundo equipo en la misma red o región para las pruebas de red.
- Unos 5 GB libres en disco para el archivo de prueba de
fio.
Paso 1: Comprobar en qué entorno estás y si hay steal time
Antes de medir, confirma si el sistema es una VM y con qué hipervisor. La utilidad systemd-detect-virt viene instalada en Ubuntu:
systemd-detect-virt
En una VM KVM verás:
kvm
En bare metal la salida es none.
A continuación comprueba el steal time, el porcentaje de tiempo que la vCPU quería ejecutarse y el host no se lo permitió. La columna st de vmstat lo muestra:
vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 3521440 48212 612344 0 0 12 20 110 180 2 1 97 0 0
0 0 0 3521440 48212 612344 0 0 0 0 95 160 0 0 100 0 0
Un st cercano a 0 en reposo y por debajo de un par de puntos bajo carga indica que el host no está saturado. Valores sostenidos por encima del 5-10 % significan que otras VM compiten por la misma CPU, y cualquier benchmark que hagas en ese momento no será representativo. En bare metal esta columna siempre es 0.
Revisa también el modelo de CPU que ve el sistema:
lscpu | grep -E 'Model name|Hypervisor vendor|Flags' | cut -c1-120
Si la VM muestra un modelo genérico como QEMU Virtual CPU o Common KVM processor en lugar del modelo real, el hipervisor no está exponiendo todas las instrucciones del procesador (AVX2, AVX-512, AES-NI) y el rendimiento en cálculo y cifrado puede ser bastante menor.
Paso 2: Instalar las herramientas de medición
Instala sysbench para CPU y memoria, fio para disco, iperf3 para red y sysstat para mpstat. Todas están en los repositorios de Ubuntu:
sudo apt update
sudo apt install sysbench fio iperf3 sysstat
Durante la instalación de iperf3 se te preguntará si quieres arrancarlo como servicio. Responde que no; lo lanzarás a mano cuando haga falta.
Comprueba las versiones:
sysbench --version && fio --version && iperf3 --version | head -n 1
Paso 3: Medir CPU y memoria
Ejecuta la prueba de CPU de sysbench usando todos los núcleos durante 30 segundos:
sysbench cpu --threads="$(nproc)" --time=30 run
La cifra que interesa es el número de eventos por segundo:
CPU speed:
events per second: 18234.57
Repite la prueba con un solo hilo (--threads=1) para ver el rendimiento por núcleo, que es lo que limita a aplicaciones de un solo hilo como muchos procesos de PHP o Redis.
Mide el ancho de banda de memoria con bloques de 1 MB:
sysbench memory --threads="$(nproc)" --memory-block-size=1M --memory-total-size=50G run
50.00 GiB transferred (21874.12 MiB/sec)
Ejecuta cada prueba tres veces en cada máquina y quédate con la mediana. Mientras corren, puedes vigilar el steal time por núcleo en otra terminal con mpstat -P ALL 1 (columna %steal).
Paso 4: Medir disco
El disco es donde más diferencias suelen aparecer. Esta prueba de fio hace lecturas aleatorias de 4 KB saltándose la caché de página (--direct=1), que es el patrón típico de una base de datos:
fio --name=randread --filename=/var/tmp/fio.test --size=4G \
--rw=randread --bs=4k --iodepth=32 --numjobs=4 \
--ioengine=libaio --direct=1 --runtime=60 --time_based \
--group_reporting
Fíjate en las IOPS y en los percentiles de latencia:
read: IOPS=182k, BW=711MiB/s (746MB/s)(41.7GiB/60001msec)
clat percentiles (usec):
| 1.00th=[ 245], 50.00th=[ 627], 99.00th=[ 1795], 99.90th=[ 2966]
Para medir escrituras síncronas, que es lo que hace el registro de transacciones de PostgreSQL o MySQL, usa escrituras de 4 KB con fsync tras cada operación:
fio --name=syncwrite --filename=/var/tmp/fio.test --size=4G \
--rw=randwrite --bs=4k --iodepth=1 --numjobs=1 \
--ioengine=psync --fsync=1 --runtime=60 --time_based
Esta prueba suele ser la que más castiga a las VM cuyo disco está en almacenamiento en red. Cuando termines, borra el archivo de prueba:
rm -f /var/tmp/fio.test
Paso 5: Medir la red
En el equipo que hará de servidor de pruebas, arranca iperf3 en modo servidor y abre el puerto si usas UFW:
sudo ufw allow 5201/tcp
iperf3 -s
Desde la máquina que quieres medir, lanza la prueba contra la IP del servidor (sustituye your_server_ip) con cuatro flujos paralelos durante 30 segundos:
iperf3 -c your_server_ip -P 4 -t 30
[SUM] 0.00-30.00 sec 32.8 GBytes 9.38 Gbits/sec 0 sender
[SUM] 0.00-30.00 sec 32.8 GBytes 9.37 Gbits/sec receiver
El caudal casi siempre es parecido entre bare metal y una VM bien configurada. Para ver la diferencia de latencia, mide con ping entre las dos máquinas y compara la media y la desviación (mdev):
ping -c 100 -i 0.2 your_server_ip | tail -n 1
Cuando termines, detén iperf3 con Ctrl+C y cierra el puerto con sudo ufw delete allow 5201/tcp.
Cómo reducir la sobrecarga
Si administras el hipervisor
Si gestionas tu propio host KVM (con libvirt o Proxmox VE), estos ajustes son los que más impacto tienen:
- Modelo de CPU
host: expone al invitado todas las instrucciones del procesador. En libvirt es<cpu mode='host-passthrough'/>y en Proxmox,cpu: host. A cambio, la migración en caliente solo funciona entre hosts con el mismo modelo de CPU. - Controladores virtio: usa
virtio-scsiovirtio-blkpara disco yvirtio-netpara red, nunca IDE ni e1000 emulados. - Sin sobreaprovisionar CPU en VM sensibles a la latencia, o fijando sus vCPU a núcleos físicos concretos (CPU pinning).
- Huge pages para VM con mucha memoria y acceso aleatorio intenso.
- Caché de disco adecuada:
cache=noneconio=nativeoio_uringsuele ser la opción más predecible para bases de datos.
Si solo controlas el sistema operativo
En un VPS no puedes tocar el hipervisor, pero sí puedes elegir un plan con vCPU dedicadas si tu proveedor lo ofrece, vigilar el steal time y dimensionar la RAM para que la base de datos trabaje en caché y dependa menos del disco.
En bare metal, fija el gobernador de frecuencia en modo rendimiento para evitar la latencia de cambio de frecuencia. En Ubuntu, cpupower viene en el paquete de herramientas del kernel:
sudo apt install linux-tools-common "linux-tools-$(uname -r)"
sudo cpupower frequency-set -g performance
Comprueba el gobernador activo:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
performance
Este ajuste no persiste tras un reinicio. Para hacerlo permanente, usa un perfil de tuned o una unidad de systemd que ejecute el mismo comando al arrancar.
Contenedores frente a máquinas virtuales
Los contenedores (Docker, Podman) no virtualizan hardware: comparten el kernel del host y aíslan procesos con namespaces y cgroups. Su sobrecarga en CPU, memoria y disco es prácticamente nula, y la de red depende del modo (el modo host es nativo, el puente con NAT añade algo de coste). A cambio, el aislamiento es más débil que el de una VM, porque un fallo del kernel afecta a todos los contenedores.
Una combinación habitual es ejecutar contenedores directamente sobre bare metal para cargas de alto rendimiento, o dentro de VM cuando se necesita aislamiento fuerte entre clientes o equipos.
Cuándo elegir cada opción
Elige bare metal cuando
- Tu carga es sensible a la latencia de cola (bases de datos OLTP con muchas escrituras síncronas, trading, juegos en tiempo real, VoIP).
- Necesitas acceso directo a hardware: GPU, NVMe específicos, tarjetas de red con SR-IOV o DPDK, o la BMC del servidor.
- Usas el servidor de forma sostenida cerca del 100 % y el coste por núcleo importa más que la flexibilidad.
- Vas a montar tu propia plataforma de virtualización o Kubernetes y quieres controlar el host.
- Tienes requisitos de cumplimiento que exigen hardware no compartido.
Elige virtualización cuando
- Necesitas aprovisionar, redimensionar o destruir servidores con rapidez.
- Tu carga es variable o no llena un servidor físico completo.
- Quieres snapshots, copias de seguridad y restauración gestionadas por la plataforma.
- Ejecutas servicios web, APIs, entornos de desarrollo y pruebas o bases de datos pequeñas y medianas, donde la diferencia de rendimiento no es el cuello de botella.
Considera un enfoque mixto cuando
Tienes una capa claramente crítica (por ejemplo, la base de datos principal) y el resto de servicios es flexible. Es habitual poner la base de datos en bare metal y las aplicaciones, colas y trabajadores en VPS conectados por red privada.
Conclusión
La virtualización con KVM y virtio apenas penaliza el cálculo puro, pero añade latencia en disco y red y depende de lo cargado que esté el host. Mide tu propia carga con sysbench, fio e iperf3 en ambos entornos, vigila el steal time y decide con datos. Como siguientes pasos puedes afinar la pila de red con sysctl, ajustar tu base de datos a la memoria disponible o montar un clúster de alta disponibilidad con Pacemaker y Corosync sobre los servidores que elijas.
