How Load Balancing Evolved
At first, an application ran on a single server. This was simple, but risky: if the server crashed, the whole app went down, and growing traffic meant buying a bigger machine.
So teams ran several copies of the app on different servers, which raised a new question: which server should the client call? DNS round robin couldn’t tell if a server was dead. Hardware load balancers like F5 were expensive. Software ones like Nginx and HAProxy required the team to install, patch, and scale them.
Microservices made it harder, since requests now needed to reach the right service first and then the right copy of it. Spring Cloud solved this with Zuul, Eureka, and Ribbon, but teams had to build and run all of it themselves.
Before AWS Application Load Balancer (ALB)
Before ALB arrived in 2016, AWS offered the Classic Load Balancer (CLB), launched in 2009. It distributed incoming traffic across multiple EC2 instances and checked their health. CLB supported Layer 4 (TCP/SSL) and basic Layer 7 (HTTP/HTTPS) load balancing, but without content-based routing.
That worked well for monolithic applications. As systems moved to microservices, developers needed more. Imagine an application with two Spring Boot services:
- User Service: handles
/users/* - Order Service: handles
/orders/*
CLB could spread HTTP requests across instances, but it could not send /users/* to one service and /orders/* to another. Teams had to run a separate load balancer for each service, or place a reverse proxy such as Nginx or HAProxy in front.
AWS introduced ALB in 2016 to solve this. ALB brought Layer 7 routing, so a single load balancer could inspect each HTTP request and send it to the right backend based on its path, hostname, or other conditions.
What is AWS Application Load Balancer (ALB)?
AWS Application Load Balancer (ALB) is a fully managed Layer 7 load balancer that distributes incoming HTTP and HTTPS requests across multiple application instances or services.
Layer 7 is the application layer, where the actual HTTP request (URL, headers, cookies) is visible. Unlike a Layer 4 load balancer, which only sees IP addresses and ports, ALB can inspect the URL path, hostname, and headers to decide where to route traffic.
Users
|
v
AWS ALB
|
+--------+--------+
| |
/users/* /orders/*
| |
v v
User Service Order Service
(Spring Boot) (Spring Boot)A single ALB can route traffic to multiple microservices, so you no longer need a separate load balancer for each one.
Key capabilities
- Path- and host-based routing: Route requests to different services based on URL paths or domains.
- Health checks: Stop sending requests to unhealthy targets, and resume when they recover.
- Multi-AZ availability: Spread traffic across healthy targets in multiple Availability Zones, so the app keeps running even if one data center fails.
- HTTPS termination: Manage TLS certificates through AWS Certificate Manager (ACM).
- Fully managed: AWS handles the infrastructure, maintenance, and patching.
How does ALB relate to Zuul, Ribbon, and Eureka?
If you have worked with Spring Cloud, these concepts will feel familiar.
Spring Cloud | AWS ALB equivalent
---------------------------------------------------------------------
Zuul | Listener rules route requests by path or host
Ribbon | ALB distributes requests across healthy targets
Eureka | Target groups keep a list of registered targetsThe jobs are similar, but the placement differs. Ribbon is client-side and runs inside your application, while ALB is server-side and runs as a separate AWS service.
Also, target groups don't fully replace Eureka. They track registered targets and their health, but they do not provide general service discovery for application-to-application calls.
Understanding ALB Architecture
An ALB has three building blocks: Listeners, Listener Rules, and Target Groups.
Listeners
The entry point to an ALB. It accepts incoming connections on a specific protocol and port, then uses listener rules to decide how to handle requests.
ALB supports two listener protocols:
- HTTP (Port 80): Accepts unencrypted HTTP requests.
- HTTPS (Port 443): Accepts encrypted requests and terminates TLS using an SSL/TLS certificate, typically managed through AWS Certificate Manager (ACM).
An ALB can have multiple listeners, each with its own rules. Every listener requires a default action, which is executed when no higher-priority rule matches.
HTTPS listeners also require a TLS security policy that determines supported TLS versions and ciphers. ALB supports multiple certificates using Server Name Indication (SNI), allowing a single listener to serve multiple domains.
Why Do We Need Both Port 80 and 443?
HTTP:80 → Redirect incoming HTTP requests to HTTPS using a 301 permanent redirect
HTTPS :443 → Securely process requests and forward them to the appropriate target groups
Forward vs Redirect
- Forward: The ALB passes the request to a target group. The browser doesn’t know which backend answered, and the URL stays the same.
- Redirect: The ALB doesn’t call a backend at all. It replies to the browser with a 301 or 302 status and a new URL, and the browser makes a fresh request to that URL.
Listener Rules
Target Groups
A target group is a collection of backend targets that receive requests forwarded by an ALB listener rule. In a microservices architecture, each service typically gets its own target group.
A target group defines four things:
- Targets: which instances, IPs, or functions receive traffic
- Protocol and port: how the ALB talks to the backend
- Health checks: how the ALB decides whether a target is healthy
- Load balancing: how requests are spread among healthy targets
Target types
- Instance: EC2 instances registered by instance ID. Common with EC2 Auto Scaling.
- IP: targets registered by private IP address. Common for ECS Fargate tasks, EKS pods, and servers reachable over VPN or Direct Connect.
- Lambda: an AWS Lambda function that the ALB invokes to handle the request.
The target type is chosen when you create the target group and cannot be changed afterward.
Protocol and port
For instance and IP target groups, the ALB forwards traffic over HTTP or HTTPS to a configured port. A Spring Boot application, for example, might listen on 8080.
Browser
|
| HTTPS :443
v
AWS ALB
|
| HTTP :8080
| HTTP because it is private VPC if you want you also use HTTPS
v
Target Group (users-tg)
|
+---- Spring Boot Instance 1
|
+---- Spring Boot Instance 2Lambda targets have no port or protocol setting, because the ALB invokes the function directly.
Get CodeCraft by Ramcharan’s stories in your inbox
Join Medium for free to get updates from this writer.
Two practical points:
- Security groups: the targets’ security group must allow inbound traffic from the ALB’s security group on the target port, or health checks will fail.
- Path is forwarded unchanged: a request to
/users/123reaches your app as/users/123.
How targets are registered
- Manual: register an EC2 instance or IP address directly.
- EC2 Auto Scaling: registers and deregisters instances as capacity changes.
- Amazon ECS: registers running tasks automatically when the service is linked to the target group.
- Amazon EKS: the AWS Load Balancer Controller registers pods.
Health Checks
A health check is how the ALB decides whether a target can receive traffic. The ALB sends a request to each target on a schedule. Targets that respond correctly receive traffic, and targets that don’t are skipped until they recover. Each target group has its own health check settings.
Health check settings
When you configure a target group, you will see these fields:
- Protocol: HTTP or HTTPS, used for the check.
- Path: the URL the ALB calls, for example
/actuator/health. The default is/. - Port: either Traffic port (the same port the target receives requests on) or an Override port, such as a separate management port.
- Interval: how often the ALB checks each target. Default is 30 seconds.
- Timeout: how long the ALB waits for a response before counting the check as failed. Default is 5 seconds.
- Healthy threshold: how many consecutive successful checks make a target healthy. Default is 5.
- Unhealthy threshold: how many consecutive failed checks make a target unhealthy. Default is 2.
- Success codes: the HTTP status codes that count as a pass. Default is
200, and you can use a list (200,204) or a range (200-299).
Target states:
- initial: the target was just registered and is being checked.
- healthy: passing checks and receiving traffic.
- unhealthy: failing checks and receiving no new requests.
- draining: being removed and finishing in-flight requests.
Load Balancing Algorithms
After health checks remove the unhealthy targets, the ALB needs a rule for picking one of the healthy ones. That rule is the load balancing algorithm, and you set it per target group.
- Round robin(default): takes turns and ignores how busy each target is.
- Least outstanding requests: picks the target that is least busy right now.
- Weighted random: picks randomly, but automatically sends less traffic to a target that looks sick.
Which Algorithm Fits?
Imagine an order-service running on three instances: A, B, and C.
Round robin: all requests are quick and similar
Every request is quick GET /orders/123. The ALB takes turns: A, B, C, A, B, C. Everyone gets an equal share.
Least outstanding requests: some requests are slow
Instance A is busy with three slow report exports, while C is idle. A new request arrives, and the ALB sends it to C, the least busy instance, instead of piling more work on A.
Weighted random: one instance is quietly failing
Instance B’s health check still returns 200, but real requests to it are slow or failing. The ALB notices and automatically sends B less traffic until it recovers.
Anomaly Mitigation
Health checks have a blind spot. An instance can pass its health check but still fail real user requests. For example, /actuator/health returns 200, but calls that need a slow database connection return errors.
Anomaly mitigation closes that gap. It is a target group feature that works with the weighted random algorithm. The ALB watches real traffic and handles a misbehaving target in three steps:
- Detect: the ALB compares each target with the others and notices one that returns more errors or connection failures.
- Reduce: it sends that target less traffic, but keeps it registered. It is not marked unhealthy.
- Recover: when the target behaves normally again, its share of traffic goes back to normal.
Two Related Features: Stickiness and Weighted Target Groups
These work alongside the algorithm rather than replacing it.
Stickiness
Imagine the order-service runs on instances A, B, and C. A user logs in, and instance A saves their session in its own memory. Their next request goes to B, which has never seen this user, so it asks them to log in again.
Without stickiness:
Login → A (session saved in A's memory)
Next req → B (B doesn't know the user → "please log in")
With stickiness:
Login → A (ALB gives the browser a cookie)
Next req → A (cookie says "send me to A")
Next req → AWith stickiness enabled, the ALB sets a cookie in the browser and uses it to send the user back to the same instance.
The downside: a few heavy users can get stuck on one instance while others sit idle. If that instance restarts, those users lose their sessions anyway.
The better fix: store sessions in Redis or a database so any instance can serve any user, and use stickiness only when you can’t change the app.
Weighted target groups
Say orders-v1 is running in production and you have built orders-v2. Switching everyone at once is risky, because a bug would affect all users.
Instead, create one target group per version and let the listener rule split the traffic:
Rule: Path = /orders/* → forward
90% → orders-v1-tg (current version)
10% → orders-v2-tg (new version)Only about 1 in 10 requests reaches v2. If v2 looks healthy, move to 50/50 and then 100%. If it has a problem, you can shift back to 100% v1 in seconds, and only a small share of users is affected. This is called a canary release.
Weighted target groups are configured in the listener rule, not on the target group itself.
How they differ
- Stickiness decides which instance a returning user goes to.
- Weighted target groups decide which version a request goes to.
They can be combined. For example, send 10% of users to v2 and use stickiness to keep each of them on v2, so they don’t switch between versions mid-session.
Conclusion
AWS Application Load Balancer (ALB) simplifies how we manage incoming traffic in modern applications. Instead of maintaining separate load balancers or custom routing infrastructure, ALB provides HTTP routing, load balancing, health checks, and HTTPS termination in a fully managed service.
By combining listeners, listener rules, and target groups, ALB makes it easier to route requests to the right microservice and distribute traffic across healthy application instances.
Features such as multi-AZ availability, stickiness, and weighted routing further help improve application reliability and support safer deployments.
Whether you’re running Spring Boot microservices on EC2 or ECS Fargate, understanding ALB is an important step toward designing scalable and highly available applications on AWS.





![System Design Interview Series:3/30[Back-of-Envelope Estimation]](https://miro.medium.com/v2/resize:fit:1358/format:webp/1*xgLXa5l3deDFviuJtxrtqA.png)


