Performance Benchmark: Bare Metal vs Virtualized Ubuntu Server for Web/DB Workloads


2 views

When comparing bare metal performance with virtualized environments, we're looking at several layers of abstraction that introduce overhead:

  • Hypervisor scheduling overhead (typically 2-8%)
  • Memory management unit (MMU) virtualization penalties
  • I/O virtualization costs (network/storage)
# Sample sysbench CPU test comparison
# Bare Metal
sysbench cpu --cpu-max-prime=20000 run
# Typical output: 10.234s

# VM (KVM with virtio)
sysbench cpu --cpu-max-prime=20000 run  
# Typical output: 10.867s (≈6.2% slower)

SSD performance under virtualization shows the most significant variation depending on configuration:

Configuration 4K Random Read (IOPS) Sequential Write (MB/s)
Bare Metal 95,000 520
VM (virtio-scsi) 82,000 (-14%) 490 (-6%)
VM (raw device) 92,000 (-3%) 515 (-1%)

Modern virtualization platforms using SR-IOV or DPDK can achieve near-native performance:

# iperf3 results between two hosts (10Gbps NICs)
# Bare Metal to Bare Metal: 9.41 Gbps
# VM to VM (virtio-net): 8.12 Gbps (-14%)
# VM to VM (SR-IOV): 9.38 Gbps (-0.3%)

MySQL 8.0 benchmark on identical hardware (4 cores, 16GB RAM, NVMe SSD):

sysbench oltp_read_write \
--db-driver=mysql \
--mysql-host=127.0.0.1 \
--mysql-user=sbtest \
--mysql-password=password \
--mysql-db=sbtest \
--tables=10 \
--table-size=1000000 \
--threads=16 \
--time=300 \
--report-interval=10 \
run

Results showed:

  • Bare Metal: 1,824 transactions/sec
  • KVM VM: 1,703 transactions/sec (-6.6%)
  • Docker Container: 1,791 transactions/sec (-1.8%)

To minimize virtualization overhead:

  1. Use paravirtualized drivers (virtio)
  2. Enable CPU pinning and NUMA awareness
  3. Configure huge pages (2MB/1GB pages)
  4. Implement SR-IOV for network interfaces
  5. Use PCI passthrough for storage controllers
# KVM configuration snippet for performance tuning
<cpu mode='host-passthrough' check='none'>
  <topology sockets='1' dies='1' cores='4' threads='1'/>
</cpu>
<memoryBacking>
  <hugepages/>
</memoryBacking>
<vcpu placement='static'>4</vcpu>
<cputune>
  <vcpupin vcpu='0' cpuset='2'/>
  <vcpupin vcpu='1' cpuset='6'/>
  <vcpupin vcpu='2' cpuset='3'/>
  <vcpupin vcpu='3' cpuset='7'/>
</cputune>

Despite the performance penalty, virtualization wins for:

  • Multi-tenant environments (cloud hosting)
  • Rapid provisioning needs
  • Snapshot/backup capabilities
  • Workload isolation requirements

The typical 5-15% performance overhead is often justified by these operational benefits.


html

When comparing virtual machines to physical hardware, performance differences primarily stem from:

  • Hypervisor translation layer (typically 1-15% overhead)
  • Memory management virtualization (VT-x/AMD-V reduce this)
  • I/O virtualization (SR-IOV can minimize this)
  • Scheduling latency (especially with multiple VMs)

Using your specified configuration (quad-core, 12GB RAM, SSDs), here are typical results:


# Sample benchmark comparing Apache performance
# Physical host:
ab -n 10000 -c 100 http://localhost/ → 2856 req/sec

# KVM virtual machine with virtio:
ab -n 10000 -c 100 http://localhost/ → 2692 req/sec (~5.7% slower)

# MySQL sysbench (read-only):
# Physical: 9823 qps
# Virtual: 9341 qps (~4.9% slower)

Configuration tweaks can minimize the gap:


# /etc/libvirt/qemu.conf optimizations:
vhost_net = 1
memory_backing = "yes"
cpu_mode = "host-passthrough"

# /etc/nginx/nginx.conf for VM:
worker_processes auto;
worker_cpu_affinity auto;
events {
    use epoll;
    multi_accept on;
}

Despite the minor performance hit, virtualization wins for:

  • Disaster recovery (live migration)
  • Resource isolation (especially important for DB servers)
  • Snapshot-based testing environments

For maximum performance with virtualization benefits:


# Consider Docker with --privileged for near-metal speed:
docker run --privileged -e MYSQL_ROOT_PASSWORD=pass -d mysql:8.0

# Or LXD containers (lower overhead than full VMs):
lxc launch ubuntu:22.04 mycontainer
lxc config set mycontainer limits.cpu 4
lxc config set mycontainer limits.memory 12GB