Scalability and High Availability are two different problems
Scalability = ability to handle larger load. High Availability = ability to avoid downtime. A system that scales very well can still go down completely if it runs in only one AZ.
A structured summary of Load Balancer, Auto Scaling Group, SSL/TLS, and scaling strategies on AWS — with core takeaways, practical steps, memorable quotes, and concept explanations.
The most important conclusions of this topic — each with a brief explanation.
Scalability = ability to handle larger load. High Availability = ability to avoid downtime. A system that scales very well can still go down completely if it runs in only one AZ.
Increasing CPU/RAM for one machine is the fastest way, but it is limited by hardware, usually requires downtime, and does not solve high availability.
Adding many small instances is much cheaper than one huge instance. Conditions: the app must not store local state, and a Load Balancer must sit in front.
True HA means surviving the failure of an entire datacenter. Placing 2 instances in the same AZ is not HA.
The LB hides the backend architecture, lets you replace or add instances without clients knowing, and is where SSL terminates and WAF is attached.
ELB is managed by AWS: it automatically scales with traffic, patches security, and integrates with Auto Scaling Group, CloudWatch, and ACM — no LB servers to operate.
Without health checks, the LB keeps sending traffic to dead instances. Health checks must reflect the actual ability to serve, not just whether the port is open.
The LB is open to the Internet (0.0.0.0/0 on 80/443), while EC2 only allows traffic from the LB's Security Group. Never expose EC2 directly to the Internet.
ALB = Layer 7 (HTTP/HTTPS, path/host routing). NLB = Layer 4 (TCP/UDP, ultra-low latency, static IP). GWLB = Layer 3 (inserts security appliances into the traffic flow).
Session affinity keeps clients tied to one instance — it easily causes imbalance and harms scaling. Prefer externalizing sessions (ElastiCache, DynamoDB).
ALB is enabled by default and free. NLB/GWLB are off by default; enabling them incurs cross-AZ data transfer charges.
The LB holds certificates and decrypts, offloading CPU from the backend. SNI allows multiple certificates on the same listener 443, serving multiple domains.
When an instance is removed from the LB (scale-in or deploy), the LB stops sending new requests but waits for current requests to finish — avoiding 502/504 errors for users.
ASG automatically increases/decreases instance count based on load, and detects and replaces failed instances — spreading instances across multiple subnets in multiple AZs.
After each scaling action, the system waits for metrics to stabilize (default 300s) before evaluating again. Without cooldown, ASG will repeatedly scale up and down, wasting resources.
A 12-step process from choosing a Load Balancer to configuring Auto Scaling — with ready-to-run code examples.
HTTP/HTTPS with path/host routing → ALB. TCP/UDP, ultra-low latency or static IP → NLB. Need to insert a firewall/appliance → GWLB.
# Check available Load Balancer types in the region
aws elbv2 describe-load-balancer-types --query "LoadBalancerTypes[].LoadBalancerType"
Health check must point to an endpoint that reflects real app health (e.g., /health), not just check the port.
aws elbv2 create-target-group \ --name tg-app-http \ --protocol HTTP --port 80 \ --vpc-id vpc-0abc123 \ --health-check-path /health \ --health-check-interval-seconds 15 \ --health-check-timeout-seconds 5 \ --healthy-threshold-count 2 \ --unhealthy-threshold-count 3
Place the ALB in public subnets in at least 2 AZs for HA. Listener 80 can redirect to 443.
aws elbv2 create-load-balancer \ --name alb-web \ --type application \ --scheme internet-facing \ --subnets subnet-pub-a subnet-pub-b \ --security-groups sg-0alb123 # Listener 443 with ACM certificate + default forward action aws elbv2 create-listener \ --load-balancer-arn arn:aws:elasticloadbalancing:...:loadbalancer/app/alb-web/xxx \ --protocol HTTPS --port 443 \ --certificates CertificateArn=arn:aws:acm:...:certificate/abc \ --default-actions Type=forward,TargetGroupArn=arn:aws:...:targetgroup/tg-app-http/yyy
The LB receives traffic from the Internet; EC2 only receives traffic from the LB's SG. This is the golden security rule.
# SG for ALB: open 80/443 from anywhere aws ec2 authorize-security-group-ingress --group-id sg-0alb123 \ --protocol tcp --port 443 --cidr 0.0.0.0/0 # SG for EC2: only accept port 80 from the ALB SG (source-group reference) aws ec2 authorize-security-group-ingress --group-id sg-0app456 \ --protocol tcp --port 80 \ --source-group sg-0alb123
Ensure instances in all AZs receive even traffic. ALB is enabled by default; NLB/GWLB must be enabled manually.
aws elbv2 modify-load-balancer-attributes \ --load-balancer-arn arn:aws:elasticloadbalancing:...:loadbalancer/net/nlb-1/xxx \ --attributes Key=load_balancing.cross_zone.enabled,Value=true
Use an LB-generated cookie (AWSALB) or an application cookie. Keep duration short and plan to move sessions out.
aws elbv2 modify-target-group-attributes \ --target-group-arn arn:aws:...:targetgroup/tg-app-http/yyy \ --attributes \ Key=stickiness.enabled,Value=true \ Key=stickiness.type,Value=lb_cookie \ Key=stickiness.lb_cookie.duration_seconds,Value=900
Only support TLS 1.2+ with a modern policy. Add multiple certificates to the same listener 443 — the client sends SNI so the LB picks the correct cert.
# Add a second certificate for another domain on the same listener 443 aws elbv2 add-listener-certificates \ --listener-arn arn:aws:...:listener/app/alb-web/xxx/aaa \ --certificates CertificateArn=arn:aws:acm:...:certificate/domain2 # Enforce TLS 1.2+ and enable SNI (already enabled by default for ALB/NLB) aws elbv2 modify-listener \ --listener-arn arn:aws:...:listener/app/alb-web/xxx/aaa \ --ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06
A Launch Template contains the AMI, instance type, key pair, security group, and user data so the app starts automatically when an instance is created.
aws ec2 create-launch-template \ --launch-template-name lt-web-v1 \ --version-description v1 \ --launch-template-data '{ "ImageId": "ami-0abcdef1234567890", "InstanceType": "t3.micro", "SecurityGroupIds": ["sg-0app456"], "UserData": "IyEvYmluL2Jhc2gKeXVtIGluc3RhbGwgLWUgbmdpbnggLXkKc3lzdGVtY3RsIGVuYWJsZSAtLW5vdyBuZ2lueAo=" }'
Choose subnets in ≥ 2 AZs, attach to the LB Target Group, and set min/desired/max. ASG will replace unhealthy instances.
aws autoscaling create-auto-scaling-group \ --auto-scaling-group-name asg-web \ --launch-template LaunchTemplateName=lt-web-v1,Version='$Latest' \ --min-size 2 --max-size 10 --desired-capacity 2 \ --vpc-zone-identifier "subnet-priv-a,subnet-priv-b" \ --target-group-arns arn:aws:...:targetgroup/tg-app-http/yyy \ --health-check-type ELB \ --health-check-grace-period 60
Target Tracking keeps a metric around a target threshold and automatically calculates the required capacity — less configuration, fewer errors than Simple Scaling.
aws autoscaling put-scaling-policy \ --auto-scaling-group-name asg-web \ --policy-name cpu-target-50 \ --policy-type TargetTrackingScaling \ --target-tracking-configuration '{ "PredefinedMetricSpecification": { "PredefinedMetricType": "ASGAverageCPUUtilization" }, "TargetValue": 50.0, "ScaleInCooldown": 300, "ScaleOutCooldown": 60 }'
For web apps, ALB RequestCountPerTarget is often a better scaling metric than CPU. For workers, use queue depth (SQS ApproximateNumberOfMessages).
aws cloudwatch put-metric-alarm \ --alarm-name "asg-high-requests" \ --metric-name RequestCountPerTarget \ --namespace AWS/ApplicationELB \ --statistic Sum --period 60 \ --threshold 1000 --comparison-operator GreaterThanThreshold \ --evaluation-periods 2 \ --dimensions Name=TargetGroup,Value=targetgroup/tg-app-http/yyy
These three parameters decide whether the system is smooth or jumpy: grace period long enough for app startup, draining long enough for requests to finish, and cooldown long enough to avoid flapping.
# Default cooldown for ASG (seconds) aws autoscaling update-auto-scaling-group \ --auto-scaling-group-name asg-web \ --default-cooldown 300 \ --health-check-grace-period 120 # Deregistration Delay (Connection Draining) on Target Group - default 300s aws elbv2 modify-target-group-attributes \ --target-group-arn arn:aws:...:targetgroup/tg-app-http/yyy \ --attributes Key=deregistration_delay.timeout_seconds,Value=60
Concise, thought-provoking quotes from this topic.
"Scalability is not about making a machine stronger — it is about making the system wider."
"Vertical scaling has limits; horizontal scaling is nearly limitless."
"High Availability means the system stays alive when an entire datacenter dies."
"A Load Balancer does not just distribute traffic — it is the single entry point that hides your entire backend."
"Without health checks, a Load Balancer is just a proxy sending traffic to dead places."
"Let AWS manage the Load Balancer — you do not need to patch and scale a proxy yourself."
"ALB understands HTTP; NLB only understands bytes. Choosing the wrong layer means choosing the wrong tool."
"Sticky sessions are an easy promise — and technical debt when the system has to scale."
"SNI lets one listener serve multiple domains — no need for multiple Load Balancers for multiple websites."
"Connection Draining is kindness to users: do not cut off requests that are still running."
"An Auto Scaling Group is both a scaling tool and insurance against instance failures."
"Scaling on the right metric matters more than scaling fast. Low CPU does not mean the system is idle."
"Cooldown is not slowness — it is how the system avoids harming itself."
The 14 most important terms — explained simply, with real-world comparisons.
The ability of a system to handle an increasing workload by adding resources. There are two directions: vertical scaling (stronger machine) and horizontal scaling (more machines).
Upgrading the resources of one instance: from t3.micro to m5.2xlarge, adding RAM, adding CPU. Often used for databases or systems that cannot be distributed.
Increasing the number of instances running in parallel (scale out). This is the cloud-native way, nearly unlimited, but requires a stateless app and a Load Balancer.
The system remains operational when a component fails. On AWS, this usually means running resources in at least 2 Availability Zones.
A device/service in front of servers that distributes traffic to multiple backends and exposes only one access point to the outside.
A Load Balancer fully managed by AWS: automatically scales with traffic, patches itself, has an SLA, and integrates with ASG, CloudWatch, and ACM.
The LB periodically sends a request to an endpoint to check whether an instance can still serve. An instance that fails N times is removed from traffic rotation.
A logical group of backends (EC2, Lambda, IP, container) that the LB sends traffic to. Each target group has its own health check and attributes.
The same client is always routed to the same instance for the session. Useful when the app stores sessions in memory, but it causes load imbalance.
Each LB node distributes traffic evenly to all instances in all AZs, instead of only within its own AZ. ALB is enabled by default; NLB/GWLB are off by default and charge for cross-AZ traffic when enabled.
The LB holds certificates and decrypts HTTPS, reducing backend CPU load. SNI lets the client declare the hostname so the LB picks the correct certificate — multiple domains on one listener.
Also called Deregistration Delay. When an instance is removed from the LB, the LB stops sending new requests but waits for in-flight requests to finish (default 300s) before disconnecting.
A collection of EC2 instances managed automatically: maintains the desired count, replaces failed instances, and scales based on policy. Set min, max, and desired capacity.
The period ASG pauses evaluation to let metrics and new instances stabilize (default 300s). It prevents repeated up/down scaling that causes waste and instability.
Choose a metric and a target value (e.g., CPU 50%), and ASG automatically calculates and adjusts capacity to keep the metric near that level. The simplest and most effective option.