ЁЯПл The SchoolтА║ЁЯЦея╕П EC2тА║ЁЯЫОя╕П рдзрдбрд╛ 10 тАФ Load balancing: рдЕрдиреЗрдХ рдбреЗрд╕реНрдХрд╕рд╛рдареА рдПрдХ reception
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЫОя╕П рдзрдбрд╛ 10 тАФ Load balancing: рдЕрдиреЗрдХ рдбреЗрд╕реНрдХрд╕рд╛рдареА рдПрдХ reception

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 10 ┬╖ рдорд╛рдЧреАрд▓: lesson-09-auto-scaling ┬╖ рдкреБрдвреАрд▓: lesson-11-monitoring


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ09, рдЖрдгрд┐ load balancer: listeners, target groups, thresholds рд╕рд╣ health checks, рдЖрдгрд┐ рдлрдХреНрдд рдирд┐рд░реЛрдЧреА рдбреЗрд╕реНрдХрдирд╛рдЪ рдкрд╛рд╣реБрдгреЗ рдорд┐рд│рддреАрд▓ рд╣рд╛ рдирд┐рдпрдо тАФ рд╣реЗ рд╕рдЧрд│реЗ ec2/fleet.py рдордзреАрд▓ elb() рдлреЗрд░реАрдлреЗрд░реАрдиреЗ simulate рдХрд░рддреЗ.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдХреЛрдгрддрд╛ рдбреЗрд╕реНрдХ рдореЛрдХрд│рд╛ рдЖрд╣реЗ рд╣реЗ рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдирд╛ рдорд╛рд╣реАрдд рдЕрд╕рдгреНрдпрд╛рдЪреА рдЧрд░рдЬ рдирд╕рд╛рд╡реА. рдореНрд╣рдгреВрди рдЕрднреНрдпрд╛рд╕рд┐рдХреЗрдЪреНрдпрд╛ рдкреНрд░рд╡реЗрд╢рджреНрд╡рд╛рд░рд╛рд╡рд░ рдПрдХрдЪ рд╕реБрдкреНрд░рд╕рд┐рджреНрдз рдкрддреНрддрд╛ рдЕрд╕рд▓реЗрд▓реЗ рдПрдХ reception ЁЯЫОя╕П рдЖрд╣реЗ. Receptionist рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рд╣реБрдгреНрдпрд╛рд▓рд╛ рдЖрд│реАрдкрд╛рд│реАрдиреЗ рдкреБрдврдЪреНрдпрд╛ рдбреЗрд╕реНрдХрдХрдбреЗ рдкрд╛рдард╡рддреЗ.

рджрд░ 10 рд╕реЗрдХрдВрджрд╛рдВрдиреА receptionist рдкреНрд░рддреНрдпреЗрдХ рдбреЗрд╕реНрдХрд▓рд╛ рдлреЛрди рдХрд░рддреЗ: "рд╕рдЧрд│реЗ рдареАрдХ?" (рдПрдХ health check). рдЬреЛ рдбреЗрд╕реНрдХ рд╕рд▓рдЧ рджреЛрдирджрд╛ рдЙрддреНрддрд░ рджреЗрдд рдирд╛рд╣реА рддреЛ unhealthy рдард░рд╡рд▓рд╛ рдЬрд╛рддреЛ тАФ рддрд┐рдереЗ рдЖрдгрдЦреА рдкрд╛рд╣реБрдгреЗ рдЬрд╛рдд рдирд╛рд╣реАрдд. рддреЛ рдкреБрдиреНрд╣рд╛ рд╕рд▓рдЧ рддреАрдирджрд╛ рдЙрддреНрддрд░ рджреЗрддреЛ рддреЗрд╡реНрд╣рд╛ рддреЛ рдирд┐рд░реЛрдЧреА рдард░рддреЛ рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ рдлреЗрд░реАрдд рдпреЗрддреЛ. рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдирд╛ рд╣реЗ рдХрд│рддрд╣реА рдирд╛рд╣реА; рдЗрддрд░ рдбреЗрд╕реНрдХ рдлрдХреНрдд рдереЛрдбрд╛ рд╡реЗрд│ рдЬрд░рд╛ рдЬрд╛рд╕реНрдд рд╡реНрдпрд╕реНрдд рд╣реЛрддрд╛рдд.

рдзрдбрд╛ 09 рдордзрд▓рд╛ рдХрд╛рд│рдЬреАрд╡рд╛рд╣рдХрд╣реА receptionist рдЪреЗ рдРрдХрддреЛ: рдЬреЛ рдбреЗрд╕реНрдХ unhealthy рдЪ рд░рд╛рд╣рддреЛ рддреЛ рдмрд╛рд╣реЗрд░ рдиреЗрд▓рд╛ рдЬрд╛рддреЛ рдЖрдгрд┐ рдмрджрд▓рд▓рд╛ рдЬрд╛рддреЛ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart LR
    users["ЁЯМН visitors"]
    alb["ЁЯЫОя╕П load balancer<br/>listener :443"]
    tg["ЁЯОп target group<br/>health check every 10 s<br/>2 fails тЖТ unhealthy ┬╖ 3 passes тЖТ healthy"]
    a["ЁЯЦея╕П web-a тЬЕ 6"]
    b["ЁЯЦея╕П web-b ЁЯЪл 0<br/>t=30s to t=60s"]
    c["ЁЯЦея╕П web-c тЬЕ 6"]
    users -->|"1"| alb -->|"2"| tg
    tg -->|"3 round robin over healthy only"| a
    tg -.->|"no traffic while unhealthy"| b
    tg --> c
    back["t=70s: web-b passed 3 checks тЖТ back to 4 ┬╖ 4 ┬╖ 4"]
    b -.->|"4"| back

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l10

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдорд╛рдЧрдЪреЗ рдбреЗрд╕реНрдХ рдпреЗрдд-рдЬрд╛рдд рдЕрд╕рддрд╛рдирд╛ (рдзрдбрд╛ 09) clients рдирд╛ рдПрдХ рд╕реНрдерд┐рд░ рдкрддреНрддрд╛ рд╣рд╡рд╛ рдЕрд╕рддреЛ. рдЖрдгрд┐ рдХрд╛рд░рдг health check рдореБрд│реЗрдЪ "рдПрдХ рдбреЗрд╕реНрдХ рдореЛрдбрд▓рд╛, рдПрдХ-рддреГрддреАрдпрд╛рдВрд╢ рдкрд╛рд╣реБрдгреНрдпрд╛рдВрдирд╛ errors рджрд┐рд╕рддрд╛рдд" рдЖрдгрд┐ "рдПрдХ рдбреЗрд╕реНрдХ рдореЛрдбрд▓рд╛, рдХреЛрдгрд╛рд▓рд╛рдЪ рдХрд│рдд рдирд╛рд╣реА" рдпрд╛рддрд▓рд╛ рдлрд░рдХ рдкрдбрддреЛ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

ec2/fleet.py рдордзреАрд▓ elb(target_health, requests, interval, unhealthy_threshold, healthy_threshold) рдкреНрд░рддреНрдпреЗрдХ target рд╕рд╛рдареА pass/fail рдирд┐рдХрд╛рд▓рд╛рдВрдЪреА рдпрд╛рджреА рдШреЗрддреЗ, рдкреНрд░рддреНрдпреЗрдХ рдлреЗрд░реАрдд thresholds рд▓рд╛рд╡рддреЗ, рдЖрдгрд┐ рддреНрдпрд╛ рдХреНрд╖рдгреА рдирд┐рд░реЛрдЧреА рдЕрд╕рд▓реЗрд▓реНрдпрд╛ targets рд╡рд░ 12 requests round robin рдиреЗ рд╡рд╛рдЯрддреЗ. ec2/demo.py рдордзреАрд▓ balancing() web-b рд▓рд╛ рддреАрди рдлреЗрд▒реНрдпрд╛рдВрд╕рд╛рдареА рдирд╛рдкрд╛рд╕ рдХрд░рддреЗ рдЖрдгрд┐ рдкрд░рдд рдЖрдгрддреЗ. Tests L10 рддрдкрд╛рд╕рддрд╛рдд рдХреА unhealthy target рд▓рд╛ traffic рдорд┐рд│рдд рдирд╛рд╣реА рдЖрдгрд┐ рддреЛ рдкрд░рдд рдпреЗрддреЛ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 ec2/demo.py balancing
python3 - <<'EOF'
import sys; sys.path.insert(0, "ec2"); import fleet
# a flapping desk: pass, fail, pass, failтАж it never fails twice in a row, so it is never marked unhealthy
flap = [True, False] * 4
for t, state, spread in fleet.elb({"web-a": [True] * 8, "web-b": flap}):
    print(f"t={t:>2}s", state, spread)
EOF

рдЦрд▒реНрдпрд╛ account рд╡рд░ (AWS credentials, рддреБрдордЪреЗ рд╕реНрд╡рддрдГрдЪреЗ VPC, subnets, SG рдЖрдгрд┐ ASG рд▓рд╛рдЧрддрд╛рдд; load balancer рдЪреЗ рддрд╛рд╕рд╛рд▓рд╛ рдмрд┐рд▓ рд▓рд╛рдЧрддреЗ тАФ рдХрд╛рдо рдЭрд╛рд▓реНрдпрд╛рд╡рд░ рддреЛ delete рдХрд░рд╛):

TG_ARN=$(aws elbv2 create-target-group --name school-web --protocol HTTP --port 80 --vpc-id vpc-0123456789abcdef0 \
    --health-check-path / --health-check-interval-seconds 10 \
    --healthy-threshold-count 3 --unhealthy-threshold-count 2 \
    --query 'TargetGroups[0].TargetGroupArn' --output text)
LB_ARN=$(aws elbv2 create-load-balancer --name school-web --type application \
    --subnets subnet-0aaa1111 subnet-0bbb2222 --security-groups sg-0123456789abcdef0 \
    --query 'LoadBalancers[0].LoadBalancerArn' --output text)
aws elbv2 create-listener --load-balancer-arn "$LB_ARN" --protocol HTTP --port 80 \
    --default-actions Type=forward,TargetGroupArn="$TG_ARN"
aws autoscaling attach-load-balancer-target-groups --auto-scaling-group-name school-web \
    --target-group-arns "$TG_ARN"
aws autoscaling update-auto-scaling-group --auto-scaling-group-name school-web \
    --health-check-type ELB --health-check-grace-period 120
aws elbv2 describe-target-health --target-group-arn "$TG_ARN"

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

balancing рдЫрд╛рдкрддреЗ t=10s web-a:тЬЕ 4 web-b:тЬЕ 4 web-c:тЬЕ 4 рдЖрдгрд┐ 20 s рд▓рд╛ рддреЗрдЪ; t=30s рд▓рд╛ тАФ web-b рдЪрд╛ рджреБрд╕рд░рд╛ check рдирд╛рдкрд╛рд╕ рдЭрд╛рд▓реНрдпрд╛рд╡рд░ тАФ web-a:тЬЕ 6 web-b:ЁЯЪл 0 web-c:тЬЕ 6, рдЖрдгрд┐ t=60s рдкрд░реНрдпрдВрдд рдЕрд╕реЗрдЪ рд░рд╛рд╣рддреЗ; t=70s рд▓рд╛, рддреАрди passes рдирдВрддрд░, рдкреБрдиреНрд╣рд╛ web-a:тЬЕ 4 web-b:тЬЕ 4 web-c:тЬЕ 4. рддреБрдордЪрд╛ flapping рдбреЗрд╕реНрдХ рдкреНрд░рддреНрдпреЗрдХ рдлреЗрд░реАрдд {'web-a': 'healthy', 'web-b': 'healthy'} {'web-a': 6, 'web-b': 6} рдЫрд╛рдкрддреЛ: рддреЛ рдирд┐рдореНрдореЗ checks рдирд╛рдкрд╛рд╕ рд╣реЛрддреЛ, рддрд░реА рдХрдзреАрд╣реА рд╕рд▓рдЧ рджреЛрдирджрд╛ рдирд╛рд╣реА, рдореНрд╣рдгреВрди рддреНрдпрд╛рд▓рд╛ рдирд┐рдореНрдорд╛ traffic рдорд┐рд│рдд рд░рд╛рд╣рддреЛ.

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

Reception рдлрдХреНрдд checks рдкрд╛рд╕ рд╣реЛрдгрд╛рд▒реНрдпрд╛ рдбреЗрд╕реНрдХрдХрдбреЗрдЪ рдкрд╛рд╣реБрдгреЗ рдкрд╛рдард╡рддреЗ, рдмрд░рд╛ рдЭрд╛рд▓реЗрд▓рд╛ рдбреЗрд╕реНрдХ рддреНрдпрд╛рдиреЗ рд╕реНрд╡рддрдГрд▓рд╛ рд╕рд┐рджреНрдз рдХреЗрд▓реНрдпрд╛рдирдВрддрд░рдЪ рдкрд░рдд рдШреЗрддреЗ тАФ рдЖрдгрд┐ рдиреЗрдордХреНрдпрд╛ рдЪреБрдХреАрдЪреНрдпрд╛ рд▓рдпреАрдд рдирд╛рдкрд╛рд╕ рд╣реЛрдгрд╛рд░рд╛ рдбреЗрд╕реНрдХ рдирд┐рд╕рдЯреВ рд╢рдХрддреЛ, рдореНрд╣рдгреВрдирдЪ рддреБрдореНрд╣реА error rates рд╡рд░рд╣реА рд▓рдХреНрд╖ рдареЗрд╡рддрд╛.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: ALB рдореНрд╣рдгрдЬреЗ рдЬрд┐рдереЗ TLS рд╕рдВрдкрддреЛ, рдЬрд┐рдереВрди access logs рдЖрдгрд┐ HTTPCode_Target_5XX_Count рдпреЗрддрд╛рдд, рдЖрдгрд┐ рдЬрд┐рдереЗ AWS WAF рдЬреЛрдбрд▓рд╛ рдЬрд╛рддреЛ. Incident рдордзреНрдпреЗ рдХреЛрдгреАрд╣реА рдЙрдШрдбрдгрд╛рд░рд╛ рдкрд╣рд┐рд▓рд╛ graph рдореНрд╣рдгрдЬреЗ рддреНрдпрд╛рдЪрд╛ target health.

тПня╕П рдкреБрдвреЗ

Fleet рд╕реНрд╡рддрдГрдЪ рдЪрд╛рд▓рддреЛ тАФ рдХрд╛рд╣реАрддрд░реА рд╡рд┐рдЪрд┐рддреНрд░ рдШрдбреЗрдкрд░реНрдпрдВрдд. рджреЛрди status checks, рджреЛрди рд╡реЗрдЧрд│реЗ рдЙрдкрд╛рдп, рдЖрдгрд┐ hypervisor рд▓рд╛ рди рджрд┐рд╕рдгрд╛рд░реЗ рдЖрдХрдбреЗ: monitoring рдЖрдгрд┐ troubleshooting.

git checkout lesson-11-monitoring

ЁЯЫОя╕П Lesson 10 тАФ Load balancing: one reception for many desks

ЁЯУН You are here: Lesson 10 of 12 ┬╖ Previous: lesson-09-auto-scaling ┬╖ Next: lesson-11-monitoring


ЁЯУж What's in this branch

Lessons 01тАУ09, plus the load balancer: listeners, target groups, health checks with thresholds, and the rule that only healthy desks get visitors тАФ simulated round by round by elb() in ec2/fleet.py.

ЁЯзТ Explain like I'm 5

Visitors should not have to know which desk is free. So the study hall has one reception ЁЯЫОя╕П at the entrance with one well-known address. The receptionist sends each visitor to the next desk in turn.

Every 10 seconds the receptionist rings each desk: "are you OK?" (a health check). A desk that fails to answer twice in a row is marked unhealthy тАФ no more visitors go there. When it answers three times in a row again, it is healthy and back in the rotation. The visitors never notice; the other desks just get a little busier for a while.

The caretaker from lesson 09 listens to the receptionist too: a desk that stays unhealthy is carried out and replaced.

ЁЯЧ║я╕П Diagram

flowchart LR
    users["ЁЯМН visitors"]
    alb["ЁЯЫОя╕П load balancer<br/>listener :443"]
    tg["ЁЯОп target group<br/>health check every 10 s<br/>2 fails тЖТ unhealthy ┬╖ 3 passes тЖТ healthy"]
    a["ЁЯЦея╕П web-a тЬЕ 6"]
    b["ЁЯЦея╕П web-b ЁЯЪл 0<br/>t=30s to t=60s"]
    c["ЁЯЦея╕П web-c тЬЕ 6"]
    users -->|"1"| alb -->|"2"| tg
    tg -->|"3 round robin over healthy only"| a
    tg -.->|"no traffic while unhealthy"| b
    tg --> c
    back["t=70s: web-b passed 3 checks тЖТ back to 4 ┬╖ 4 ┬╖ 4"]
    b -.->|"4"| back

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/ec2/lesson-diagrams.html#l10

тЭУ What

ЁЯдФ Why

Because clients need one stable address while the desks behind it come and go (lesson 09). And because a health check is the difference between "one desk is broken, a third of the visitors see errors" and "one desk is broken, nobody notices".

ЁЯФз How (in this repo)

elb(target_health, requests, interval, unhealthy_threshold, healthy_threshold) in ec2/fleet.py takes a list of pass/fail results per target, applies the thresholds each round, and spreads 12 requests round robin over the targets that are currently healthy. balancing() in ec2/demo.py fails web-b for three rounds and brings it back. Tests L10 check that the unhealthy target gets no traffic and that it returns.

ЁЯзк Try it

python3 ec2/demo.py balancing
python3 - <<'EOF'
import sys; sys.path.insert(0, "ec2"); import fleet
# a flapping desk: pass, fail, pass, failтАж it never fails twice in a row, so it is never marked unhealthy
flap = [True, False] * 4
for t, state, spread in fleet.elb({"web-a": [True] * 8, "web-b": flap}):
    print(f"t={t:>2}s", state, spread)
EOF

On a real account (needs AWS credentials, your own VPC, subnets, SG and ASG; a load balancer bills by the hour тАФ delete it when you are done):

TG_ARN=$(aws elbv2 create-target-group --name school-web --protocol HTTP --port 80 --vpc-id vpc-0123456789abcdef0 \
    --health-check-path / --health-check-interval-seconds 10 \
    --healthy-threshold-count 3 --unhealthy-threshold-count 2 \
    --query 'TargetGroups[0].TargetGroupArn' --output text)
LB_ARN=$(aws elbv2 create-load-balancer --name school-web --type application \
    --subnets subnet-0aaa1111 subnet-0bbb2222 --security-groups sg-0123456789abcdef0 \
    --query 'LoadBalancers[0].LoadBalancerArn' --output text)
aws elbv2 create-listener --load-balancer-arn "$LB_ARN" --protocol HTTP --port 80 \
    --default-actions Type=forward,TargetGroupArn="$TG_ARN"
aws autoscaling attach-load-balancer-target-groups --auto-scaling-group-name school-web \
    --target-group-arns "$TG_ARN"
aws autoscaling update-auto-scaling-group --auto-scaling-group-name school-web \
    --health-check-type ELB --health-check-grace-period 120
aws elbv2 describe-target-health --target-group-arn "$TG_ARN"

тЬЕ Verify тАФ what you should see

balancing prints t=10s web-a:тЬЕ 4 web-b:тЬЕ 4 web-c:тЬЕ 4 and the same at 20 s; at t=30s тАФ after web-b's second failed check тАФ web-a:тЬЕ 6 web-b:ЁЯЪл 0 web-c:тЬЕ 6, staying that way to t=60s; at t=70s, after three passes, back to web-a:тЬЕ 4 web-b:тЬЕ 4 web-c:тЬЕ 4. Your flapping desk prints {'web-a': 'healthy', 'web-b': 'healthy'} {'web-a': 6, 'web-b': 6} in every round: it fails half its checks, yet never twice in a row, so it keeps getting half the traffic.

ЁЯПБ What you just proved

The reception only sends visitors to desks that pass their checks, takes a recovered desk back only after it proves itself тАФ and a desk that fails in just the wrong rhythm can slip through, which is why you also watch error rates.

тЪая╕П Common mistakes

ЁЯПн Why this matters in production: the ALB is where TLS ends, where access logs and HTTPCode_Target_5XX_Count come from, and where AWS WAF attaches. Its target health is the first graph anyone opens in an incident.

тПня╕П Next

The fleet runs itself тАФ until something odd happens. Two status checks, two different fixes, and the numbers the hypervisor cannot see: monitoring and troubleshooting.

git checkout lesson-11-monitoring
тЖР Previousauto scalingNext тЖТmonitoring

This page is the lesson's README from the lesson-10-load-balancing branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.