ЁЯУм рдзрдбрд╛ 07 тАФ Queues рдЖрдгрд┐ async рдХрд╛рдо: рдкрдЯрдХрди рдЙрддреНрддрд░ рджреНрдпрд╛, рд╕рд╛рд╡рдХрд╛рд╢ рдХрд╛рдо рдирдВрддрд░ рдХрд░рд╛
ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 18 рдкреИрдХреА рдзрдбрд╛ 07 ┬╖ рдорд╛рдЧреЗ: lesson-06-load-balancing ┬╖ рдкреБрдвреЗ: lesson-08-events
ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ
рдзрдбреЗ 01тАУ06, рдЖрдгрд┐ queue. рдПрдХ рддрд╛рддрдбреАрдЪреА рд╕реВрдЪрдирд╛ 5 million рдкрд╛рд▓рдХрд╛рдВрдкрд░реНрдпрдВрдд SMS рдиреЗ рдкреЛрд╣реЛрдЪрд╛рдпрд▓рд╛ рд╣рд╡реА тАФ
рддреЗ рдХрд╛рдо рд╢рд┐рдХреНрд╖рд┐рдХреЗрдЪреНрдпрд╛ request рдЪреНрдпрд╛ рдЖрдд рдЪрд╛рд▓рддрд╛ рдХрд╛рдорд╛ рдирдпреЗ. Request рд╕реВрдЪрдирд╛ save рдХрд░рддреЛ, queue рд╡рд░
рдПрдХ job рдареЗрд╡рддреЛ рдЖрдгрд┐ 201 рдЙрддреНрддрд░ рджреЗрддреЛ. Workers jobs рдШреЗрддрд╛рдд, batches рдордзреНрдпреЗ рдкрд╛рдард╡рддрд╛рдд, backoff рд╕рд╣
retry рдХрд░рддрд╛рдд рдЖрдгрд┐ рдЕрдкрдпрд╢реА jobs dead-letter queue (DLQ) рдордзреНрдпреЗ рдареЗрд╡рддрд╛рдд. Delivery
at-least-once рдЕрд╕рддреЗ, рдореНрд╣рдгреВрди рдкреНрд░рддреНрдпреЗрдХ consumer idempotent рдЕрд╕рд╛рдпрд▓рд╛ рд╣рд╡рд╛.
design/demo.py рдордзреАрд▓ queues() workers рдЪреА рд╕рдВрдЦреНрдпрд╛ рд╡реЗрдЧ рдХрд╕рд╛ рдард░рд╡рддреЗ рддреЗ рджрд╛рдЦрд╡рддреЗ.
ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ
рдПрдХ рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рддрд╛рддрдбреАрдЪреА рд╕реВрдЪрдирд╛ рдШреЗрдКрди рдпреЗрддреЗ: "рдЙрджреНрдпрд╛ рд╢рд╛рд│рд╛ рдмрдВрдж тАФ рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рд▓рдХрд╛рд▓рд╛ рдХрд│рд╡рд╛." рдЦрд┐рдбрдХреАрд╡рд░рдЪреНрдпрд╛ рдХрд╛рд░рдХреБрдирд╛рдиреЗ рд╕реНрд╡рддрдГрдЪ 5 million рдкрд╛рд▓рдХрд╛рдВрдирд╛ рдлреЛрди рдХреЗрд▓реЗ, рддрд░ рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рджрд┐рд╡рд╕реЗрдВрджрд┐рд╡рд╕ рдЦрд┐рдбрдХреАрд╡рд░ рдерд╛рдВрдмреВрди рд░рд╛рд╣реАрд▓, рдЖрдгрд┐ рддрд┐рдЪреНрдпрд╛ рдорд╛рдЧрдЪреА рд░рд╛рдВрдЧ рдлрд╛рдЯрдХрд╛рдмрд╛рд╣реЗрд░ рдЬрд╛рдИрд▓.
рдореНрд╣рдгреВрди рджреАрдкрд┐рдХрд╛ рдЦрд┐рдбрдХреАрд╡рд░ рдПрдХ рдЯреНрд░реЗ ЁЯУе рдареЗрд╡рддреЗ. рдХрд╛рд░рдХреВрди рдПрдХ рдЪрд┐рдареНрдареА рд▓рд┐рд╣рд┐рддреЗ тАФ "рд╕реВрдЪрдирд╛ 42 рдмрджреНрджрд▓ рдкреНрд░рддреНрдпреЗрдХ рдкрд╛рд▓рдХрд╛рд▓рд╛ рдлреЛрди рдХрд░рд╛" тАФ рддреА рдЯреНрд░реЗрдордзреНрдпреЗ рдЯрд╛рдХрддреЗ, рдЖрдгрд┐ рд╢рд┐рдХреНрд╖рд┐рдХреЗрд▓рд╛ рд╕рд╛рдВрдЧрддреЗ: "рдЭрд╛рд▓реЗ, рддреЗ рдорд╛рд░реНрдЧрд╛рд╡рд░ рдЖрд╣реЗ." рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рдПрдХрд╛ рдорд┐рдирд┐рдЯрд╛рдд рдирд┐рдШреВрди рдЬрд╛рддреЗ.
рдорд╛рдЧрдЪреНрдпрд╛ рдЦреЛрд▓реАрдд, рдорджрддрдиреАрд╕ рдЯреНрд░реЗрдордзреВрди рдЪрд┐рдареНрдареНрдпрд╛ рдШреЗрддрд╛рдд рдЖрдгрд┐ рдлреЛрди рдХрд░рддрд╛рдд. рдЬрд╛рд╕реНрдд рдорджрддрдиреАрд╕, рдЬрд▓рдж рдлреЛрди. рдПрдЦрд╛рджреА рдорджрддрдиреАрд╕ рдЪрд┐рдареНрдареА рдЕрд░реНрдзрд╡рдЯ рдЕрд╕рддрд╛рдирд╛ рдЪрдХреНрдХрд░ рдпреЗрдКрди рдкрдбрд▓реА, рддрд░ рдереЛрдбреНрдпрд╛ рд╡реЗрд│рд╛рдиреЗ рддреА рдЪрд┐рдареНрдареА рдкрд░рдд рдЯреНрд░реЗрдордзреНрдпреЗ рдЬрд╛рддреЗ, рдЖрдгрд┐ рджреБрд╕рд░реА рдорджрддрдиреАрд╕ рддреА рдШреЗрддреЗ тАФ рдореНрд╣рдгреВрди рдХрд╛рд╣реА рдкрд╛рд▓рдХрд╛рдВрдирд╛ рдлреЛрди рджреЛрдирджрд╛ рдпреЗрдК рд╢рдХрддреЛ. рдкреНрд░рддреНрдпреЗрдХ рдорджрддрдиреАрд╕ рдЖрдзреА рдПрдХ рдпрд╛рджреА рддрдкрд╛рд╕рдд рдЕрд╕реЗрд▓ рддрд░ рд╣реЗ рдареАрдХ рдЖрд╣реЗ: "рд╕реВрдЪрдирд╛ 42 рдмрджреНрджрд▓ рдпрд╛ рдкрд╛рд▓рдХрд╛рд▓рд╛ рдЖрдзреАрдЪ рдХреЛрдгреА рдлреЛрди рдХреЗрд▓рд╛ рдЖрд╣реЗ рдХрд╛?"
рдкреБрдиреНрд╣рд╛ рдкреБрдиреНрд╣рд╛ рдЕрдкрдпрд╢реА рд╣реЛрдгрд╛рд░реА рдЪрд┐рдареНрдареА (рдЪреБрдХреАрдЪрд╛ рдирдВрдмрд░) рдХрд╛рдпрдордЪреА рдлрд┐рд░рдд рд░рд╛рд╣рдд рдирд╛рд╣реА. рддреА рдПрдЦрд╛рджреНрдпрд╛ рд╡реНрдпрдХреНрддреАрдиреЗ рдкрд╛рд╣рд╛рд╡реА рдореНрд╣рдгреВрди рдмрд╛рдЬреВрдЪреНрдпрд╛ рдЯреНрд░реЗрдордзреНрдпреЗ рдЬрд╛рддреЗ.
ЁЯЧ║я╕П рдЖрдХреГрддреА
flowchart LR
t["тЬНя╕П teacher: POST urgent notice"] --> api["ЁЯФМ API<br/>save notice + 1 job<br/>тЖТ 201 in ~50 ms"]
api --> q[["ЁЯУм queue"]]
q --> w1["ЁЯС╖ worker"]
q --> w2["ЁЯС╖ worker"]
q --> w3["ЁЯС╖ тАж 50 workers"]
w1 --> sms["ЁЯУ▒ SMS provider<br/>batches of 500"]
w2 --> sms
w3 --> sms
w1 -.->|"no 'done' in time тЖТ visible again"| q
q -.->|"failed 5 times"| dlq[["ЁЯз║ DLQ"]]
note["50 workers ├Ч 50 SMS/s<br/>тЖТ 5M in 33.3 min"]
ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрд╡реГрддреНрддреА + рдПрдХ lab: https://school-edh.pages.dev/system-design/lesson-diagrams.html#l07
тЭУ рдХрд╛рдп
- Synchronous тАФ рдмреЛрд▓рд╛рд╡рдгрд╛рд░рд╛ рдХрд╛рдо рдкреВрд░реНрдг рд╣реЛрдИрдкрд░реНрдпрдВрдд рдерд╛рдВрдмрддреЛ. User рд▓рд╛ рдЖрддреНрддрд╛ рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ рддреНрдпрд╛рд╕рд╛рдареА рдпреЛрдЧреНрдп (рд╕реВрдЪрдирд╛рдВрдЪреА рдпрд╛рджреА).
- Asynchronous тАФ рдмреЛрд▓рд╛рд╡рдгрд╛рд▒реНрдпрд╛рд▓рд╛ рд▓рдЧреЗрдЪ "рд╕реНрд╡реАрдХрд╛рд░рд▓реЗ" рдорд┐рд│рддреЗ; рдХрд╛рдо рдирдВрддрд░ рд╣реЛрддреЗ. рд╣рд│реВ рдХрд╛рдо, рдерд╛рдВрдмреВ рд╢рдХрдгрд╛рд░реЗ рдХрд╛рдо, рдЖрдгрд┐ рд╣рд│реВ рдХрд┐рдВрд╡рд╛ рдмреЗрднрд░рд╡рд╢рд╛рдЪреНрдпрд╛ рдмрд╛рд╣реЗрд░рдЪреНрдпрд╛ service рд╢реА рдмреЛрд▓рдгрд╛рд░реЗ рдХрд╛рдо (SMS, email, video encoding, reports) рдпрд╛рдВрд╕рд╛рдареА рдпреЛрдЧреНрдп.
- Queue тАФ producer (API) рдЖрдгрд┐ consumers (workers) рдпрд╛рдВрдЪреНрдпрд╛рдордзрд▓реА jobs рдЪреА рдЯрд┐рдХрд╛рдК рдпрд╛рджреА. рддреА рдЧрд░реНрджреА рд╢реЛрд╖реВрди рдШреЗрддреЗ: jobs request рдордзреНрдпреЗ рдирд╛рд╣реА, queue рдордзреНрдпреЗ рдерд╛рдВрдмрддрд╛рдд.
- Worker тАФ job рдШреЗрдгрд╛рд░реА, рддреЗ рдХрд░рдгрд╛рд░реА, рдЖрдгрд┐ рдордЧ done рдореНрд╣рдгрдгрд╛рд░реА (рддреЛ delete рдХрд░рдгрд╛рд░реА) process. рдЬрд▓рдж рдЬрд╛рдгреНрдпрд╛рд╕рд╛рдареА workers рдЬреЛрдбрд╛; рд╡реЗрдЧ рдореНрд╣рдгрдЬреЗ рддреБрдореНрд╣реА рдЬреНрдпрд╛рдЪреЗ рдкреИрд╕реЗ рджреЗрддрд╛ рддреЗ.
- At-least-once delivery тАФ рдмрд╣реБрддреЗрдХ queues (SQS standard, RabbitMQ, Kafka consumers) рдкреНрд░рддреНрдпреЗрдХ job рдХрд┐рдорд╛рди рдПрдХрджрд╛ рдкреЛрд╣реЛрдЪрд╡рдгреНрдпрд╛рдЪреЗ рд╡рдЪрди рджреЗрддрд╛рдд тАФ рдХрдзреА рдХрдзреА рджреЛрдирджрд╛. Exactly-once processing рд╣реА рддреБрдореНрд╣реА рдмрд╛рдВрдзрд╛рдпрдЪреА рдЧреЛрд╖реНрдЯ рдЖрд╣реЗ, рдЖрдкреЛрдЖрдк рдорд┐рд│рдгрд╛рд░реА рдирд╛рд╣реА.
- Visibility timeout тАФ worker job рдШреЗрддреЛ рддреЗрд╡реНрд╣рд╛ queue рддреЛ N рд╕реЗрдХрдВрдж рд▓рдкрд╡рддреЗ. Worker рдиреЗ рд╡реЗрд│реЗрдд "done" рдореНрд╣рдЯрд▓реЗ рдирд╛рд╣реА (рддреЛ crash рдЭрд╛рд▓рд╛, рдХрд┐рдВрд╡рд╛ рд╣рд│реВ рд╣реЛрддрд╛), рддрд░ job рдкреБрдиреНрд╣рд╛ рджрд┐рд╕реВ рд▓рд╛рдЧрддреЛ рдЖрдгрд┐ рджреБрд╕рд░рд╛ worker рддреЛ рдШреЗрддреЛ. рддреЛ рд╕рд░реНрд╡рд╛рдд рд╣рд│реВ рд╕рд╛рдорд╛рдиреНрдп job рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд рдареЗрд╡рд╛.
- Backoff рд╕рд╣ retries тАФ рдкреНрд░рддреНрдпреЗрдХ рдЕрдкрдпрд╢рд╛рдирдВрддрд░ рдЬрд╛рд╕реНрдд рд╡реЗрд│ рдерд╛рдВрдмрд╛ (1 s, 2 s, 4 s тАж jitter рд╕рд╣), рдореНрд╣рдгрдЬреЗ рдЖрдзреАрдЪ рдЕрдбрдЪрдгреАрдд рдЕрд╕рд▓реЗрд▓реНрдпрд╛ SMS provider рд╡рд░ рд╕рддрдд рдорд╛рд░рд╛ рд╣реЛрдд рдирд╛рд╣реА.
- Dead-letter queue (DLQ) тАФ N рдЕрдкрдпрд╢реА рдкреНрд░рдпрддреНрдирд╛рдВрдирдВрддрд░ job рдорд╛рдгрд╕рд╛рд╕рд╛рдареА рдХрд┐рдВрд╡рд╛ рдирдВрддрд░рдЪреНрдпрд╛ redrive рд╕рд╛рдареА рдмрд╛рдЬреВрд▓рд╛ рдЬрд╛рддреЛ. рддреА рд░рд┐рдХрд╛рдореА рдирд╕реЗрд▓ рддреЗрд╡реНрд╣рд╛ alert рджреНрдпрд╛.
- Idempotent consumer тАФ рддреЛрдЪ job рджреЛрдирджрд╛ process рдХреЗрд▓рд╛ рддрд░реА рдкрд░рд┐рдгрд╛рдо рдПрдХрджрд╛ рдХреЗрд▓реНрдпрд╛рд╕рд╛рд░рдЦрд╛рдЪ: "(рд╕реВрдЪрдирд╛ 42, рдкрд╛рд▓рдХ 17) рдкрд╛рдард╡рд▓реЗ" рдЕрд╢реА table рдареЗрд╡рд╛ рдЖрдгрд┐ рдиреЛрдВрдж рдЕрд╕реЗрд▓ рддрд░ рд╡рдЧрд│рд╛.
- Backpressure тАФ workers рдкреВрд░реНрдг рдХрд░рддрд╛рдд рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ jobs рдЬрд▓рдж рдЖрд▓реЗ рдХреА queue рд╡рд╛рдврддреЗ. рд╕рд░реНрд╡рд╛рдд рдЬреБрдиреНрдпрд╛ job рдЪреЗ рд╡рдп рдкрд╛рд╣рд╛, backlog рдиреБрд╕рд╛рд░ workers рд╡рд╛рдврд╡рд╛, рдЖрдгрд┐ рдЧрд░рдЬ рдЕрд╕реЗрд▓ рддрд░ producers рдирд╛ рд╣рд│реВ рдХрд░рд╛ (429, рдзрдбрд╛ 12).
ЁЯдФ рдХрд╛
рдХрд╛рд░рдг рдХрд╛рдЧрдж (рдзрдбрд╛ 01) рдореНрд╣рдгрддреЛ "post p99 < 500 ms" рдЖрдгрд┐ "рддрд╛рддрдбреАрдЪреНрдпрд╛ рд╕реВрдЪрдирд╛рдВрд╕рд╛рдареА рдкрд╛рд▓рдХрд╛рд▓рд╛ notification рдорд┐рд│рддреЗ". Request рдордзреНрдпреЗ 5 million SMS рдкрд╛рдард╡рд▓реНрдпрд╛рдиреЗ рдкрд╣рд┐рд▓реЗ рд╡рдЪрди рдореЛрдбрддреЗ. Queue рджреЛрдиреНрд╣реА рдкрд╛рд│рддреЗ: рд╢рд┐рдХреНрд╖рд┐рдХреЗрдЪрд╛ request рдЬрд▓рдж, рдЖрдгрд┐ рдкрд╛рдард╡рдгреЗ рддреБрдореНрд╣реА рдкреИрд╕реЗ рджреЗрддрд╛ рддрд┐рддрдХреНрдпрд╛ workers рдЗрддрдХреЗ рдЬрд▓рдж. рддреЗ рдЕрдкрдпрд╢ рд╡реЗрдЧрд│реЗ рдареЗрд╡рддреЗ: SMS provider 10 рдорд┐рдирд┐рдЯреЗ рдмрдВрдж рдЕрд╕рд▓рд╛, рддрд░ jobs queue рдордзреНрдпреЗ рдерд╛рдВрдмрддрд╛рдд; рд╕реВрдЪрдирд╛ post рдХрд░рдгреЗ рдЪрд╛рд▓реВрдЪ рд░рд╛рд╣рддреЗ.
ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)
рдпрд╛ рдзрдбреНрдпрд╛рд╕рд╛рдареА lab рдордзреНрдпреЗ queue class рдирд╛рд╣реА тАФ model рдореНрд╣рдгрдЬреЗ рдЧрдгрд┐рдд, рдЖрдгрд┐ рддреЛрдЪ рдореБрджреНрджрд╛ рдЖрд╣реЗ:
рд╡реЗрд│ = jobs ├╖ (workers ├Ч рдкреНрд░рддреНрдпреЗрдХ worker рдЪрд╛ рд╡реЗрдЧ). design/demo.py
рдордзреАрд▓ queues() рдкреНрд░рддреНрдпреЗрдХреА рд╕реЗрдХрдВрджрд╛рд▓рд╛ 50 SMS рдпрд╛ рд╡реЗрдЧрд╛рдиреЗ 10, 50 рдЖрдгрд┐ 200 workers рд╕рд╛рдареА рддреЗ рдЫрд╛рдкрддреЗ. Snippet
рд╡реЗрдЧ рдмрджрд▓рддреЛ, jobs рдмрд╛рд╣реЗрд░ рдЬрд╛рдгреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд▓рдж рдпреЗрддрд╛рдд рдЕрд╕реЗ рдПрдХ рдЧрд░реНрджреАрдЪреЗ рдорд┐рдирд┐рдЯ рдЬреЛрдбрддреЛ (backlog), рдЖрдгрд┐ рдПрдХрдЪ job
рджреЛрдирджрд╛ рдорд┐рд│рдгрд╛рд░рд╛ рдПрдХ idempotent consumer рдЪрд╛рд▓рд╡рддреЛ.
ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛
python3 design/demo.py queues
python3 - <<'EOF'
jobs = 5_000_000
for workers, rate in ((50, 50), (50, 25), (100, 50), (50, 5)):
print(f"{workers:>3} workers ├Ч {rate:>2} SMS/s тЖТ {jobs / (workers * rate) / 60:6.1f} min")
arrive, drain = 3_000, 2_500 # per second, for one busy minute
print(f"backlog after 60 s: {(arrive - drain) * 60:,} jobs waiting ┬╖ cleared {(arrive - drain) * 60 / drain:.0f} s after the rush")
# at-least-once: message 2 is delivered twice (the worker crashed before it said 'done')
deliveries = ["sms-1", "sms-2", "sms-2", "sms-3"]
sent, done = [], set()
for m in deliveries:
if m in done: continue # idempotent consumer: already handled
sent.append(m); done.add(m)
print("delivered", len(deliveries), "┬╖ sent", len(sent), sent)
EOF
тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ
queues рдЫрд╛рдкрддреЗ:
тФАтФА 'send 5M urgent SMS' must not run inside the request
request: save the notice, put ONE job on a queue, answer 201 in ~50 ms
workers: take jobs, send in batches of 500, retry with backoff, park failures in a DLQ
10 workers ├Ч 50 SMS/s тЖТ all 5M sent in 166.7 min
50 workers ├Ч 50 SMS/s тЖТ all 5M sent in 33.3 min
200 workers ├Ч 50 SMS/s тЖТ all 5M sent in 8.3 min
queues decouple speed: the request is fast, the work is as fast as you pay for ┬╖ delivery is at-least-once
рддреБрдордЪрд╛ snippet рдЫрд╛рдкрддреЛ:
50 workers ├Ч 50 SMS/s тЖТ 33.3 min
50 workers ├Ч 25 SMS/s тЖТ 66.7 min
100 workers ├Ч 50 SMS/s тЖТ 16.7 min
50 workers ├Ч 5 SMS/s тЖТ 333.3 min
backlog after 60 s: 30,000 jobs waiting ┬╖ cleared 12 s after the rush
delivered 4 ┬╖ sent 3 ['sms-1', 'sms-2', 'sms-3']
ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ
рд╢рд┐рдХреНрд╖рд┐рдХреЗрд▓рд╛ рдЙрддреНрддрд░ рдорд┐рд│рдгреНрдпрд╛рдЪреА рд╡реЗрд│ рдпрд╛рдВрдкреИрдХреА рдХреЛрдгрддреНрдпрд╛рдЪ рдЖрдХрдбреНрдпрд╛рд╡рд░ рдЕрд╡рд▓рдВрдмреВрди рдирд╛рд╣реА тАФ рддреЛ рдПрдХ queue write рдЖрд╣реЗ. рдХрд╛рдорд╛рдЪреА рд╡реЗрд│ рдЕрд╡рд▓рдВрдмреВрди рдЖрд╣реЗ: рд╡реЗрдЧ рдирд┐рдореНрдорд╛ рдХрд░рд╛ рдЖрдгрд┐ рддреА рджреБрдкреНрдкрдЯ рд╣реЛрддреЗ; workers рджреБрдкреНрдкрдЯ рдХрд░рд╛ рдЖрдгрд┐ рддреА рдирд┐рдореНрдореА рд╣реЛрддреЗ; рд╣рд│реВ provider (5 SMS/s) 33 рдорд┐рдирд┐рдЯрд╛рдВрдЪреЗ 5.5 рддрд╛рд╕ рдХрд░рддреЛ. рдЧрд░реНрджреА рдПрдХ backlog рдорд╛рдЧреЗ рдареЗрд╡рддреЗ рдЬреЛ рдЧрд░реНрджреАрдЪреНрдпрд╛ рд╡реЗрд│реА requests рдЕрдкрдпрд╢реА рдХрд░рдгреНрдпрд╛рдРрд╡рдЬреА рдЧрд░реНрджреА рдирдВрддрд░ рд░рд┐рдХрд╛рдорд╛ рд╣реЛрддреЛ. рдЖрдгрд┐ рджреЛрдирджрд╛ рдкреЛрд╣реЛрдЪрд▓реЗрд▓рд╛ job рдПрдХрджрд╛рдЪ рдкрд╛рдард╡рд▓рд╛ рдЧреЗрд▓рд╛, рдХрд╛рд░рдг consumer рдиреЗ рдЖрдзреА рддрдкрд╛рд╕рд▓реЗ.
тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛
- рд╣рд│реВ рдмрд╛рд╣реЗрд░рдЪреЗ calls (SMS, email, PDF) request рдЪреНрдпрд╛ рдЖрдд рдХрд░рдгреЗ
- exactly-once рдЧреГрд╣реАрдд рдзрд░рдгреЗ: idempotency рддрдкрд╛рд╕рдгреА рдирд╛рд╣реА, рдореНрд╣рдгреВрди worker restart рдирдВрддрд░ рдкрд╛рд▓рдХрд╛рдВрдирд╛ рджреЛрди SMS рдпреЗрддрд╛рдд
- job рдкреЗрдХреНрд╖рд╛ рд▓рд╣рд╛рди visibility timeout тАФ рджреЛрди workers рдПрдХрд╛рдЪ рд╡реЗрд│реА рддреЛрдЪ job рдХрд░рддрд╛рдд
- DLQ рдирд╛рд╣реА: рдПрдХ рд╡рд╛рдИрдЯ message рдХрд╛рдпрдо retry рд╣реЛрдд рд░рд╛рд╣рддреЛ рдЖрдгрд┐ рдЗрддрд░рд╛рдВрдирд╛ рдЕрдбрд╡рддреЛ
- рдХреЛрдгреАрд╣реА рд▓рдХреНрд╖ рди рджреЗрдгрд╛рд░реА DLQ
- user рдерд╛рдВрдмрд▓реЗрд▓рд╛ рдЕрд╕рддреЛ рдЕрд╢рд╛ read рд╕рд╛рдареА queue рд╡рд╛рдкрд░рдгреЗ тАФ рддреЗ рдХрдореА рдирд╡реНрд╣реЗ, рдЬрд╛рд╕реНрдд рдерд╛рдВрдмрддрд╛рдд
- queue depth рдХрд┐рдВрд╡рд╛ рд╕рд░реНрд╡рд╛рдд рдЬреБрдиреНрдпрд╛ message рдЪреНрдпрд╛ рд╡рдпрд╛рдРрд╡рдЬреА CPU рд╡рд░ workers рд╡рд╛рдврд╡рдгреЗ
- SMS provider рдкрд░рд╡рд╛рдирдЧреА рджреЗрддреЛ рддреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд workers тАФ рдЖрддрд╛ рд╕рдЧрд│реЗрдЪ throttle рд╣реЛрддрд╛рдд (рдорд░реНрдпрд╛рджрд╛ рд╣реА constraint рдЖрд╣реЗ, рдзрдбрд╛ 01)
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд
On a real account тАФ 5 рдкреНрд░рдпрддреНрдирд╛рдВрдирдВрддрд░ DLQ рдЕрд╕рд▓реЗрд▓реА, рдЖрдгрд┐ рдПрдХрд╛ batch рдкреЗрдХреНрд╖рд╛ рдЬрд╛рд╕реНрдд visibility timeout рдЕрд╕рд▓реЗрд▓реА SQS queue:
aws sqs create-queue --queue-name urgent-sms-dlq \
--attributes MessageRetentionPeriod=1209600
aws sqs create-queue --queue-name urgent-sms --attributes '{
"VisibilityTimeout": "120",
"RedrivePolicy": "{\"deadLetterTargetArn\":\"arn:aws:sqs:ap-south-1:123456789012:urgent-sms-dlq\",\"maxReceiveCount\":\"5\"}"
}'
Batch рдордзрд▓реЗ рдлрдХреНрдд рдЕрдкрдпрд╢реА messages рдХрд│рд╡рдгрд╛рд░рд╛ Lambda consumer (рдореНрд╣рдгрдЬреЗ рдЪрд╛рдВрдЧрд▓реЗ messages рдкреБрдиреНрд╣рд╛ retry рд╣реЛрдд рдирд╛рд╣реАрдд), SMS provider рдЪреА рдорд░реНрдпрд╛рджрд╛ рдкрд╛рд│рдгреНрдпрд╛рд╕рд╛рдареА concurrency рд╡рд░ рдХрдорд╛рд▓ рдорд░реНрдпрд╛рджреЗрд╕рд╣:
aws lambda create-event-source-mapping --function-name send-sms \
--event-source-arn arn:aws:sqs:ap-south-1:123456789012:urgent-sms \
--batch-size 10 --function-response-types ReportBatchItemFailures \
--scaling-config MaximumConcurrency=50
Idempotency рддрдкрд╛рд╕рдгреА, database рдордзреАрд▓ unique key рдЪреНрдпрд╛ рд░реВрдкрд╛рдд:
CREATE TABLE sms_sent (notice_id bigint, parent_id bigint, PRIMARY KEY (notice_id, parent_id));
INSERT INTO sms_sent VALUES ($1, $2) ON CONFLICT DO NOTHING; -- 0 rows inserted тЖТ already sent, skip
рдЕрдзрд┐рдХ рдЦреЛрд▓рд╛рдд: Scaling рд╢рд╛рд│рд╛, рдзрдбреЗ 12 (SQS, backlog рдиреБрд╕рд╛рд░ рд╡рд╛рдврдгрд╛рд░реЗ workers) рдЖрдгрд┐ 13 (idempotency, DLQs).
ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рдлрдХреНрдд queue рдЪреНрдпрд╛ рд▓рд╛рдВрдмреАрд╡рд░ рдирд╛рд╣реА, рддрд░
ApproximateAgeOfOldestMessageрд╡рд░ alarm рд▓рд╛рд╡рд╛. "рд╕рд░реНрд╡рд╛рдд рдЬреБрдирд╛ рддрд╛рддрдбреАрдЪрд╛ SMS 20 рдорд┐рдирд┐рдЯреЗ рдерд╛рдВрдмрд▓рд╛ рдЖрд╣реЗ" рд╣рд╛ рдкрд╛рд▓рдХрд╛рд▓рд╛ рдЬрд╛рдгрд╡рдгрд╛рд░рд╛ рдЖрдХрдбрд╛ рдЖрд╣реЗ.
тПня╕П рдкреБрдвреЗ
рдПрдХ рд╕реВрдЪрдирд╛, рдЖрдгрд┐ рдЖрддрд╛ рдЪрд╛рд░ jobs рд╡реНрд╣рд╛рдпрд▓рд╛ рд╣рд╡реЗрдд: SMS, email, search index, analytics. API рдиреЗ рдкреНрд░рддреНрдпреЗрдХрд╛рд▓рд╛ call рдХрд░рд╛рд╡рд╛ рдХрд╛? рдирд┐рдпреЛрдЬрди рдХрд╛рд░реНрдпрд╛рд▓рдп рдПрдХрд╛ рдШрдЯрдиреЗрдЪреА рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ рдЖрдгрд┐ рдкреНрд░рддреНрдпреЗрдХ рдРрдХрдгрд╛рд▒реНрдпрд╛рд▓рд╛ рдкреНрд░рддрд┐рд╕рд╛рдж рджреЗрдК рджреЗрддреЗ тАФ рддреА рдХрдзреАрд╣реА рди рдЧрдорд╛рд╡рддрд╛.
git checkout lesson-08-events