footer-logofooter-logo
Game Server Performance: Bare Metal vs Virtual MachinesGo back

Game Server Performance: Bare Metal vs Virtual Machines

Bare metal wins on the two numbers that decide whether a game server feels good: worst-case tick time and worst-case latency. A single-tenant VM on hardware you control gets close. An oversold multi-tenant VPS is where fixed-tick simulation falls apart, because a vCPU scheduled a few milliseconds late is a missed tick every player sees as rubber-banding. This guide covers what a hypervisor adds to a tick loop, why the 95th-percentile tick time matters more than average throughput, how to measure steal time and MSPT on your own server, and when a VM is still the right call.

08 July 2026

by Clay Berndt

Game Servers

Performance

Virtualization

Dedicated Servers

Loading...

The short answer

Bare metal wins on the two numbers that decide whether a game server feels good: worst-case tick time and worst-case latency. A single-tenant virtual machine on hardware you control comes close enough that most players will never tell the difference. An oversold multi-tenant VPS, the kind that fills the cheap end of game hosting, is where the wheels come off, because the thing a hypervisor does under contention (making your CPU wait its turn) is the exact thing a fixed-tick game loop cannot absorb.

That is the whole argument in one paragraph. A game server is not judged on how much work it gets through in a second; it is judged on whether every single tick finishes inside its budget. Miss one tick and every connected player sees it: rubber-banding, a hit that did not register, a rollback. Average throughput can look perfect while the worst one percent of ticks quietly ruins the match. Virtualisation adds variance to precisely that worst one percent, and cheap virtualisation adds a lot of it.

So the honest position is conditional, not tribal. Bare metal is the safe default for anything competitive or busy. A VM is fine, sometimes the better call, when you own the hypervisor and control who else runs on the box. A shared VPS from a host selling four times more vCPUs than it has cores is the setup that generates the "why is my server lagging" threads. This article explains the mechanism behind each of those, and shows you how to measure which situation you are actually in.

This guide covers:

  • what a hypervisor adds to a tick loop: vCPU scheduling, steal time, timer jitter, NUMA and I/O paths
  • why fixed-tick simulation cares about the 95th-percentile tick, not the average
  • the oversubscription economics that make cheap VPS game hosting lag
  • how to measure steal time and tick time on your own server, with real commands
  • why containers are not VMs, and when a VM is genuinely the right tool

For the wider case (managed hosting versus running your own box, and choosing the hardware) the bare-metal game hosting guide is the pillar this article sits under.

What a hypervisor actually adds

Start with the friendly version. A modern hypervisor like KVM executes guest CPU instructions on the real processor with hardware assistance (VT-x or AMD-V). For raw arithmetic a VM runs within a few percent of native, and if a game server were CPU-bound in the "crunch a big array" sense, virtualisation would barely matter. It isn't, and that is the catch. A game server is latency-bound on a repeating schedule, and the hypervisor sits between that schedule and the hardware. Here is what it inserts.

vCPU scheduling and steal time. Your VM's virtual CPUs are not CPUs; they are threads the host scheduler runs on real cores whenever it decides to. When the host is busy with other guests, host processes or interrupts, your vCPU sits in a run queue waiting for a physical core. That wait is CPU steal time, reported as %st or st in top, vmstat and mpstat. It is time your game loop wanted the CPU and did not get. On a box with enough cores for every guest it stays near zero; under oversubscription it climbs, and every millisecond of steal is a millisecond your tick ran late. Leaseweb's analysis of steal time puts the rule of thumb at sustained steal above 10 percent meaning the guest is running slower than it should.

Timer and interrupt jitter. A game loop wakes on a timer 20 or 64 times a second. Under virtualisation that timer interrupt is itself mediated by the hypervisor, which adds small, variable delays to each wakeup. On an idle host the delay is negligible. Under load the wakeup can drift by milliseconds, and a loop that wakes late finishes late.

NUMA effects. On a two-socket server, memory attached to one socket is slower to reach from the other. If the hypervisor schedules your vCPUs on one socket while your VM's memory lives on the other, every access pays the cross-node penalty. Bare metal has the same physics, but the OS sees the real topology and places threads accordingly; a VM often sees a flattened, synthetic topology unless the host deliberately exposes the real one.

Memory ballooning. The virtio-balloon device lets the host reclaim RAM from a guest by inflating a "balloon" inside it. Handy for density, hostile to a game server: if the host claws back memory your JVM or game process was using, you get swapping or garbage-collection pressure at the worst possible moment. On oversold hosts, ballooning is how a provider fits more guests than there is RAM for.

virtio I/O paths. Disk and network run through paravirtualised drivers (virtio-blk and virtio-net, usually with vhost). These are fast; they are not free. Every packet and every disk read crosses one more boundary than it would on bare metal. For a chunk-loading Minecraft world, or a busy server writing logs and world saves, that extra path length shows up as occasional I/O stalls that stretch a tick. The same VirtIO tax is covered from the container angle in our LXC vs KVM comparison.

Individually these are small. The problem is that they all land on the same victim: the tick that has to finish in 50 milliseconds, or 15.

Why the worst tick is the only tick that matters

A Minecraft server ticks 20 times a second, which gives each tick 50 milliseconds to do everything: mob AI, redstone, block updates, entity movement, then sending the world to every player. Stay inside the budget and the server holds 20 TPS. Blow it and the tick runs long, the next one starts late, and time on the server slows down for everyone at once. CS2 runs its simulation at 64 tick, roughly 15.6 milliseconds per tick, with a subtick system that timestamps inputs between ticks so a shot lands where it was fired. A slow tick still delays when those inputs get processed.

Here is the part that trips up capacity planning: these are worst-case problems, not average ones. A server can average 19.9 TPS and feel terrible because once a second a tick takes 180 milliseconds. Averages hide that; percentiles do not. The useful number is the 95th-percentile tick time (p95), not the mean, because it tells you what your slow ticks look like, and the slow ticks are what players feel.

A hypervisor that adds 8 milliseconds of steal here and a 12-millisecond scheduling delay there will not move your average much. It will wreck your p95. That is the entire reason bare metal and a well-run VM can post the same average TPS while feeling completely different in a firefight. The average says "fine"; the 95th percentile says "stutters under load", and only one of those is the truth players experience.

Oversubscription: why cheap VPS game hosting lags

The economics of budget VPS hosting are simple, and they work against you. A host has a box with, say, 32 physical cores. Sold honestly as dedicated cores, that is a fixed number of customers. Sold as vCPUs at 4:1 oversubscription, it is 128 vCPUs worth of plans on the same silicon. Most of the time most guests are idle, so the maths works and the host makes money.

The moment several of your neighbours get busy at once (a backup job, another game server filling up, someone kicking off a compile), the host scheduler has more runnable vCPUs than it has cores, and it makes yours wait. That wait is the steal time from the last section, and you have no control over it, because the contention is coming from tenants you cannot see. This is the noisy-neighbour problem, and for a fixed-tick workload it is close to a worst case: your tick budget is fixed at 50 or 15 milliseconds, but the CPU time you actually receive is now a lottery run by other people's load. It is also why a VPS can benchmark beautifully at 3am and fall over at peak, on the same plan, with nothing changed on your side.

How to measure it on your own server

Enough theory. Here is how to find out whether virtualisation is actually costing you, on the machine you have.

Steal time. Run top and read the st figure on the %Cpu(s) line:

%Cpu(s): 42.1 us,  3.2 sy,  0.0 ni, 38.0 id,  0.0 wa,  0.0 hi,  1.1 si, 15.6 st

The 15.6 st is the number that matters: 15.6 percent of the time, this vCPU wanted to run and could not, because the host was busy elsewhere. vmstat 1 puts the same figure in its rightmost st column once a second, and mpstat -P ALL 1 breaks %steal out per core:

vmstat 1
mpstat -P ALL 1

On bare metal st is always 0, because there is no hypervisor to steal from, which is itself the tell. If you see any steal, you are on a guest; if you see sustained double-digit steal, your host is oversubscribed. These outputs are illustrative. Your values will differ with hardware, load and how busy your neighbours are.

Minecraft tick time. Install the spark profiler (a plugin or mod, depending on your server flavour) and run /spark tps. Spark reports TPS against the target of 20, and tick durations against the 50-millisecond budget, giving you the minimum, median, 95th-percentile and maximum MSPT:

/spark tps
TPS from last 5s, 10s, 1m, 5m, 15m:
  17.9, 18.8, 19.7, 20.0, 20.0
Tick durations (min/med/95%ile/max ms) from last 10s, 1m:
  22/47/96/210;  20/43/71/180

Watch the 95%ile column, not the median. A median of 47 milliseconds with a 95th-percentile of 96 is a server that looks healthy on average and stutters under load. On an oversubscribed guest, that 95th-percentile figure and your steal time rise together, which is exactly how you connect the symptom to the cause. /spark health gives the same TPS and MSPT alongside CPU and memory in one snapshot. (Output representative.)

Source and CS2 servers. The stats console command prints CPU usage and an fps figure that tracks the tick rate: a healthy 64-tick server reports fps at or just above 64, capped by the tick rate, and any dip under load is a frame the simulation could not finish in time. Run it a few times in a row to see the variance, since a single line is only a snapshot.

The cleanest way to isolate the hypervisor's cost is to hold everything else constant: same CPU, same RAM, same game version, same load, and change only whether the server runs on bare metal or inside a KVM guest on that identical hardware. That is a test worth running in a controlled lab rather than arguing from first principles.

The point that measurement would put a figure on is not controversial: on identical hardware, the bare-metal run holds a lower and flatter 95th-percentile tick time, and the guest's disadvantage grows with load. What a benchmark settles is how big the gap is on a single-tenant VM you control, which is usually small, versus what oversubscription does to it, which is not.

Containers are not virtual machines

A lot of "should I virtualise" anxiety evaporates once you separate containers from VMs, because they are not the same tradeoff. An LXC system container or a Docker container shares the host kernel. There is no guest kernel, no virtual hardware, and no vCPU scheduling layer between your process and the core. That means there is no steal time to speak of and no timer-virtualisation jitter: a containerised game server on bare metal runs at essentially native speed, with a cgroup capping how much CPU and memory it may use. The overhead is a rounding error.

So "I want to run several isolated game servers on one box" does not require VMs. Containers give you per-server resource limits, tidy packaging and near-native performance on the same kernel, which is exactly what a game panel like Pterodactyl does under the hood. The tradeoffs that do exist (weaker isolation than a VM, a shared kernel, no live migration) are about security and operations, not tick performance, and we cover them in full in LXC vs KVM in Proxmox. For raw game-server performance, a container on bare metal is the near-native option; a VM is the one that adds the scheduling layer this whole article is about.

When a VM is the right call

Virtualisation is not the enemy; oversubscription is. There are real cases where a VM is the right tool, and they share one feature: you control the contention.

  • Dev, staging and test servers. Nobody's competitive experience depends on a staging box's p95 tick. Spin up VMs freely; the isolation and snapshot convenience are worth more than the last few milliseconds.
  • Small or casual servers. A survival server for you and a dozen friends spends most of its ticks well under budget. There is so much headroom that the hypervisor's overhead never becomes the bottleneck, and a modest VM is completely fine.
  • A VM on your own hypervisor. This is the important one. If you rent a whole bare-metal box and run your own hypervisor on it, you decide how many guests share the cores and whether they are oversubscribed. Pin the game VM to dedicated cores, do not overcommit, and you get most of virtualisation's flexibility with steal time you control rather than steal time your host inflicts. The difference between this and a cheap VPS is entirely about who owns the oversubscription decision.

The setup to avoid for anything busy or competitive is the one where someone else made that decision for you, and priced it to be aggressive.

If you must virtualise: tuning that helps

Given a VM on hardware you control, a handful of settings claw back most of the lost worst-case performance:

  • Pin vCPUs to physical cores. CPU pinning (vcpupin in libvirt) ties the game VM's vCPUs to specific physical cores, so the scheduler stops bouncing them around. That cuts jitter and improves cache behaviour. Do not share those pinned cores with other guests.
  • Use the host CPU model. Set the guest to host-passthrough (or at least host-model) so the VM sees the real CPU and its full instruction set, instead of a lowest-common-denominator model that leaves performance on the table.
  • Do not oversubscribe the cores that matter. Match vCPUs to real cores for the game VM, and keep total committed vCPUs at or below physical cores when tick stability matters. The density you give up is the latency you keep.
  • Turn off ballooning for the game VM. Give it a fixed memory reservation so the host cannot reclaim RAM mid-match. Let ballooning apply to guests that can tolerate it.
  • Keep the fast NIC and disk paths. Use virtio with vhost-net, and put game state on NVMe. The sizing side of this is in the server sizing guide, which also makes the case for fewer, faster cores over many slow ones.

None of this makes a VM beat bare metal. It closes the gap to the point where, on a box you control, the difference stops mattering for most servers.

The verdict, by condition

SituationBest choiceWhy
Competitive shooter (CS2 and the like)Bare metalSub-16 ms tick budget leaves no room for steal or jitter
Busy public Minecraft or large modpackBare metalTick budget tight under entity and redstone load; p95 rules
Small SMP or friends serverVM is fineLarge tick headroom absorbs the overhead
Dev, staging or testVM on your hypervisorSnapshots and isolation beat the last few milliseconds
Several servers on one owned boxContainers on bare metalNear-native, per-server limits, no vCPU layer
VM on a hypervisor you ownFine if tunedPin cores, no overcommit; you control contention
Cheap oversold multi-tenant VPSAvoid for anything busySteal time set by neighbours you cannot see

Latency is the other half of "feels good", and it is mostly about geography and routing rather than the metal-versus-VM question; the game server latency guide covers that side.

Deploying on Serverside

If the workload is competitive or busy, the argument above points one way: the whole machine, with no hypervisor between your tick loop and the cores. A Serverside game server is single-tenant bare metal on our own network (AS55285), so there is no steal time, no noisy neighbours, and no oversubscription set by anyone but you. Provisioning is sub-minute, and always-on DDoS mitigation sits in front of the public interface, which for a game server is not optional. If you would rather slice one box into VMs yourself, that is supported too: rent the dedicated hardware, run your own hypervisor, and you own every contention decision this article told you to watch.

FAQ

Does a VM always add lag to a game server?

No. A VM on hardware you control, with vCPUs pinned and no oversubscription, adds overhead small enough that most servers never notice it. The lag people blame on "virtualisation" almost always comes from oversubscription rather than the hypervisor itself: a shared VPS where your CPU time depends on other tenants' load. The underlying mechanism is CPU steal time, and you can measure it directly.

What is CPU steal time and what number is bad?

Steal time (%st in top) is the percentage of time your virtual CPU was ready to run but had to wait for the host to hand it a physical core. On bare metal it is always zero. On a healthy VM it stays near zero. A common rule of thumb is that sustained steal above 10 percent means the guest is running slower than it should, and for a fixed-tick game server even a few percent shows up as slow ticks.

Why does my VPS game server lag even though CPU usage looks low?

Because in-guest CPU usage does not show contention on the host. Your server can sit at 30 percent CPU and still miss ticks if the host keeps making your virtual CPU wait; that lost time shows up as steal, not as usage. Check the st column in top or vmstat 1. High steal with low usage is the classic signature of an oversubscribed VPS.

Are containers better than VMs for game-server performance?

For raw performance, yes. A Docker or LXC container on bare metal shares the host kernel, so there is no virtual-CPU scheduling layer and no steal time, and it runs at near-native speed. VMs give stronger isolation and features like live migration that containers do not. For tick performance a container on bare metal beats a VM; for isolating untrusted tenants a VM wins. Our LXC vs KVM comparison has the full tradeoff.

How do I measure whether virtualisation is hurting my server?

Two numbers. For steal time, run top, vmstat 1 or mpstat -P ALL 1 and read the st or %steal column. For tick health on Minecraft, install the spark profiler and run /spark tps, watching the 95th-percentile MSPT rather than the average. On Source and CS2 servers the stats command reports an fps figure that tracks the tick rate. If steal time and 95th-percentile tick time climb together, the host is the problem.

Clay Berndt

Written by

Clay Berndt

CEO, Serverside.com & Host Havoc

Clay is the CEO of Serverside.com and Host Havoc, with more than a decade of experience running globally distributed hosting infrastructure and a game-server platform that has served over 200,000 customers.

Keep reading

View all articles