Проектаванне системы задньага календаря па прынцыпе «вузькага месца»: ад скрацальніка URL да электронной торгавлі
Падчынны падход да проектавання сервераў Node.js, які спачатку уважае тэрэтывы: калі трэба дадаць балансавальнікі навантажэння, Redis, реплікі, кяухі і ліміты частоты, а такса кожнага з іх.
Крыніцы: System Design for Backend Engineers: A Practical Guide With Real Examples
Багато інжынераў падходзяць да проектавання системы шляхом стварэння схемы: балансіра навантажэння, Redis, Kafka, API-шлюза, дзесятка мікросервісаў. Рэзультат выглядае вражаюча, але нічога не пояснюе. Чы то пад час адбору на работу, чы ў рэальным продукце, проектаванне — это практыка выбору правильных компонентаў для конкрэтнай проблемы і можлівасць обґрунтування кожнага з іх. У гэтым падрабніку показаны прыклады такага абгрунтування на двух конкрэтных системах — скрайшувачы URL і невялікай бэкенд-системе для е-камеры, ўпрымкі якога дапамагае поступова развиваць архітектуру, крок за крокам, і называць компромісы, якія вводзяцца на кожным з эўх крокаў.
Пачніце з трэбаванняў, а не з тэхналогій
Найпасуючыя першыя памылкі — это пачатак з інструментаў. Хтось описвае проблему, і першыя мысляй з’яўляюцца: «Redis чы не? Kafka? Microservices?» Такі порядак ўскладнюе рашэнне. Пакуль вы не знаеце, калі сама система должна функцыянаваць і у якіх масштабах, у вас няма падстав для выбору чаго-небудзь.
Возьмімо, прыклад, скартавач URL. Перш чым накрэсліць хоць якія елементы, трэба атрымаць адпаведныя адказы на такія запитанні:
- Сколькі будзе корыстувачаў і сколькі URL-адрэсаў яны створыць?
- Якую шчыльнасц запитоў ён должен пераканаць у момент піку навантажэння?
- Як дзяўно будуць дзейнальныя лінкі і чы можа ў яных выйсці тэрмін дзейнальнасці?
- Чы патрэбны корыстувачам статыстыкі клікаў?
- Які час перываноў я ўзяць за прыемны?
- Як швалява должна выдавацца перыялізацыя?
Кожны адказ вплывае на дизайн. Сервіс, які прыме такое навантажэнне:
1,000 requests/day
майже нічага не мае спакойна з тым, які должен вытрымаць такое навантажэнне:
10 million requests/secon
Першы варіант легка пасвае на адзін маленькі сервер. Другі з самага пачатку вымушвае прыймать рашэнні ў паводзе кэшавання, реплікацыі і геаграфіі.
Пачніце з самай простой архітектуры, якая работае
Для маленькага скартавальніка URL першая версія можа быць практычна простой:
Client
↓
Node.js API
↓
PostgreSQL
API генеруе короткі код і вяртае лінк у такім формате:
https://example.com/abc123
Пасля чаго ён зберагае адзіны супарабоўкі ў PostgreSQL:
short_code → original_url
Калі браузер запрашае шлях, падобны таму, як нижчэй, API шукае первісны URL і адпавядае перенаправленнем:
/abc123
Для невялікага обсягу работы гэта ўжо цэлы, правільны система. Нічога ў яй не вымагае вжыць стандартныя рашэнні:
Kafka
Redis
Kubernetes
Microservices
Адаптаванне ўсьго таму, што гэта можліва, прыносіць толькі вышэйшыя эксплуатацыйныя витраты, больш захворэўнасцей і больш працы для кожнага новага члена команды. Створыце тое, што працуе, вы меркайце яго, а потым расшырываеце тыя часткі, якія виявляюцца вузькімі месцамі.
Расшырэнне, калі адна сервера недастаткова
Падазроўваючы, што сервіс скрацання лінкаў стане популярным, а яго ўсё той жа процес API будзе перавантажаны:
1 API server
Можна было б продаваць большыя машыны, але вертыкальнае расшырэнне мае свой ліміт, і адна машына ёсць адной точкай збою. Больш распашчасты спосаб — запуск калькольных ідэнтычных экземпляраў за дапамогою балансіра навантажэння:
Load Balancer
↓
┌───────────┼───────────┐
↓ ↓ ↓
Node API Node API Node API
↓ ↓ ↓
└───────────┼───────────┘
↓
PostgreSQL
Запыты тепер распадзяюцца між калькольнымі экземплярамі прыложэння. Гэта ўжо горизонтальнае расшырэнне: замест таго, каб паслужыцца
1 huge server
вы паслужыцеся
multiple smaller servers
Горызонтальнае масштабаванне працюе толькі тады, калі экземпляры можна заменіць адны на другі, і гэта паднімае запытанні, якіх раней не было:
- Дзе знаходзіцца стан сесіі, якщо наступны запит корыстніка можа прайсці да іншага экземпляра?
- Чы рэальна кожны экземпляр ў стане безстановасці?
- Куда падаюць заваношаныя файлы, калі локальны диск больш не ўзаемна выкарыстоўваецца?
- Як кожны экземпляр прабывае да спільнай інфраструктуры, такой як база дадзеных?
Масштабаванне аднаго компонента часта стварае трэбованні ў іншых частях; тут стан павінен перайсці у спільныя хранілышча.
Дадзіце кэш, калі у вас справжня проблема з кэшаваннем
Популярныя короткія лінкі запрашваюцца знова і знова:
/abc123
/abc123
/abc123
/abc123
/abc123
Няма прычыны, чаму кожна з тых запитоў павінна працаваць з PostgreSQL. Кэш, які знаходзится пры самай базе дадзенаў, соручае з мемарыі неабходныя данні, пераходзячы да базы дадзенаў толькі у разе ўспаміну і зберагаючы рэзультат на будучыя запиты:
Client
↓
Load Balancer
↓
Node.js API
↓
Redis
│
├── Cache Hit → Return URL
│
└── Cache Miss
↓
PostgreSQL
↓
Redis
Такі падход з викорыстаннем кэша можа скасаваць большую частку навантажэння на чытанне базы дадзенаў у ситуаціях з неравнамерным навантажэнням, такіх як перенаправленні лінкаў. Аднак ён стварае новыя пытанні: якщо мета короткага лінка змянюецца або выдаліцца, як кэшаваная копія гэта дазнаецца? Тады патрэбна стратегія анавегацыі кэшу — будзь то выдаленне ключа пасля кожнага зберагання, заданне тэрміна жыцця кэшу або ўжоўвесьце гэтыя заходы. Чытайце болей паўню інфармацыю пра гэтыя варыянты ў нашай аднародзе па прынцыпам, падазрохлівасцям і канцэпціям кэшавання ў Redis.
Кожныя палёсткі ў гэтым кансэпцыі супакоўваюцца з такімі толькі затратамі. Спроможнасць назваць гэтыя затраты і ўскладнівае разлік межаў дизайна і дыяграмы.
Вылечыце базу дадзеных прытаманная да адбавлення ўсё большых баз дадзеных
Іноды PostgreSQL можа стаць вузкім месца. Перш чым дадаць новую інфраструктуру, выявіце прычыны ўповольнення. Частыя прычыны включаюць:
- Відсутнае індексаванне столбцоў, якія выкарыстоўваюцца для пошуку
- Неэфектывныя запыткі або з’еднання
- Шаблоны запыткаў N+1 у працоўным праграме
- Верненне набагато большай колькасці рэядкаў або столбцоў, чым трэба
- Некаліткавая стораначэнне, напрыклад, вялікія зсувы
- Неправильна налаштаваны або выкараны пул з’язнаў
Часта рашэнняя ёсць простым запыткам:
CREATE INDEX ...
Гэта дешавае і безпечней, чым адбавлення новага компонента. Правілле, якое трэба памятаць: вылечыце вузкія месца, якія вы з’явілі, прытаманная да адбавлення архітэктуры навакола іх.
Реплікі для чытання для завад з великай колькасцю операцый чытання
Багатыя прыкладніцы чытаюць значна большую колькасць дадзеных, чым запішваюць іх, напрыклад:
90% reads
10% writes
У такім случае галоўная база дадзеных можа быць перавантажаная запытамі на чытанне. Аднам з раўнявання ёй є аднароджэнне реплік для чытання: галоўная база прыме ўсі запісы, а реплікі будуць виконваць частку запытамі на чытанне.
Node.js API
↓
┌────────┴────────┐
↓ ↓
Primary DB Read Replica
↓ ↑
Writes Reads
Косц розліку пад час реплікацыі
У большасці наладак реплікі апдэйтуюцца асінхронна, таму запіс падае на галоўную базу раней, чым досягае реплікі:
Write → Primary
↓
Replication
↓
Read Replica
Якщо запыт запішвае якісь данні, а пасля гэтага негайнаа чытае іх з реплікі, ён можа пабачыць застарэлыя данні на короткі час. Таму прыкладніца павінна ведаць, якія запыты на чытанне патрабуюць найновейшаг стану. Часты падход — адправляць запыты типу „чытай своія ж запісы“, напрыклад, завантажваць прафіль сразу пасля яго збережэння, на галоўную базу, а всё іншае — на реплікі.
Перакладзіце роботу з медленным виконанням у фонавы задачы
Дзеяння, якія не патрабуюць завершыцца прытаму, калі корыстнік чакае адпаведны ўтвар:
- Адправка электранаў
- Стварэнне рахункоў-фактур
- Расылка паведамленняў
- Складанне звярненняў
- З’язак з медленнымі зовнішнімі сервісамі
У зменшэньне чакання корыстніка API фіксуе тое, што трэба здарыцца, дадзеўвае задачу у чергу і адразу ж дае адпаведны ўтвар:
Client
↓
Node.js API
↓
Create Record
↓
Queue Job
↓
Response
Адзінэцкі процес-рабочы берае задачу і выкаанае роботу:
Queue
↓
Worker
↓
Process Job
У практыцы адна черга можа сапраўджваць рабочыя процесы, якія керуюць калькама задач:
API
↓
Redis / Queue
↓
Worker
├── Email
├── Invoice
└── Notification
Это дапамагае зменшыць час адпаведзення на запиты і дае можлівасць кантролюваць колькасць праказаў і ліміты праходзкай спроможнасці. Аднак гэта таксама стварае свою сяброўскую групу проблем, якія трэба врачыць:
- Задача можа выканацца больш чым раз, таму працоўнікі павінны вытрымліваць дуплікаты.
Масштабаванне ніколі не ўзлегка. Якщо вы ствараеце гэта ў Node.js, наша інструкцыя па стварэнню систем заданняў у фоне з BullMQ і Redis рассказвае пра гэтыя проблемы ў кодзе.
Проектаванне з урахоўваннем неудачы ўсё раней, чым яна выйдзе
Цікавая работа над дызайнам пачынаецца тады, калі вы перестаёте спытваць толькі, што будзе, калі всё працуе, і пачынаете спытваць, што будзе, калі ўсё зламаецца.
Адмовіцца ад працы грацыязна, калі зламаецца залежнасць
Падзіце, калі Redis стане недоступным. Чы гэта мае прывяжвацца да зупінкі всей API? Якщо Redis выкарыстоўваецца толькі як кэш, то, верагатна, не трэба. API можа прыхіліцца да PostgreSQL без кэша — гэта будзе медленней, але ўсё равно правільна:
Request
↓
Redis
↓
FAIL
↓
PostgreSQL
↓
Response
Якщо Redis таксама выкарыстоўваецца для падтрымкі ярлыковай чаты заданняў або механізма лімітавання частоты запытаў, працэс падвякання становіцца значна серйозней, таму што для гэтых функцыяў немае простаг альтернатыва. Проектаванне должна чытка паказаць ролю кожнага компонента, адтолькі як гэта паказвае, як будзе дзейсніцца система, калі компонент зламаецца.
Установіце таймаут для кожнага зовання званоўна
Уявіце, што API запытае зовнішню службу платежаў без налаштавання таймаута:
API
↓
Payment Service
↓
... waiting ...
↓
... waiting ...
↓
... waiting ...
Пакуль сервер чакае, ён прытрымвае сокеты, памяць і ресурсы для запытаў, якія можаць ніколі не адпаведзець. Пад высокай навантажэнні гэтыя застрялы запыты могу выцягнуць усі процесы. Хораша система назначае кожнаму запыту канечную дату:
API
↓
Payment Service
↓
5 second timeout
↓
Failure
Калі заканчываецца тэрмін, працоўны програма должна выбраць, як далей дзеяць, і правы выбар залежыць ад операцыі:
- Праказаць паказванне знову
- Адправіць памылку кліенту
- Пакласты операцыю у чергу на пазнейшы час
- Выварыць альтэрнатыўны варыянт
- Заазначыць операцыю як у паўстаноўленні і выправіць ёе пазней
Праказы зноў ёсць безпечныя толькі калі операцыі ўзаемна аднаковыя
Калі паказванне аб платэжы выйшае за час, праказаць яго зноў здаецца логічным. Але тайма-аут не паведамляе, чы платэж зазнаў няудачы. Можа, платеж усё-такі быў успешны, а проста загубілася адпаведнае падтверджэнне. Абмовленая праказа можа вырахаваць кліенту двойную суму.
Рашэнням ёсць прыемлівасць узаемна аднаковых операцый: прыкрепіць стабільны ідэнтыфікатор да операцыі, каб прыймальная сторона могла распазнаць павтарэнне.
payment_id = order_123
Прадаўцу платэжных аперацый выкарыстоўваецца гэты ключ, каб з’ясаваць, чы рошчыну вучынена ўжо, і ён вяртае первасны рэзультат у замен на практыкаванне дадатковых збораў:
Request
↓
Idempotency Key
↓
Payment Provider
↓
Already processed?
├── Yes → Return previous result
└── No → Process payment
Дадаванне практык пры перапрынцэўванні выкалічвае адна лінія коду. Ёх безпечная рэалізацыя выкалічвае саўместную працу всіх элементаў системы. Наша стаття на тэму ключоў ідэмпотентнасці ў канцах POST у Node.js паказвае, як самостайна рэалізаваць ўсё гэта на стороне прыемніка.
Захаванне системы за дапамогою лімітавання частоты
Тепер заўважкім, што аднам кліенту пачынае надаць такую колькасць трафіку:
100,000 requests/minute
Прыйманне ўсьго гэтага дазволіла б аднаму корыстніку паспрабаваць пагоршыць якасць службы для всіх. Лімітавальнік частоты распакоўваецца перед API і адхоўчае занадто многія рошчыны з кодам HTTP 429:
Client
↓
Rate Limiter
↓
Allowed?
├── Yes → API
└── No → 429
Калі існуе калькі API-экзаментаў, лямбарды павінны быть спакушаны, і самэ гэта ўчыніла Redis популярным базовым хранальнікам для распадзеленага лімітавання частоты запытаў: кожны экзамент збільшае тыя ж ключы.
Ліміты павінны адпраўляць тое, што робіць кожны канечны пункт. Канечны пункт для заходжэння є метай для атакаў типу brute-force, таму строгі ліміт, як гэты, є разумным:
Login:
10 requests/minute
Натоўпная спісаванне продуктав, на протывару, можа толькі больш прабачыць:
GET /products:
1000 requests/minute
Устанавіце ліміты на адвесу кастоў операцыі і ўзора аблікаванняяга, а не прыменяйце ўніверсальную цифру.
Дызайн системы — гэта пераважна компромісы
Рэдка калі існуе адна ідеальная архітэктура. Большасць рашэнняў — гэта выбір межа варыянтамі, кожны з якіх хораш у разных аспектах.
SQL протыва NoSQL
Сяроднікавая база дадзейнаў апраноцьвае моцную сяроднікавую модэлізацыю, транзакцыі і моцныя запыты. База дадзейнаў типу NoSQL можа запропанаваць іншыя характэрыстыкі масштабавання, гнучкія схемы і прынтэсы для конкрэтных навантажэнняў. Форма вашых дадзейнаў і спосабы ўступу да яных вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялікай мерой вялік
Валідна альтэватыва – модульны моноліт заместо ранніх мікросервісаў
Гэты выбар заслуговыць на адзін самастоятны раздзял, таму што самэлька складная архітектура ў такім случае стоіць найдорожэ. Новы продукт не патрабуе, каб ён спачатку быў створаны як сукупнасьць такіх сервісаў:
Auth Service
User Service
Product Service
Order Service
Payment Service
Notification Service
Лепшы варыянт – адна застосоўка, якую можна розмістіць:
Node.js Application
якая внутршняя арганізавана ў модулі з чысткімі межамі:
├── Auth
├── Users
├── Products
├── Orders
├── Payments
└── Notifications
У такім разе є адна база коду, адна процедура розмішчэння, і чысткая разлікаванне меж між домэнамі. Якщо пазней якой-небудзь модулю патрабуеяцца масштабаванне або незалежнае розмішчэння, чысткія межы дапамагаюць лёгка яго выдзельніць.
Мікросервісы дзеясна рашаюць рэальныя проблемы організацыі та масштабавання. Аднак яны таксама ствараюць проблемы з сетевымі абяронамі между сервісамі, распраўленым трэйсінгам, аднаходжэнням сервісаў, болей складнымі процесамі развяртання, працоўкамі з адносамом дакладнасці дадзеных между межамі сервісаў, а таксама большай колькасцю задач з манітарынгам та інфраструктурам. Прыймайце гэтыя затраты толькі тады, калі вам патрэбны яхо прынцыповыя перавагі.
Рашайце кожную прычыну спаду на самом маленькім эфектыўным рэвэле
Разглядзіце простую трывярную систему з медленным базам дадзеных:
Client
↓
API
↓
Database
Існуе шкала можлівых рэакцый, ад найменш дорогіх да найбольш уразлівых. Якщо конкрэтны запыт працуе медленна, оптымізавайце яго:
Slow query
↓
Optimize query
Якщо запыты скануюць усю табліцу, дадзіце індэкс:
Missing index
↓
Add index
Якщо тыя ж дадзеныя запрашваюцца паўтараючы, дадзіце кэш:
Repeated reads
↓
Add cache
Якщо чытанняя запыты домінуюць, дадзіце реплікі:
Read-heavy workload
↓
Read replicas
Толькі при практычна великіх масштабах прыходзіцца да структурных змян:
Massive scale
↓
Partitioning / sharding / architectural changes
Адказчыкам ёсць важлівасць параду. Кожны крок выконваецца толькі тады, калі пярэдній вже не ўстаёмць, і кожны з ягох дадае большую складнасць, чым пярэдній.
Практычны процес для адзінакоў з дизайном
Той самы падход прыменяецца і да адзінакоў з дизайном системы. Надёжная последовасць выглядае так:
- Уточніць функцыональныя та нефункцыональныя трэбаванні.
- Адказаць на пытанні пра трафік і зберагчыце.
- Запропанаваць самую простую архітектуру, якая ўсе гэта задовольняе.
- Выявіць, дзе ўсё перша зламаецца.
- Спецыяльна расшырыць гэтыя вузкія месца.
- Разглядаць сцэнарыі неудач.
- Обсудзіць компрэсіі, якія вы прыменяеце.
- Обоснаваць кожны даданы компонент.
Такы падход ў дзесяткі разоў пераканлівыя, чым негайнае стварэнне двадцаті кантэйнероў. Адгуканы дыяграма без логіки, якая стоіць за ўсім гэтым, не ёсць хорашым дизайнам.
Аб’еднанне элементаў: маленькі бэкенд для і-камерцыі
Застосаванне гэтых ідэй у інтарнет-магазіне дае разумную пачатковую архітектуру, такую як гэта:
Client
↓
Load Balancer
↓
┌────────┴────────┐
↓ ↓
Node API Node API
│ │
└────────┬────────┘
↓
┌────────┼────────┐
↓ ↓ ↓
Redis PostgreSQL Queue
│ ↓
│ Worker
│ ↓
│ Email / Invoice
│
↓
External APIs
Payment / Shipp
Тое, што робіць яе західнай, — гэта тое, што кожны компонент адпавядае на пытанне:
- Redis адпавядае за кэшаванне, даныя короткага трымання, лічыльнікі лімітаў частоты і інфраструктуру очаквання.
- PostgreSQL храніць стойкія бізнес-даны і забезпечвае реляцыйныя транзакціі для замовленняў і платэжаў.
- Очаквання прыемліць повольную, асінхронную работу.
- Калькольванні API забезпечваюць горызонтальнае масштабаванне і рэдунданцію.
- Балансавальнік навантажэння распадзяляе трафік між гэтымі калькольваннямі.
Заўважыце, што Redis выпалюе калькольна ролі. Гэта эфектыва, але гэта таксама значыць, што перыв у работе Redis адразу вялічыць наследкі для кэшавання, обмежэння частоты запытанняў та обробкі заданняў, што якраз і є тым видам залежнасцяў, якія павінны быць выявлены пад час аналізу нештачакоў.
Шэсць пытанняў, якія трэба задаць пры завершанні проектавання
- Якую проблему гэта рашае? Якщо вы не можете ясна ўтварыць гэта, архітектура не ўжо гатовая.
- Якая масштабаванняе неабходна? Колькісць корыстнікаў, частота запытанняў, об’ём дадзеных, цілі ў чысце зберагання та затрымкі.
Прыемныя складнасці кращыя за вражаючыя
Найбольшая пастка ў вучэнні проектаванню систем — глыбока пераконанасць, што болей складная архітектура павінна быць лепшай. Гэта не так; яна проста болей складная. Хораша разработка ставіць мету адпраўныя складнасці.
Якщо адмініструеццая працэўнае ядро Node.js і база дадзенаў PostgreSQL падтрымліваюць неабходныя трэбаванні, гэта ўсё ж таки чыста сябе падтрымваючая архітектура. Калі навантажэнне зрастае, дадзейце новыя екземпляры. Калі чытанне дадзенаў стае вузкам местам, оптымізавайце яго. Калі кэшаванне дапамагае, дадзейце Redis. Калі роботу можна адкласці, створыце очакальную лісту. Калі модулю сапраўды патрэбна незалежная масштабаванне або развярненне, рассмотрыце можлівасць яго выяўлення. Архітектура — гэта тое, што развіваецца разам з продуктам.
Ключовыя выводы
- Спачатку неабходныя трэбаванні і адмашныя оценкі ўместнасці; выбор тэхналогій выконвуецца на ўсходзе з іх.
- Пачніце з самай простой работаючай системы і масштабавайце толькі тыя элементы, якія, за дапамогай памераў, выказуюцься вузкам местам.
- Кожна дадатковая элемента карыцца пэўнымі наследкамі: спяльны стан для горызонтальнага масштабавання, анулюванне дадзеных у кэшах, затрымкі у репліках, дуплікаты ў очакальных лістах.
- Ясна спланавайце можлівасць абыякавання, выкарыстоўваючы запасны варіянты, таймауты, ідэмпатныя перапрыбуткі і ліміты частоты запытоў.