ЁЯУм рдзрдбрд╛ 12 тАФ Queues + рд╕рдВрдкреВрд░реНрдг рдЖрд░рд╛рдЦрдбрд╛: рдЧрд░реНрджреА gate рд╡рд░рдЪ рдЭреЗрд▓рд╛
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 13 рдкреИрдХреА рдзрдбрд╛ 12 ┬╖ рдорд╛рдЧреАрд▓: lesson-11-partitioning ┬╖ рдкреБрдвреАрд▓: lesson-13-surviving-failure
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ11, рдЖрдгрд┐ рд╢реЗрд╡рдЯрдЪреЗ рд╕рд╛рдзрди: request рдЖрдгрд┐ рд╣рд│реВ рдХрд╛рдо рдпрд╛рдВрдЪреНрдпрд╛рдордзреНрдпреЗ рдПрдХ queue (Amazon SQS),
backlog рдиреБрд╕рд╛рд░ scale рд╣реЛрдгрд╛рд▒реНрдпрд╛ workers рд╕рд╣ тАФ рдЖрдгрд┐ рдордЧ scale рдХреЗрд▓реЗрд▓реНрдпрд╛ web app рдЪрд╛ рд╕рдВрдкреВрд░реНрдг
рдЖрд░рд╛рдЦрдбрд╛. scale/demo.py рдордзрд▓реЗ queues() рдкреНрд░рдорд╛рдгрдкрддреНрд░рд╛рдВрдЪреНрдпрд╛ requests рдЪреА
рдПрдХ рдЧрд░реНрджреА queue рдордзреВрди рдкрд╛рдард╡рддреЗ, рдЖрдгрд┐ рдЕрдкрдпрд╢реА рдХрд╛рдо рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ рдкрд░рдд рдорд┐рд│рд╡рддрд╛ рдпреЗрдгреНрдпрд╛рд╕рд╛рдареА рдХрд╛рдп рд▓рд╛рдЧрддреЗ рддреЗ
рд╕рд╛рдВрдЧрддреЗ: at-least-once delivery, visibility timeout, DLQ рдЖрдгрд┐ idempotent workers.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдирд┐рдХрд╛рд▓рд╛рдирдВрддрд░ рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рд▓рдХрд╛рд▓рд╛ рдЫрд╛рдкрд▓реЗрд▓реЗ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рд╣рд╡реЗ рдЕрд╕рддреЗ. рдЫрдкрд╛рдИрд▓рд╛ рд╡реЗрд│ рд▓рд╛рдЧрддреЛ. рдЬрд░ рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рд▓рдХ рдЫрдкрд╛рдИ рд╣реЛрдИрдкрд░реНрдпрдВрдд рдЦрд┐рдбрдХреАрд╡рд░ рдерд╛рдВрдмрд▓рд╛, рддрд░ рд░рд╛рдВрдЧ рдХрдзреАрдЪ рдкреБрдвреЗ рд╕рд░рдХрдд рдирд╛рд╣реА.
рдореНрд╣рдгреВрди рджреАрдкрд┐рдХрд╛ tokens ЁЯОЯя╕П рд╡рд╛рдкрд░рддреЗ. рдкрд╛рд▓рдХ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдорд╛рдЧрддреЛ, рддреНрдпрд╛рд▓рд╛ рд▓рдЧреЗрдЪ token рдорд┐рд│рддреЛ, рдЖрдгрд┐ рддреЛ рдЬрддреНрд░реЗрдЪреА рдордЬрд╛ рдШреНрдпрд╛рдпрд▓рд╛ рдЬрд╛рддреЛ. Token рдПрдХрд╛ рдкреЗрдЯреАрдд рдЬрд╛рддреЛ. рдорд╛рдЧрдЪреНрдпрд╛ рдЦреЛрд▓реАрдд рдЫрдкрд╛рдИ рдХрд░рдгрд╛рд░реЗ рдкреЗрдЯреАрддреВрди рдПрдХреЗрдХ token рдШреЗрддрд╛рдд рдЖрдгрд┐ рдЫрд╛рдкрддрд╛рдд.
рддреАрди рд╕реЗрдХрдВрдж рджрд░ рд╕реЗрдХрдВрджрд╛рд▓рд╛ 800 рдкрд╛рд▓рдХ рдорд╛рдЧрдгреА рдХрд░рддрд╛рдд. 3 рдЫрдкрд╛рдИ рдХрд░рдгрд╛рд▒реНрдпрд╛рдВрд╕рд╣ рдкреЗрдЯреАрдд 1,500 tokens рдЬрдорддрд╛рдд рдЖрдгрд┐ рджрд╣рд╛ рд╕реЗрдХрдВрджрд╛рдВрдирдВрддрд░рд╣реА рддреА рд░рд┐рдХрд╛рдореА рд╣реЛрдд рдирд╛рд╣реА. рдореНрд╣рдгреВрди рджреАрдкрд┐рдХрд╛ рдПрдХ рдирд┐рдпрдо рдЬреЛрдбрддреЗ: "рдкреЗрдЯреАрддрд▓реНрдпрд╛ рдкреНрд░рддреНрдпреЗрдХ 100 tokens рдорд╛рдЧреЗ рдПрдХ рдЫрдкрд╛рдИ рдХрд░рдгрд╛рд░рд╛, рдЬрд╛рд╕реНрддреАрдд рдЬрд╛рд╕реНрдд 10". рдкреЗрдЯреА рднрд░рд▓реА рдХреА рдЫрдкрд╛рдИ рдХрд░рдгрд╛рд░реЗ рд╡рд╛рдврд╡рд▓реЗ рдЬрд╛рддрд╛рдд; рд░рд┐рдХрд╛рдореА рдЭрд╛рд▓реА рдХреА рддреЗ рдШрд░реА рдЬрд╛рддрд╛рдд. рдкреЗрдЯреА рдЧрд░реНрджреА рдЭреЗрд▓рддреЗ: requests рдЦрд┐рдбрдХреАрд╡рд░ рдЧрд░реНрджреА рдХрд░рдгреНрдпрд╛рдРрд╡рдЬреА рдкреЗрдЯреАрдд рдерд╛рдВрдмрддрд╛рдд.
рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдЫрд╛рдкрддрд╛рдирд╛ рдордзреНрдпреЗрдЪ рдЫрдкрд╛рдИ рдЕрдбрдХрд▓реА, рддрд░ рдХрд╛рд╣реА рд╡реЗрд│рд╛рдиреЗ token рдкреЗрдЯреАрдд рдкрд░рдд рдЬрд╛рддреЛ, рдЖрдгрд┐ рджреБрд╕рд░рд╛ рдЫрдкрд╛рдИ рдХрд░рдгрд╛рд░рд╛ рдкреБрдиреНрд╣рд╛ рдкреНрд░рдпрддреНрди рдХрд░рддреЛ. рдХрдзреА рдХрдзреА рддреЛрдЪ token рджреЛрдирджрд╛ рджрд┐рд▓рд╛ рдЬрд╛рддреЛ, рдореНрд╣рдгреВрди рдкреНрд░рддреНрдпреЗрдХ рдЫрдкрд╛рдИ рдХрд░рдгрд╛рд░рд╛ рдЖрдзреА рддрдкрд╛рд╕рддреЛ "рд╣реЗ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдЖрдзреАрдЪ рдЫрд╛рдкрд▓реЗ рдЖрд╣реЗ рдХрд╛?". рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рдЕрдкрдпрд╢реА рдард░рдгрд╛рд░рд╛ token рдПрдХрд╛ рдмрд╛рдЬреВрдЪреНрдпрд╛ рдкреЗрдЯреАрдд рдЬрд╛рддреЛ, рдореНрд╣рдгрдЬреЗ рдХреЛрдгреАрддрд░реА рддреЛ рдкрд╛рд╣реВ рд╢рдХреЗрд▓. Tokens рдкреЗрдЯреАрдд рдХрд╛рдпрдо рд░рд╛рд╣рдд рдирд╛рд╣реАрдд: рдХрд╛рд╣реА рджрд┐рд╡рд╕рд╛рдВрдирдВрддрд░ рдЬреБрдирд╛ token рдлреЗрдХреВрди рджрд┐рд▓рд╛ рдЬрд╛рддреЛ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
u["ЁЯСк parents"] --> api["ЁЯН│ API<br/>202 Accepted + token"]
api -->|"SendMessage"| q["ЁЯУм SQS queue<br/>backlog"]
q -->|"ReceiveMessage"| w["ЁЯЦия╕П workers<br/>1 per 100 waiting, max 10"]
w -->|"DeleteMessage when done"| q
q -.->|"failed too many times"| dlq["ЁЯзп dead-letter queue"]
m["ЁЯУК ApproximateNumberOfMessagesVisible"] -.->|"scale workers"| w
ЁЯЧ║я╕П рд░реЗрдЦрд╛рдЯрд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/scaling/lesson-diagrams.html#l12
тЭУ рдХрд╛рдп
- Queue тАФ рдХрд╛рдо рд╕реНрд╡реАрдХрд╛рд░рдгрд╛рд░рд╛ рднрд╛рдЧ рдЖрдгрд┐ рддреЗ рдХрд░рдгрд╛рд░рд╛ рднрд╛рдЧ рдпрд╛рдВрдЪреНрдпрд╛рдордзрд▓рд╛ buffer.
API рд▓рдЧреЗрдЪ рдЙрддреНрддрд░ рджреЗрддреЗ (
202 Accepted, рдирдВрддрд░ рддрдкрд╛рд╕рдгреНрдпрд╛рд╕рд╛рдареА рдПрдХрд╛ id рд╕рд╣); workers рдХрд╛рдо рдЖрдкрд▓реНрдпрд╛ рд╡реЗрдЧрд╛рдиреЗ рдХрд░рддрд╛рдд. - Amazon SQS тАФ AWS рдЪреА managed queue:
- Standard queue тАФ рдЦреВрдк рдЬрд╛рд╕реНрдд throughput, at-least-once delivery (рдПрдЦрд╛рджрд╛ message рджреЛрдирджрд╛ рдпреЗрдК рд╢рдХрддреЛ) рдЖрдгрд┐ рд╢рдХреНрдп рддрд┐рддрдХрд╛ рдХреНрд░рдо;
- FIFO queue (рдирд╛рд╡
.fifoрдиреЗ рд╕рдВрдкрддреЗ) тАФ message group рдордзреНрдпреЗ рдХреНрд░рдо рд░рд╛рдЦрд▓рд╛ рдЬрд╛рддреЛ рдЖрдгрд┐ duplicates рдХрд╛рдврд▓реЗ рдЬрд╛рддрд╛рдд, рдкрдг throughput рдХрдореА.
- At-least-once delivery тАФ standard queue рдкреНрд░рддреНрдпреЗрдХ message рдПрдХ рдХрд┐рдВрд╡рд╛ рдЕрдзрд┐рдХ рд╡реЗрд│рд╛ рдкреЛрд╣реЛрдЪрд╡рддреЗ. рддреЛрдЪ message рджреЛрди workers рдкрд░реНрдпрдВрдд, рдХрд┐рдВрд╡рд╛ рдПрдХрд╛рдЪ worker рдХрдбреЗ рджреЛрдирджрд╛ рдкреЛрд╣реЛрдЪреВ рд╢рдХрддреЛ. рддреНрдпрд╛рдЪреА рддрдпрд╛рд░реА рдареЗрд╡рд╛.
- Visibility timeout тАФ worker рд▓рд╛ message рдорд┐рд│рд╛рд▓рд╛ рдХреА SQS рддреЛ рдЗрддрдХрд╛ рд╡реЗрд│ рд▓рдкрд╡рддреЗ (default 30 рд╕реЗрдХрдВрдж). Worker рдиреЗ рддреЛ рд╡реЗрд│реЗрдд delete рдХреЗрд▓рд╛ рддрд░ рдХрд╛рдо рдЭрд╛рд▓реЗ; worker crash рдЭрд╛рд▓рд╛ рдХрд┐рдВрд╡рд╛ рдЦреВрдк рд╣рд│реВ рдЕрд╕рд▓рд╛, рддрд░ message рджреБрд╕рд▒реНрдпрд╛ worker рд╕рд╛рдареА рдкреБрдиреНрд╣рд╛ рджрд┐рд╕реВ рд▓рд╛рдЧрддреЛ. рдХрд╛рдорд╛рд▓рд╛ рд▓рд╛рдЧрдгрд╛рд▒реНрдпрд╛ рд╡реЗрд│реЗрдкреЗрдХреНрд╖рд╛ рддреЛ рдЬрд╛рд╕реНрдд рдареЗрд╡рд╛.
- Retries тАФ delete рди рдЭрд╛рд▓реЗрд▓рд╛ message рдкрд░рдд рдпреЗрддреЛ рдЖрдгрд┐ рдкреБрдиреНрд╣рд╛ рдкреНрд░рдпрддреНрди рд╣реЛрддреЛ. рдкреНрд░рддреНрдпреЗрдХ receive рддреНрдпрд╛рдЪреНрдпрд╛ receive count рдордзреНрдпреЗ 1 рдЪреА рднрд░ рдШрд╛рд▓рддреЛ.
- Dead-letter queue (DLQ) тАФ redrive policy рд╕рд╛рдВрдЧрддреЗ:
maxReceiveCountreceives рдирдВрддрд░ message DLQ рдордзреНрдпреЗ рд╣рд▓рд╡рд╛. рдордЧ рдПрдХ рдЦрд░рд╛рдм (poison) message workers рдирд╛ рдЕрдбрд╡рдд рдирд╛рд╣реА, рдЖрдгрд┐ рдПрдЦрд╛рджреА рд╡реНрдпрдХреНрддреА рддреЛ рдкрд╛рд╣реВрди, рджреБрд░реБрд╕реНрддреАрдирдВрддрд░ рддреНрдпрд╛рд▓рд╛ source queue рдордзреНрдпреЗ рдкрд░рдд redrive рдХрд░реВ рд╢рдХрддреЗ. DLQ рд▓рд╛ source queue рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд retention рджреНрдпрд╛, рдореНрд╣рдгрдЬреЗ рдмрд╛рдЬреВрд▓рд╛ рдареЗрд╡рд▓реЗрд▓реЗ messages рдХреЛрдгреА рдкрд╛рд╣рдгреНрдпрд╛рдЖрдзреА expire рд╣реЛрдд рдирд╛рд╣реАрдд. - Message retention тАФ message queue рдордзреНрдпреЗ default 4 рджрд┐рд╡рд╕ рд░рд╛рд╣рддреЛ, рдЖрдгрд┐ рддреБрдореНрд╣реА рддреЛ
1 рдорд┐рдирд┐рдЯрд╛рдкрд╛рд╕реВрди 14 рджрд┐рд╡рд╕рд╛рдВрдкрд░реНрдпрдВрдд рдареЗрд╡реВ рд╢рдХрддрд╛. рддреНрдпрд╛рдирдВрддрд░ рддреЛ delete рд╣реЛрддреЛ, рдХрд╛рдо рдЭрд╛рд▓реЗ рдЕрд╕реЛ рд╡рд╛
рдирд╕реЛ. рд╕рд░реНрд╡рд╛рдд рдЬреБрдиреНрдпрд╛ message рдЪреЗ рд╡рдп рдкрд╛рд╣рд╛ (
ApproximateAgeOfOldestMessage). - Idempotent worker тАФ рддреЛрдЪ message рджреЛрдирджрд╛ рдХреЗрд▓рд╛ рддрд░реА рдкрд░рд┐рдгрд╛рдо рдПрдХрджрд╛ рдХреЗрд▓реНрдпрд╛рд╕рд╛рд░рдЦрд╛рдЪ (рдЖрдзреА рддрдкрд╛рд╕рд╛ "рдкреНрд░рдорд╛рдгрдкрддреНрд░ рдЖрдзреАрдЪ рдмрдирд▓реЗ рдЖрд╣реЗ рдХрд╛?"). At-least-once delivery рдореБрд│реЗ рд╣реЗ рдЖрд╡рд╢реНрдпрдХ рдЖрд╣реЗ.
- рд╕рдЧрд│реЗ рдПрдХрддреНрд░: queue рдЧрд░реНрджреА рдЭреЗрд▓рддреЗ; workers messages asynchronously рд╣рд╛рддрд╛рд│рддрд╛рдд. Retries, DLQ рдЖрдгрд┐ idempotent consumers рдЕрд╕рддреАрд▓ рддрд░ рдЕрдкрдпрд╢реА рдХрд╛рдо рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ рдкрд░рдд рдорд┐рд│рд╡рддрд╛ рдпреЗрддреЗ.
- Backlog рдиреБрд╕рд╛рд░ scale тАФ workers рд╕рд╛рдареАрдЪрд╛ рд╕рдВрдХреЗрдд рдореНрд╣рдгрдЬреЗ
ApproximateNumberOfMessagesVisible, рдХрд┐рдВрд╡рд╛ рддреНрдпрд╛рд╣реВрди рдЪрд╛рдВрдЧрд▓рд╛ рдкреНрд░рддреНрдпреЗрдХ worker рдорд╛рдЧрдЪрд╛ backlog (messages ├╖ workers), рдПрдХ worker рд╕реНрд╡реАрдХрд╛рд░рд╛рд░реНрд╣ рд╡реЗрд│реЗрдд рдХрд┐рддреА рд╕рдВрдкрд╡реВ рд╢рдХрддреЛ рддреНрдпрд╛рдЪреНрдпрд╛рд╢реА рддреБрд▓рдирд╛ рдХрд░реВрди. Kubernetes рд╕рд╛рдареА рд╣реЗ KEDA рдХрд░рддреЗ; EC2 Auto Scaling group backlog-per-instance metric рд╡рд░ target-track рдХрд░реВ рд╢рдХрддреЛ; SQS event source рдЕрд╕рд▓реЗрд▓реЗ Lambda function рдЖрдкрд▓реЗ pollers рдЖрдкреЛрдЖрдк scale рдХрд░рддреЗ.
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рдХрд╛рд╣реА рдХрд╛рдо рдПрдЦрд╛рджреНрдпрд╛ рдкрд╛рдирд╛рд▓рд╛ рд▓рд╛рдЧрд╛рд╡рд╛ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рд╣рд│реВ рдЕрд╕рддреЗ, рдЖрдгрд┐ рдЧрд░реНрджреА servers рдЬреЛрдбрд╛рдпрд▓рд╛ рд▓рд╛рдЧрдгрд╛рд▒реНрдпрд╛ рд╡реЗрд│реЗрдкреЗрдХреНрд╖рд╛ рдХрдореА рдХрд╛рд│ рдЯрд┐рдХрддреЗ. Queue "3 рд╕реЗрдХрдВрджрд╛рдВрдд 2,400 requests" рдЪреЗ "рдкреБрдврдЪреНрдпрд╛ рдХрд╛рд╣реА рд╕реЗрдХрдВрджрд╛рдВрдд рдкреВрд░реНрдг рдЭрд╛рд▓реЗрд▓реА 2,400 рдХрд╛рдореЗ" рдХрд░рддреЗ. рдкреБрдврдЪрд╛ рднрд╛рдЧ рдЬрд▓рдж рд░рд╛рд╣рддреЛ, рдЖрдгрд┐ рдорд╛рдЧрдЪрд╛ рднрд╛рдЧ рддреНрдпрд╛рд▓рд╛ рдЭреЗрдкреЗрд▓ рдЕрд╢рд╛ рд╡реЗрдЧрд╛рдиреЗ рдЪрд╛рд▓рддреЛ. рд╣реА рдЬрд╛рджреВ рдирд╛рд╣реА: message рддрд░реАрд╣реА expire рд╣реЛрдК рд╢рдХрддреЛ, рдХрд┐рдВрд╡рд╛ рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА рдЕрдкрдпрд╢реА рдард░реВ рд╢рдХрддреЛ. Retries, DLQ рдЖрдгрд┐ idempotent workers рдЕрд╕рддреАрд▓ рддрд░ рддреЗ рдЕрдкрдпрд╢реА рдХрд╛рдо crash рдордзреНрдпреЗ рд╣рд░рд╡рдгреНрдпрд╛рдРрд╡рдЬреА рдЬрдкрд▓реЗ рдЬрд╛рддреЗ рдЖрдгрд┐ рд╕реБрд░рдХреНрд╖рд┐рддрдкрдгреЗ рдкрд░рдд рдорд┐рд│рд╡рддрд╛ рдпреЗрддреЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
scale/sim.py рдордзрд▓реЗ drain(arrivals, per_worker, workers_for) рдПрдХреЗрдХ рд╕реЗрдХрдВрдж
рдЪрд╛рд▓рд╡рддреЗ: рддреЗ workers_for(backlog) рд▓рд╛ рдХрд┐рддреА workers рдЪрд╛рд▓рд╡рд╛рдпрдЪреЗ рддреЗ рд╡рд┐рдЪрд╛рд░рддреЗ тАФ рдпрд╛ рд╕реЗрдХрдВрджрд╛рдЪреЗ arrivals
рдпреЗрдгреНрдпрд╛рдЖрдзреАрдЪреНрдпрд╛ backlog рд╡рд░реВрди рдард░рд╡рд▓реЗрд▓реЗ, рдЬрд╕реЗ рдЦрд▒реНрдпрд╛ autoscaler рд▓рд╛ metric рдереЛрдбрд╛ рдЙрд╢рд┐рд░рд╛ рджрд┐рд╕рддреЛ
тАФ arrivals рдЬреЛрдбрддреЗ, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ worker рд▓рд╛ per_worker рдХрд╛рдореЗ рдкреВрд░реНрдг рдХрд░реВ рджреЗрддреЗ. рдкреНрд░рддреНрдпреЗрдХ row рдореНрд╣рдгрдЬреЗ (second,
arrived, workers, done, backlog). queues() рдард░рд▓реЗрд▓реНрдпрд╛ 3 workers рдЪреА рддреБрд▓рдирд╛ "рдкреНрд░рддреНрдпреЗрдХ 100 рдерд╛рдВрдмрд▓реЗрд▓реНрдпрд╛рдВрдорд╛рдЧреЗ
рдПрдХ worker, рдХрд┐рдорд╛рди 1, рдЬрд╛рд╕реНрддреАрдд рдЬрд╛рд╕реНрдд 10" рд╢реА рдХрд░рддреЗ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 scale/demo.py queues
python3 - <<'EOF'
import sys; sys.path.insert(0, "scale"); from sim import drain
arrivals = [50, 800, 800, 800, 200, 50, 50, 50, 50, 50]
for name, rule in (("fixed 3", lambda b: 3), ("fixed 8", lambda b: 8), ("1 per 100 waiting, max 10", lambda b: min(10, max(1, -(-b // 100)))),
("1 per 100 waiting, max 20", lambda b: min(20, max(1, -(-b // 100)))), ("1 per 50 waiting, max 20", lambda b: min(20, max(1, -(-b // 50))))):
rows = drain(arrivals, 100, rule)
print(f"{name:<26} peak backlog {max(r[4] for r in rows):>5} ┬╖ most workers {max(r[2] for r in rows):>2} ┬╖ left after 10 s {rows[-1][4]:>4}")
for s, a, w, d, b in drain(arrivals, 100, lambda b: min(10, max(1, -(-b // 100)))):
print(f"second {s}: arrived {a:>3}, workers {w:>2}, done {d:>4}, waiting {b:>4}")
EOF
python3 scale/test_scale.py
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
queues рд╣реЗ рдЫрд╛рдкрддреЗ:
fixed 3 workers peak backlog 1500 ┬╖ left after 10 s 150
scale on backlog (1 worker per 100 waiting, max 10) peak backlog 800 ┬╖ left after 10 s 0
the queue (SQS) absorbs the burst; workers process messages asynchronously, at their own pace
SQS delivers at least once: a visibility timeout, retries, a DLQ and idempotent workers make failed work safe to recover
рддреБрдордЪрд╛ snippet рд╣реЗ рдЫрд╛рдкрддреЛ:
fixed 3 peak backlog 1500 ┬╖ most workers 3 ┬╖ left after 10 s 150
fixed 8 peak backlog 0 ┬╖ most workers 8 ┬╖ left after 10 s 0
1 per 100 waiting, max 10 peak backlog 800 ┬╖ most workers 8 ┬╖ left after 10 s 0
1 per 100 waiting, max 20 peak backlog 800 ┬╖ most workers 8 ┬╖ left after 10 s 0
1 per 50 waiting, max 20 peak backlog 700 ┬╖ most workers 14 ┬╖ left after 10 s 0
second 0: arrived 50, workers 1, done 50, waiting 0
second 1: arrived 800, workers 1, done 100, waiting 700
second 2: arrived 800, workers 7, done 700, waiting 800
second 3: arrived 800, workers 8, done 800, waiting 800
second 4: arrived 200, workers 8, done 800, waiting 200
second 5: arrived 50, workers 2, done 200, waiting 50
second 6: arrived 50, workers 1, done 100, waiting 0
second 7: arrived 50, workers 1, done 50, waiting 0
second 8: arrived 50, workers 1, done 50, waiting 0
second 9: arrived 50, workers 1, done 50, waiting 0
Tests тЬЕ L12 a queue absorbs the burst and drains to zero рдЖрдгрд┐ 13/13 passed рдиреЗ рд╕рдВрдкрддрд╛рдд.
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
Model рдордзреНрдпреЗ рдкреНрд░рддреНрдпреЗрдХ request queue рдордзреНрдпреЗ рдерд╛рдВрдмрд▓реА рдЖрдгрд┐ рдирдВрддрд░ рдкреВрд░реНрдг рдЭрд╛рд▓реА. Backlog рдиреБрд╕рд╛рд░ scaling рдиреЗ рдЧрд░реНрджреА рд╕реЗрдХрдВрдж 6 рдкрд░реНрдпрдВрдд рд╕рдВрдкрд╡рд▓реА рдЖрдгрд┐ рдкрд░рдд 1 worker рд╡рд░ рдЖрд▓реЗ; рдард░рд▓реЗрд▓реЗ 3 workers 10 рд╕реЗрдХрдВрджрд╛рдВрдирдВрддрд░рд╣реА 150 рдиреЗ рдорд╛рдЧреЗ рд╣реЛрддреЗ. рдард░рд▓реЗрд▓реЗ 8 workers backlog рддрдпрд╛рд░рдЪ рд╣реЛрдК рджреЗрдд рдирд╛рд╣реАрдд тАФ рдкрдг рджрд┐рд╡рд╕рднрд░ 8 workers рдЪреЗ рдкреИрд╕реЗ рдореЛрдЬрддрд╛рдд. рдХрдорд╛рд▓ 10 рд╡рд░реВрди 20 рдХреЗрд▓реНрдпрд╛рдиреЗ рдХрд╛рд╣реАрдЪ рдмрджрд▓рд▓реЗ рдирд╛рд╣реА, рдХрд╛рд░рдг рдирд┐рдпрдорд╛рдиреЗ рдХрдзреАрдЪ 8 рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдорд╛рдЧрд┐рддрд▓реЗ рдирд╛рд╣реАрдд; рдЬрд╛рд╕реНрдд рдЙрддреНрд╕реБрдХ рдирд┐рдпрдорд╛рдиреЗ (рдкреНрд░рддреНрдпреЗрдХ 50 рдорд╛рдЧреЗ 1) 14 рдкрд░реНрдпрдВрдд workers рд╡рд╛рдкрд░рд▓реЗ рдЖрдгрд┐ peak рдереЛрдбреЗ рдХрдореА рдареЗрд╡рд▓реЗ. рдЖрдгрд┐ рдЧрд░реНрджреАрдЪрд╛ рдкрд╣рд┐рд▓рд╛ рд╕реЗрдХрдВрдж рдиреЗрд╣рдореАрдЪ рд╣рд│реВ рдЕрд╕рддреЛ: autoscaler рд▓рд╛ backlog рддреЛ рддрдпрд╛рд░ рдЭрд╛рд▓реНрдпрд╛рдирдВрддрд░рдЪ рджрд┐рд╕рддреЛ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- user рд▓рд╛ рдЖрддреНрддрд╛рдЪ рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ рдЕрд╢рд╛ рдХрд╛рдорд╛рд╕рд╛рдареА queue (рдкрд╛рдирд╛рдЪреЗ рдЙрддреНрддрд░) тАФ queues рдереЛрдбреНрдпрд╛ рд╡реЗрд│рд╛рдиреЗ рдкреВрд░реНрдг рд╣реЛрдК рд╢рдХрдгрд╛рд▒реНрдпрд╛ рдХрд╛рдорд╛рд╕рд╛рдареА рдЕрд╕рддрд╛рдд, рдЖрдгрд┐ UI рдиреЗ рддрд╕реЗ рд╕рд╛рдВрдЧрд┐рддрд▓реЗ рдкрд╛рд╣рд┐рдЬреЗ ("рддреБрдордЪреЗ рдкреНрд░рдорд╛рдгрдкрддреНрд░ рддрдпрд╛рд░ рд╣реЛрдд рдЖрд╣реЗ")
- рдХрд╛рдорд╛рдкреЗрдХреНрд╖рд╛ рдХрдореА visibility timeout тАФ рдХрд╛рдо рдЪрд╛рд▓реВ рдЕрд╕рддрд╛рдирд╛рдЪ message рдкрд░рдд рдпреЗрддреЛ, рдЖрдгрд┐ рддреЗ рджреЛрдирджрд╛ рд╣реЛрддреЗ
- idempotent рдирд╕рд▓реЗрд▓реЗ workers тАФ at-least-once delivery рдореБрд│реЗ рджреЛрди рдкреНрд░рдорд╛рдгрдкрддреНрд░реЗ рдЬрд╛рддрд╛рдд
- dead-letter queue рдирд╛рд╣реА тАФ рдПрдХ рдмрд┐рдШрдбрд▓реЗрд▓рд╛ message expire рд╣реЛрдИрдкрд░реНрдпрдВрдд рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рдкреНрд░рдпрддреНрдирд╛рдд рд░рд╛рд╣рддреЛ, рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рд╡реЗрд│реА рдПрдХ worker рд╡рд╛рдкрд░рддреЛ
- рджрд┐рд╡рд╕реЗрдВрджрд┐рд╡рд╕ рд╡рд╛рдврдгрд╛рд░рд╛ backlog тАФ retention рдХрд╛рд│рд╛рдкреЗрдХреНрд╖рд╛ (default 4 рджрд┐рд╡рд╕) рдЬреБрдиреЗ messages delete рд╣реЛрддрд╛рдд, рдХрд╛рдо рдЭрд╛рд▓реЗ рдЕрд╕реЛ рд╡рд╛ рдирд╕реЛ
- backlog рдРрд╡рдЬреА CPU рдиреБрд╕рд╛рд░ workers scale рдХрд░рдгреЗ
- рдорд╛рдЧрдЪрд╛ database рдЭреЗрд▓реВ рд╢рдХрддреЛ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд▓рдж scale рд╣реЛрдгрд╛рд░реЗ workers (рдзрдбрд╛ 10)
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
рдЦрд▒реНрдпрд╛ account рд╡рд░ тАФ dead-letter queue рд╕рд╣ рдПрдХ queue (queue messages 4 рджрд┐рд╡рд╕ рдареЗрд╡рддреЗ, DLQ 14 рджрд┐рд╡рд╕; 5 receives рдирдВрддрд░ message DLQ рдордзреНрдпреЗ рдЬрд╛рддреЛ):
aws sqs create-queue --queue-name certificates-dlq --attributes '{"MessageRetentionPeriod": "1209600"}'
aws sqs create-queue --queue-name certificates --attributes '{
"VisibilityTimeout": "120",
"MessageRetentionPeriod": "345600",
"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:ap-south-1:111122223333:certificates-dlq\",\"maxReceiveCount\":\"5\"}"
}'
aws sqs get-queue-attributes --attribute-names ApproximateNumberOfMessagesVisible \
--queue-url https://sqs.ap-south-1.amazonaws.com/111122223333/certificates
Kubernetes рд╡рд░ KEDA тАФ рдкреНрд░рддреНрдпреЗрдХ 100 рдерд╛рдВрдмрд▓реЗрд▓реНрдпрд╛ messages рдорд╛рдЧреЗ рд╕реБрдорд╛рд░реЗ рдПрдХ worker pod, 1 рддреЗ 10:
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata: { name: certificate-workers }
spec:
scaleTargetRef: { name: certificate-worker }
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: aws-sqs-queue
authenticationRef: { name: keda-aws }
metadata:
queueURL: https://sqs.ap-south-1.amazonaws.com/111122223333/certificates
queueLength: "100"
awsRegion: ap-south-1
ЁЯПЧя╕П рд╕рдВрдкреВрд░реНрдг рдЖрд░рд╛рдЦрдбрд╛ тАФ scale рдХреЗрд▓реЗрд▓реА рдЬрддреНрд░рд╛
flowchart LR
u["ЁЯСк parents"] --> cf["ЁЯМН CloudFront<br/>UI from S3 ┬╖ micro-cache ┬╖ shield"]
cf -->|"/api"| lb["тЪЦя╕П ALB or API Gateway"]
lb --> api["ЁЯН│ stateless API<br/>ASG ┬╖ pods + HPA/Karpenter ┬╖ Lambda"]
api --> rc["ЁЯУМ Redis / Valkey"]
api --> px["ЁЯЫОя╕П RDS Proxy"]
px --> pri["ЁЯУТ primary"]
px --> rep["ЁЯУЪ replicas"]
api --> ddb["ЁЯЧВя╕П DynamoDB<br/>keys that spread"]
api --> q["ЁЯУм SQS"] --> wk["ЁЯЦия╕П workers<br/>scale on backlog"]
| рд╕реНрддрд░ | рдХрд╢рд╛рдиреЗ scale рд╣реЛрддреЛ | рдХрд╛рдп рдкрд╛рд╣рд╛рдпрдЪреЗ |
|---|---|---|
| UI | CloudFront edges, versioned files, рдЧрд░реНрджреАрдЪреНрдпрд╛ рдкрд╛рдирд╛рдВрд╡рд░ s-maxage |
cache hit rate, origin requests |
| API | load balancer рдорд╛рдЧреЗ stateless рдкреНрд░рддреА: ASG, HPA + Karpenter, рдХрд┐рдВрд╡рд╛ Lambda | p99 latency, 5xx, concurrency, Pending pods |
| Reads | Redis cache-aside, read replicas | hit rate, ReplicaLag |
| Connections | RDS Proxy / рдПрдХ pool | DatabaseConnections рд╡рд┐рд░реБрджреНрдз max_connections |
| Writes | рдкрд╕рд░рдгрд╛рд▒реНрдпрд╛ key рд╕рд╣ partitions | throttled requests, hot keys |
| рд╣рд│реВ рдХрд╛рдо | SQS + backlog рдиреБрд╕рд╛рд░ workers | ApproximateNumberOfMessagesVisible, DLQ depth |
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдкреНрд░рддреНрдпреЗрдХ рд╕реНрддрд░ рд╕реНрд╡рддрдГрдЪреНрдпрд╛ рд╕рдВрдХреЗрддрд╛рдиреБрд╕рд╛рд░ scale рд╣реЛрддреЛ. рдореЛрдареНрдпрд╛ рджрд┐рд╡рд╕рд╛рдЖрдзреА рд╕рдВрдкреВрд░реНрдг рдорд╛рд░реНрдЧрд╛рдЪрд╛ load-test рдХрд░рд╛ (рдзрдбрд╛ 02), рдорд╛рд╣реАрдд рдЕрд╕рд▓реЗрд▓рд╛ spike schedule рдХрд░рд╛ (рдзрдбреЗ 06, 08), рдЖрдгрд┐ API рд╕реНрддрд░ рдЖрддрд╛ рдЬреЗ рдкрд╛рдард╡реЗрд▓ рддреЗ database рд╕реНрддрд░ тАФ cache, replicas, proxy, partitions, queue тАФ рдЭреЗрд▓реВ рд╢рдХрддреЛ рдпрд╛рдЪреА рдЦрд╛рддреНрд░реА рдХрд░рд╛.
тПня╕П рдкреБрдвреЗ
рдЬрддреНрд░рд╛ рдЖрддрд╛ рд╕реНрддрд░рд╛рдиреБрд╕рд╛рд░ рд╡рд╛рдвреВ рд╢рдХрддреЗ. рдкрдг рдореЛрдареНрдпрд╛ рдЬрддреНрд░реЗрдд рдЬрд╛рд╕реНрдд рднрд╛рдЧ рдЕрд╕рддрд╛рдд, рдЖрдгрд┐ рднрд╛рдЧ рдмрд┐рдШрдбрддрд╛рдд: рдПрдЦрд╛рджреА рд╣рд│реВ service, рдЕрдбрдХрд▓реЗрд▓рд╛ database, рд╣рд░рд╡рд▓реЗрд▓реА рдЗрдорд╛рд░рдд. рд╢реЗрд╡рдЯрдЪрд╛ рдзрдбрд╛: рдмрд┐рдШрд╛рдбрд╛рддреВрди рдЯрд┐рдХрдгреЗ тАФ timeouts, рд╕рднреНрдп retries, breaker switch рдЖрдгрд┐ рддреАрди рдЗрдорд╛рд░рддреА.
git checkout lesson-13-surviving-failure