ЁЯПл The SchoolтА║ЁЯУИ ScalingтА║ЁЯОк рдзрдбрд╛ 01 тАФ Scaling рдХрд╛: рд╢рд╛рд│реЗрдЪреНрдпрд╛ рдЬрддреНрд░реЗрддреАрд▓ рдирд┐рдХрд╛рд▓рд╛рдЪрд╛ рджрд┐рд╡рд╕
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯОк рдзрдбрд╛ 01 тАФ Scaling рдХрд╛: рд╢рд╛рд│реЗрдЪреНрдпрд╛ рдЬрддреНрд░реЗрддреАрд▓ рдирд┐рдХрд╛рд▓рд╛рдЪрд╛ рджрд┐рд╡рд╕

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 13 рдкреИрдХреА рдзрдбрд╛ 01 ┬╖ рдкреБрдвреЗ: lesson-02-measuring-load


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

рд╣рд╛ рдкреВрд░реНрдг рдХреЛрд░реНрд╕ рд╕реЛрдбрд╡рддреЛ рддреА рдПрдХрдЪ рд╕рдорд╕реНрдпрд╛: рд╕рд╛рдорд╛рдиреНрдп рджрд┐рд╡рд╢реА рд╢рд╛рд│реЗрдЪреНрдпрд╛ website рд▓рд╛ рд╕реЗрдХрдВрджрд╛рд▓рд╛ 40 рднреЗрдЯреА рдорд┐рд│рддрд╛рдд. рдирд┐рдХрд╛рд▓рд╛рдЪреНрдпрд╛ рджрд┐рд╡рд╢реА рддреНрдпрд╛ 2,000 рд╣реЛрддрд╛рдд. Site рд╕рдЧрд│реНрдпрд╛рдВрд╕рд╛рдареА рдЬрд▓рдж рд░рд╛рд╣рд┐рд▓реА рдкрд╛рд╣рд┐рдЬреЗ тАФ page (UI), рддреНрдпрд╛рдорд╛рдЧрдЪрд╛ API, рдЖрдгрд┐ рддреНрдпрд╛рдорд╛рдЧрдЪрд╛ database. рд╕рдВрдкреВрд░реНрдг рдХреЛрд░реНрд╕рднрд░ рддреБрдореНрд╣реА рд╡рд╛рдкрд░рд╛рд▓ рддреНрдпрд╛ рдЦрд▒реНрдпрд╛ files:

ЁЯОТ рд╕реБрд░реВ рдХрд░рдгреНрдпрд╛рдЖрдзреА: рддреБрдореНрд╣рд╛рд▓рд╛ рдлрдХреНрдд Python 3 рд╣рд╡реЗ тАФ AWS account рдирдХреЛ, pip install рдирдХреЛ. sim.py рдордзреНрдпреЗ рдЧреЛрд▓ рдЙрджрд╛рд╣рд░рдгрд╛рдЪреНрдпрд╛ рдЖрдХрдбреНрдпрд╛рдВрд╕рд╣ рд╢рд┐рдХрд╡рдгреНрдпрд╛рд╕рд╛рдареАрдЪреЗ models рдЖрд╣реЗрдд (рдПрдХрд╛ server рд▓рд╛ рд╕реЗрдХрдВрджрд╛рд▓рд╛ 150 requests, 2 рдорд┐рдирд┐рдЯрд╛рдВрдЪрд╛ warm-up, 200 ms рдЪрд╛ Lambda). рдЦрд▒реНрдпрд╛ systems рдордзреНрдпреЗ network jitter, retries рдЖрдгрд┐ limits рдпреЗрддрд╛рдд тАФ рдПрдЦрд╛рджреНрдпрд╛ рдЖрдХрдбреНрдпрд╛рд╡рд░ рд╡рд┐рд╢реНрд╡рд╛рд╕ рдареЗрд╡рдгреНрдпрд╛рдЖрдзреА рдЦрд▒реНрдпрд╛ system рдЪрд╛ load test рдХрд░рд╛ (рдзрдбрд╛ 02). on a real account рдЕрд╕реЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реНрдпрд╛ commands рд╕рд╛рдареА AWS CLI (рдХрд┐рдВрд╡рд╛ Terraform / kubectl) рдЖрдгрд┐ credentials рд▓рд╛рдЧрддрд╛рдд, рдЖрдгрд┐ рддреНрдпрд╛рдВрдЪреЗ рдкреИрд╕реЗ рд▓рд╛рдЧреВ рд╢рдХрддрд╛рдд.

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

рджрд░рд╡рд░реНрд╖реА рдирд┐рдХрд╛рд▓рд╛рдЪреНрдпрд╛ рджрд┐рд╡рд╢реА рд╢рд╛рд│рд╛ рдЬрддреНрд░рд╛ рднрд░рд╡рддреЗ. рд╕рд╛рдорд╛рдиреНрдп рджрд┐рд╡рд╢реА рдХрд╛рд╣реА рдкрд╛рд▓рдХ office рдордзреНрдпреЗ рдпреЗрддрд╛рдд. рдПрдХрд╛ рдЦрд┐рдбрдХреАрд╡рд░ рдПрдХ рдХрд╛рд░рдХреВрди рдкреБрд░реЗрд╕рд╛ рдЕрд╕рддреЛ.

рдордЧ рдирд┐рдХрд╛рд▓ рд╕реВрдЪрдирд╛ рдлрд▓рдХрд╛рд╡рд░ рд▓рд╛рдЧрддреЛ. рд╕рдЧрд│реЗ рдПрдХрджрдо рдпреЗрддрд╛рдд. рд░рд╛рдВрдЧ рдлрд╛рдЯрдХрд╛рдмрд╛рд╣реЗрд░ рдЬрд╛рдКрди рд░рд╕реНрддреНрдпрд╛рдкрд░реНрдпрдВрдд рдкреЛрд╣реЛрдЪрддреЗ.

рдореБрдЦреНрдпрд╛рдзреНрдпрд╛рдкрд┐рдХрд╛ рджреАрдкрд┐рдХрд╛рд╕рдореЛрд░ рджреЛрди рдкрд░реНрдпрд╛рдп рдЖрд╣реЗрдд:

рдЖрдгрд┐ рдЖрдгрдЦреА рдПрдХ рдирд┐рдпрдо: рдЬрддреНрд░рд╛ рддрд┐рдЪреНрдпрд╛ рд╕рд░реНрд╡рд╛рдд рд╣рд│реВ рднрд╛рдЧрд╛рдЗрддрдХреАрдЪ рдЬрд▓рдж рдЕрд╕рддреЗ. рд╕рдЧрд│реНрдпрд╛ рджрд╣рд╛ рдЦрд┐рдбрдХреНрдпрд╛рдВрдирд╛ office рдЪреНрдпрд╛ рдПрдХрд╛рдЪ рдиреЛрдВрджрд╡рд╣реАрдЪреА рд╡рд╛рдЯ рдкрд╛рд╣рд╛рд╡реА рд▓рд╛рдЧрдд рдЕрд╕реЗрд▓ рддрд░ рджрд╣рд╛ рдЦрд┐рдбрдХреНрдпрд╛рдВрдЪрд╛ рдЙрдкрдпреЛрдЧ рд╣реЛрдд рдирд╛рд╣реА.

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

flowchart LR
    p["ЁЯСк parents<br/>40 тЖТ 2,000 per second"]
    subgraph up["ЁЯЫЛя╕П scale UP"]
      big["one bigger counter<br/>more CPU, more memory<br/>there is a biggest size"]
    end
    subgraph out["ЁЯкСЁЯкСЁЯкС scale OUT"]
      lb["тЪЦя╕П helper at the gate<br/>load balancer"]
      c1["counter 1"]
      c2["counter 2"]
      c3["counter тАж23"]
      lb --> c1
      lb --> c2
      lb --> c3
    end
    db["ЁЯУТ the one register<br/>database тАФ the slowest part?"]
    p --> big
    p --> lb
    big --> db
    c1 --> db
    c2 --> db
    c3 --> db

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

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

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг traffic рд╕рдкрд╛рдЯ рдирд╕рддреЗ. рдирд┐рдХрд╛рд▓рд╛рдЪрд╛ рджрд┐рд╡рд╕, sale, рдПрдЦрд╛рджреА рдмрд╛рддрдореА рдХрд┐рдВрд╡рд╛ TV рдЬрд╛рд╣рд┐рд░рд╛рдд рдПрдХрд╛ рдорд┐рдирд┐рдЯрд╛рдд рд╕рд╛рдорд╛рдиреНрдп load рдЪреНрдпрд╛ 50 рдкрдЯ load рдЖрдгреВ рд╢рдХрддреЗ. 40 req/s рд▓рд╛ рдареАрдХ рдЪрд╛рд▓рдгрд╛рд░реА site 2,000 рд▓рд╛ рдХреЛрд╕рд│рддреЗ тАФ рдЖрдзреА рд╣рд│реВ pages, рдордЧ errors, рдордЧ рдХрдзреАрдЪ рд░рд┐рдХрд╛рдореА рди рд╣реЛрдгрд╛рд░реА рд░рд╛рдВрдЧ. 50 рдкрдЯ рдореЛрдареЗ рдПрдХ machine рддреБрдореНрд╣реА рд╡рд┐рдХрдд рдШреЗрдК рд╢рдХрдд рдирд╛рд╣реА. App рдиреЗ рдкрд░рд╡рд╛рдирдЧреА рджрд┐рд▓реА рддрд░ рддреБрдореНрд╣реА 20 рд▓рд╣рд╛рди machines рдЖрдгрдЦреА рдЬреЛрдбреВ рд╢рдХрддрд╛. рд╣рд╛ рдХреЛрд░реНрд╕ app рд▓рд╛ рддреЗ рд╢рдХреНрдп рдХрд░рд╛рдпрд▓рд╛ рд╢рд┐рдХрд╡рддреЛ, рдПрдХрд╛ tier рдорд╛рдЧреВрди рджреБрд╕рд░рд╛.

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

scale/sim.py рдордзрд▓реЗ servers_needed(rps, per_server_rps, target_util=0.6) load рд▓рд╛ рдПрдХ server 60% рд╡рд░ рдЬрд┐рддрдХреЗ рдХрд░реВ рд╢рдХрддреЛ рддреНрдпрд╛рдиреЗ рднрд╛рдЧрддреЗ рдЖрдгрд┐ рд╡рд░рдЪреНрдпрд╛ рдкреВрд░реНрдгрд╛рдВрдХрд╛рдд рдиреЗрддреЗ: ceil(rps / (per_server_rps ├Ч 0.6)). scale/demo.py рдордзрд▓реЗ why() рддреНрдпрд╛рд▓рд╛ рдПрдХрд╛ server рд▓рд╛ 150 req/s (рдЙрджрд╛рд╣рд░рдгрд╛рдЪрд╛ рдЖрдХрдбрд╛) рдзрд░реВрди 40, 400 рдЖрдгрд┐ 2,000 req/s рд╕рд╛рдареА рд╡рд┐рдЪрд╛рд░рддреЗ. рддреБрдордЪрд╛ рд╕реНрд╡рддрдГрдЪрд╛ рдЖрдХрдбрд╛ load test рдордзреВрди рдпреЗрддреЛ (рдзрдбрд╛ 02).

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

python3 scale/demo.py why
python3 - <<'EOF'
import sys; sys.path.insert(0, "scale"); from sim import servers_needed
for per in (150, 300, 600):
    print(f"per server {per:>3} req/s тЖТ {servers_needed(2000, per):>2} servers for 2,000 req/s")
for u in (0.6, 0.8, 1.0):
    print(f"run each server at {u:.0%} тЖТ {servers_needed(2000, 150, u):>2} servers")
print("results x10 (20,000 req/s) тЖТ", servers_needed(20000, 150), "servers")
EOF
python3 scale/test_scale.py

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

why рд╣реЗ print рдХрд░рддреЗ:

      40 req/s at 150 req/s per server (run at 60%) тЖТ   1 server(s)
     400 req/s at 150 req/s per server (run at 60%) тЖТ   5 server(s)
    2000 req/s at 150 req/s per server (run at 60%) тЖТ  23 server(s)

рддреБрдордЪрд╛ snippet рд╣реЗ print рдХрд░рддреЛ:

per server 150 req/s тЖТ 23 servers for 2,000 req/s
per server 300 req/s тЖТ 12 servers for 2,000 req/s
per server 600 req/s тЖТ  6 servers for 2,000 req/s
run each server at 60% тЖТ 23 servers
run each server at 80% тЖТ 17 servers
run each server at 100% тЖТ 14 servers
results x10 (20,000 req/s) тЖТ 223 servers

Tests рд╢реЗрд╡рдЯреА 13/13 passed рджрд╛рдЦрд╡рддрд╛рдд.

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

рдореЛрдареНрдпрд╛ server рд▓рд╛ (300 рдХрд┐рдВрд╡рд╛ 600 req/s) рдХрдореА рдкреНрд░рддреА рд▓рд╛рдЧрддрд╛рдд тАФ рд╣реЗ scaling up. рддреНрдпрд╛рдЪ server рдЪреНрдпрд╛ рдЬрд╛рд╕реНрдд рдкреНрд░рддреА тАФ рд╣реЗ scaling out, рдЖрдгрд┐ рддреЗ 10├Ч рд▓рд╛ рд╕реБрджреНрдзрд╛ рдЪрд╛рд▓рдд рд░рд╛рд╣рддреЗ (223 servers). 100% рд╡рд░ рдЪрд╛рд▓рд╡рд▓реНрдпрд╛рдиреЗ рд╣рд┐рд╢реЛрдмрд╛рдд 9 servers рд╡рд╛рдЪрддрд╛рдд, рдкрдг рдЕрдЪрд╛рдирдХ рд╡рд╛рдвреАрд╕рд╛рдареА рдХрд┐рдВрд╡рд╛ рдЧреЗрд▓реЗрд▓реНрдпрд╛ server рд╕рд╛рдареА рдЬрд╛рдЧрд╛рдЪ рдЙрд░рдд рдирд╛рд╣реА.

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

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

On a real account тАФ рдПрдХрд╛ EC2 instance рд▓рд╛ scale up рдХрд░рдгреЗ рдореНрд╣рдгрдЬреЗ рддреЗ рдерд╛рдВрдмрд╡рдгреЗ, type рдмрджрд▓рдгреЗ рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ рд╕реБрд░реВ рдХрд░рдгреЗ (рддреНрдпрд╛ machine рдХрдбреВрди рдХрд╛рд╣реА рдорд┐рдирд┐рдЯреЗ рд╕реЗрд╡рд╛ рдирд╛рд╣реА):

aws ec2 stop-instances --instance-ids i-0123456789abcdef0
aws ec2 wait instance-stopped --instance-ids i-0123456789abcdef0
aws ec2 modify-instance-attribute --instance-id i-0123456789abcdef0 --instance-type '{"Value": "m7g.2xlarge"}'
aws ec2 start-instances --instance-ids i-0123456789abcdef0

Scaling out рдореНрд╣рдгрдЬреЗ load balancer рдорд╛рдЧрдЪреНрдпрд╛ Auto Scaling group рд╡рд░рдЪрд╛ рдПрдХ рдЖрдХрдбрд╛ (рдзрдбрд╛ 06):

aws autoscaling set-desired-capacity --auto-scaling-group-name school-api --desired-capacity 23

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдирд┐рдХрд╛рд▓рд╛рдЪреНрдпрд╛ рджрд┐рд╡рд╕рд╛рдЖрдзреА рдкреНрд░рддреНрдпреЗрдХ tier рд╕рд╛рдареА рдПрдХ рдУрд│ рд▓рд┐рд╣рд╛: "UI тАж рдиреЗ scale рд╣реЛрддреЛ, API тАж рдиреЗ scale рд╣реЛрддреЛ, database тАж рдиреЗ scale рд╣реЛрддреЛ". рдЬреНрдпрд╛ tier рд▓рд╛ рдЙрддреНрддрд░ рдирд╛рд╣реА рддреЛрдЪ рдЖрдзреА рдХреЛрд╕рд│рддреЛ.

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

"рд╕реЗрдХрдВрджрд╛рд▓рд╛ 2,000" рдЖрдгрд┐ "рдПрдХрд╛ server рд▓рд╛ 150" рд╣реЗ рдЖрдХрдбреЗ рдЖрд╣реЗрдд. рдЦрд░реЗ рдЖрдХрдбреЗ рдХреБрдареВрди рдпреЗрддрд╛рдд? рдмрд╛рдВрдзрдгреНрдпрд╛рдЖрдзреА рдореЛрдЬрд╛.

git checkout lesson-02-measuring-load

ЁЯОк Lesson 01 тАФ Why scaling: results day at the school fair

ЁЯУН You are here: Lesson 01 of 13 ┬╖ Next: lesson-02-measuring-load


ЁЯУж What's in this branch

The one problem this whole course solves: on a normal day the school website gets 40 visits a second. On results day it gets 2,000. The site must stay fast for everyone тАФ the page (the UI), the API behind it, and the database behind that. Real files you will use all the way through:

ЁЯОТ Before you start: you need Python 3 and nothing else тАФ no AWS account, no pip install. sim.py holds teaching models with round example numbers (150 requests a second per server, a 2-minute warm-up, a 200 ms Lambda). Real systems add network jitter, retries and limits тАФ load-test the real thing (lesson 02) before you trust a number. Commands marked on a real account need the AWS CLI (or Terraform / kubectl) and credentials, and they can cost money.

ЁЯзТ Explain like I'm 5

Every year the school holds a fair on results day. On a normal day a few parents come to the office. One clerk at one counter is enough.

Then the results go up on the notice board. Everyone comes at once. The queue goes out of the gate and down the road.

The head teacher, Dipika, has two choices:

And one more rule: the fair is only as fast as its slowest part. Ten counters do not help if all of them must wait for the one office register.

ЁЯЧ║я╕П Diagram

flowchart LR
    p["ЁЯСк parents<br/>40 тЖТ 2,000 per second"]
    subgraph up["ЁЯЫЛя╕П scale UP"]
      big["one bigger counter<br/>more CPU, more memory<br/>there is a biggest size"]
    end
    subgraph out["ЁЯкСЁЯкСЁЯкС scale OUT"]
      lb["тЪЦя╕П helper at the gate<br/>load balancer"]
      c1["counter 1"]
      c2["counter 2"]
      c3["counter тАж23"]
      lb --> c1
      lb --> c2
      lb --> c3
    end
    db["ЁЯУТ the one register<br/>database тАФ the slowest part?"]
    p --> big
    p --> lb
    big --> db
    c1 --> db
    c2 --> db
    c3 --> db

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

тЭУ What

ЁЯдФ Why

Because traffic is not flat. Results day, a sale, a news story or a TV advert can bring 50 times the normal load in one minute. A site that is fine at 40 req/s fails at 2,000 тАФ slow pages first, then errors, then a queue that never empties. You cannot buy one machine that is 50 times bigger. You can add 20 more small ones, if the app allows it. This course is about making the app allow it, tier by tier.

ЁЯФз How (in this repo)

servers_needed(rps, per_server_rps, target_util=0.6) in scale/sim.py divides the load by what one server can do at 60% and rounds up: ceil(rps / (per_server_rps ├Ч 0.6)). why() in scale/demo.py asks it for 40, 400 and 2,000 req/s with 150 req/s per server тАФ an example number. Your own number comes from a load test (lesson 02).

ЁЯзк Try it

python3 scale/demo.py why
python3 - <<'EOF'
import sys; sys.path.insert(0, "scale"); from sim import servers_needed
for per in (150, 300, 600):
    print(f"per server {per:>3} req/s тЖТ {servers_needed(2000, per):>2} servers for 2,000 req/s")
for u in (0.6, 0.8, 1.0):
    print(f"run each server at {u:.0%} тЖТ {servers_needed(2000, 150, u):>2} servers")
print("results x10 (20,000 req/s) тЖТ", servers_needed(20000, 150), "servers")
EOF
python3 scale/test_scale.py

тЬЕ Verify тАФ what you should see

why prints:

      40 req/s at 150 req/s per server (run at 60%) тЖТ   1 server(s)
     400 req/s at 150 req/s per server (run at 60%) тЖТ   5 server(s)
    2000 req/s at 150 req/s per server (run at 60%) тЖТ  23 server(s)

Your snippet prints:

per server 150 req/s тЖТ 23 servers for 2,000 req/s
per server 300 req/s тЖТ 12 servers for 2,000 req/s
per server 600 req/s тЖТ  6 servers for 2,000 req/s
run each server at 60% тЖТ 23 servers
run each server at 80% тЖТ 17 servers
run each server at 100% тЖТ 14 servers
results x10 (20,000 req/s) тЖТ 223 servers

The tests end with 13/13 passed.

ЁЯПБ What you just proved

A bigger server (300 or 600 req/s) needs fewer copies тАФ that is scaling up. More copies of the same server тАФ that is scaling out, and it keeps working at 10├Ч (223 servers). Running at 100% saves 9 servers in the arithmetic, but leaves no room for a spike or a lost server.

тЪая╕П Common mistakes

ЁЯПн In production

On a real account тАФ scaling up one EC2 instance means stopping it, changing the type and starting it again (a few minutes with no service from that machine):

aws ec2 stop-instances --instance-ids i-0123456789abcdef0
aws ec2 wait instance-stopped --instance-ids i-0123456789abcdef0
aws ec2 modify-instance-attribute --instance-id i-0123456789abcdef0 --instance-type '{"Value": "m7g.2xlarge"}'
aws ec2 start-instances --instance-ids i-0123456789abcdef0

Scaling out is a number on an Auto Scaling group behind a load balancer (lesson 06):

aws autoscaling set-desired-capacity --auto-scaling-group-name school-api --desired-capacity 23

ЁЯПн Why this matters in production: before results day, write down one line per tier: "the UI scales by тАж, the API scales by тАж, the database scales by тАж". A tier with no answer is the one that fails first.

тПня╕П Next

"2,000 a second" and "150 per server" are numbers. Where do real numbers come from? Measure before you build.

git checkout lesson-02-measuring-load
тЖР Course homeall lessonsNext тЖТmeasuring load

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