☁ Cloud & DevOps

Autoscaling and load balancing: coping with traffic spikes

How load balancers and autoscaling work, vertical and horizontal scaling, metrics and thresholds, health checks and stateless applications explained.

A site that handles a hundred concurrent visitors can collapse when a thousand arrive, perhaps because an article was shared or a promotional campaign started. Keeping enough servers running for the maximum peak at all times is expensive; keeping too few is risky. Load balancing and autoscaling solve this dilemma by adapting resources to real traffic.

Two ways to grow

Vertical scaling

You replace the server with a more powerful one: more CPU, more memory. It is simple, requires no changes to the application and works well up to a point. There are three limits: there is still a largest possible machine, changing size often requires a reboot, and a single server remains a single point of failure.

Horizontal scaling

You add more identical servers and split the work among them. It has no theoretical limit, lets you survive the failure of one machine and can be done without interruptions. In exchange it requires the application to be designed to run as several copies at once, and a component that distributes traffic: the load balancer.

The load balancer

The load balancer receives all requests and distributes them among the available servers. The most common distribution criteria are:

  • round robin: requests go to each server in turn;
  • least connections: the request goes to the least busy server at that moment;
  • hash of the address or a header: the same client always lands on the same server.

Load balancers work at two different levels. Layer 4 balancers dispatch TCP or UDP connections without looking at their content: they are fast and generic. Layer 7 balancers read HTTP requests and can route by domain, path or headers, handle certificates and add information.

Health checks

A balancer without health checks keeps sending requests to a stuck server. With health checks, it periodically queries an application endpoint, for example /health, and stops using servers that don't respond correctly, putting them back into rotation when they are healthy again.

A good health check verifies that the application can really serve requests, but without depending on too many external services: if the check fails every time a secondary service slows down, the balancer risks excluding all servers at once.

Stateless applications

Horizontal scaling only works well if any server can handle any request. This means the application must be stateless:

  • user sessions must be stored in a shared store, such as Redis or the database, not in a single server's memory;
  • uploaded files go into a common object storage, not onto the local disk;
  • scheduled jobs must be run by a single server or coordinated, otherwise they run as many times as there are servers.

There is the shortcut of sticky sessions, where the balancer always sends the same user to the same server. It works, but distributes load less evenly and loses sessions when a server is removed. It is best regarded as a temporary solution.

Autoscaling

Autoscaling adds and removes servers automatically based on a metric. It is configured with a few parameters:

Parameter Example Meaning
Minimum 2 Number of instances always running, even at night
Maximum 10 Ceiling beyond which it won't grow, to contain costs
Metric Average CPU at 60% Value the system tries to maintain
Cooldown 5 minutes Minimum wait between two successive actions

A minimum of two instances ensures that a failure doesn't stop the service. The maximum protects against a mistake or an attack that would make spending grow without limit.

Choosing the right metric

CPU is the most used metric, but not always the most suitable. An application that spends most of its time waiting for the database can be slow with low CPU. Valid alternatives are requests per instance, response time or, for background jobs, the length of the queue to process.

Reaction times

A new instance isn't ready instantly: it must boot, load the application and pass health checks. If that takes four minutes and the spike arrives in thirty seconds, autoscaling steps in too late. Helpful measures include prebuilt images with everything installed, applications that start quickly and, for predictable events, a scheduled increase in instances before the traffic arrives.

The bottleneck moves

Adding application servers is useless if the limit lies elsewhere. Often, when instances double, the database receives twice the connections and becomes the problem itself. Before relying on autoscaling it pays to check with a load test where the system really gives way: database, cache, external services with request limits. In my work this test almost always reveals an unexpected bottleneck, and it is much better to discover it in a test than during the peak.

In short

  • Vertical scaling is simple but limited; horizontal scaling requires applications designed for multiple copies.
  • The load balancer distributes requests and, thanks to health checks, excludes servers that aren't working.
  • Sessions, files and scheduled jobs must be handled outside the single server.
  • Autoscaling is configured with a minimum, maximum, metric and cooldown, chosen with care.
  • A load test shows where the real bottleneck lies before the peak arrives.
MM
Marco Marzaduri

Marco Marzaduri works in cybersecurity, digital forensics and web development. With degrees in computer science and psychology, he combines technical analysis with an understanding of the human factor.

Read also