System Design Explained: APIs, Databases, Caching, CDNs, Load Balancing & Production Infra

System Design Explained: APIs, Databases, Caching, CDNs, Load Balancing & Production Infra

Hayk Simonyan· · 12 хв читання · Дивитися на YouTube →

Детальний підсумок відео «System Design & API Security» (повний огляд)

Вступ: чому навичка проєктування систем є ключовою для senior-ролей

Автор починає з важливого спостереження: більшість розробників вміють додавати функції до вже існуючої архітектури, але не здатні проєктувати системи або функціонал з нуля. Коли їм дають нечіткі вимоги й просять створити архітектуру, вони «застигають». Саме це вміння — приймати архітектурні рішення, робити компроміси, проєктувати з нуля за мінімальних вимог — відрізняє senior-розробника від middle. Компанії платять високі зарплати не за написання коду або виконання інструкцій, а за архітектурні рішення, які впливають на продуктивність, зберігання даних і кінцевий продукт. Автор ділиться досвідом: він опанував ці концепції за другий рік кар’єри та успішно проходив співбесіди з system design, тому його поради перевірені на практиці.

Огляд курсу: що буде вивчено

Відео є частиною великого курсу. Автор перераховує наступні теми: основи (core concepts), проєктування API, вибір баз даних і проєктування шару даних, кешування та CDN, обробка великих даних, проєктування для продакшену (реальний світ, а не локальна машина), а також практичні кроки для успішного проходження співбесід. Курс побудовано так, щоб поступово ускладнювати систему — від одного сервера до масштабованих рішень.

Основи: односерверне налаштування та потік запитів

Спочатку автор пропонує розглянути найпростішу архітектуру — один сервер, на якому працюють веб-застосунок, база даних, кеш тощо. Це дозволяє зрозуміти, як обробляються запити. Користувачі (браузер або мобільний додаток) звертаються до домену, DNS перетворює його на IP-адресу сервера, потім клієнт надсилає HTTP-запит. Сервер повертає HTML для браузера або JSON для мобільного додатка. Автор наводить приклад API-запиту GET /products/{id} і відповіді у форматі JSON з полями id, name, description, price. Цей простий підхід — основа для розуміння, як рухаються дані в системі, і він підходить для невеликої кількості користувачів, але не витримає великого навантаження.

Вибір бази даних: реляційні vs NoSQL

Коли з’являється потреба розділити веб-рівень і рівень даних, постає питання вибору бази даних. Автор порівнює реляційні (RDBMS) — PostgreSQL, MySQL, Oracle, SQLite — та нереляційні (NoSQL) — Cassandra, MongoDB, Redis, Neo4j. Реляційні бази використовують SQL, дані структуровані в таблицях і рядках. Їхні переваги: підтримка складних JOIN-операцій (наприклад, з’єднання таблиць клієнтів, продуктів і замовлень) та забезпечення узгодженості даних через ACID-транзакції (атомарність, узгодженість, ізоляція, довговічність). Приклад — банківський переказ, де вся операція має виконатися повністю або не виконатися взагалі.

NoSQL бази бувають різних типів: документні (MongoDB — дані у JSON-документах), ширококолонкові (Cassandra — добре для великої кількості записів), графові (Neo4j — зберігають зв’язки, використовуються для рекомендацій, як Neptune у Amazon), ключ-значення (Redis, Memcached — дуже швидкі, бо зберігаються в RAM). NoSQL переваги: гнучкість для неструктурованих даних, низька затримка, масштабованість. Наприклад, у MongoDB можна зберігати всю інформацію про користувача, його замовлення та продукти в одному документі, уникаючи JOIN.

Коли що використовувати? Реляційні — якщо дані добре структуровані (наприклад, e-commerce з клієнтами та замовленнями) або потрібна строга узгодженість (банківські системи). NoSQL — якщо потрібна низька затримка, дані неструктуровані (JSON), або потрібна гнучка масштабованість (наприклад, рекомендаційна система з даними активності користувачів).

Вертикальне та горизонтальне масштабування

Щоб підтримувати зростаюче навантаження, використовують два підходи. Вертикальне (scale up) — додаємо ресурси до існуючого сервера (більше RAM, CPU). Це просто, але має обмеження: фізична межа ресурсів, а також відсутність резервування — якщо сервер виходить з ладу, вся система падає. Горизонтальне (scale out) — додаємо більше серверів, які розподіляють навантаження. Це дає відмовостійкість (якщо один сервер не працює, інші продовжують обслуговувати користувачів) та кращу масштабованість (можна просто додати новий сервер). Для горизонтального масштабування потрібен балансувальник навантаження (load balancer), який направляє запити до відповідного сервера.

Стратегії балансування навантаження

Автор пояснює сім алгоритмів роботи балансувальників. Перший — Round Robin: запити розподіляються по черзі між серверами в послідовному порядку; підходить, коли всі сервери однакової потужності. Другий — Least Connections: запит направляється до сервера з найменшою кількістю активних з’єднань; корисний при сесіях різної тривалості. Третій — Least Response Time: вибирається сервер із найменшим часом відповіді та найменшою кількістю з’єднань; ефективно, коли сервери мають різну продуктивність і мета — швидка відповідь. Четвертий — IP Hash: на основі хешу IP-адреси клієнта обирається сервер; гарантує, що той самий клієнт завжди потрапляє на той самий сервер (наприклад, для збереження стану сесії на сервері). Далі — зважені алгоритми (Weighted Round Robin / Weighted Least Connections): серверам присвоюються ваги відповідно до їхньої потужності (наприклад, більше RAM — більша вага), і балансувальник відповідно розподіляє трафік. Географічні алгоритми: запит спрямовується до найближчого географічного сервера (наприклад, для користувачів із Європи — європейський сервер). Найскладніший — Consistent Hashing: використовується хеш-кільце; кожен клієнт «прив’язується» до найближчого сервера на кільці; забезпечує стабільне з’єднання з одним сервером, як IP Hash, але ефективніше при додаванні/видаленні серверів.

Крім того, балансувальники мають функцію health check: вони регулярно перевіряють доступність серверів і не надсилають трафік до недоступних. Приклади програмних балансувальників: Nginx і HAProxy; апаратних: F5 і Citrix; хмарних: AWS Elastic Load Balancing, Azure Load Balancer, Google Cloud Load Balancing.

Єдина точка відмови (Single Point of Failure)

Автор пояснює, що будь-який компонент, який при падінні зупиняє всю систему, є єдиною точкою відмови. Наприклад, одна база даних — якщо вона виходить з ладу, всі API-сервери не можуть працювати, і клієнти втрачають доступ. Це загрожує надійності (втрати бізнесу), масштабованості (кожен новий компонент збільшує ризик) та безпеці (атаки на цю точку можуть вивести систему з ладу). Щоб уникнути цього, автор пропонує три стратегії: додавання резервування (наприклад, два балансувальники — якщо один падає, інший бере на себе трафік); постійний моніторинг і health check для самих балансувальників; самовідновлювані системи — при виявленні несправності автоматично створюється новий екземпляр.

Проєктування API: стилі REST, GraphQL, gRPC

API — це контракт між клієнтом і сервером, що визначає, як запитувати та отримувати дані. Він приховує деталі реалізації та встановлює межі між сервісами. Автор розглядає три основні стилі.

REST: ресурс-орієнтований, використовує HTTP методи (GET, POST, PUT/PATCH, DELETE). Стан не зберігається: кожен запит містить всю потрібну інформацію. Широко застосовується в вебі та мобільних додатках.

GraphQL: мова запитів, що дозволяє клієнту запитувати лише потрібні дані через один endpoint. Операції: query (читання), mutation (зміна), subscription (реальний час). Мінімізує кількість запитів — наприклад, у REST для отримання даних про користувача, його пости та підписників потрібно три запити, а GraphQL може зробити це за один. Рекомендується для складних інтерфейсів.

gRPC: високопродуктивний RPC-фреймворк від Google, який використовує Protocol Buffers і HTTP/2. Підтримує потокову передачу. Найкраще підходить для комунікації між мікросервісами, оскільки швидший за HTTP, але потребує підтримки HTTP/2, тому рідко використовується в браузерах.

Автор наводить порівняння REST і GraphQL: у REST endpointи ресурсні (/api/v1/users/123), відповіді мають фіксовану структуру, версіонуються (v1, v2); GraphQL має один endpoint (/graphql), клієнт визначає структуру відповіді (наприклад, query { user(id: 123) { name posts { title } } }), версіонування зазвичай не потрібне, але можна додавати поля з префіксами.

Принципи дизайну API

Хороший API має бути:

  • Консистентним — однакове іменування (camelCase чи snake_case) та патерни.
  • Простим — мінімум складності; найкращий API — той, яким можна користуватися без документації.
  • Безпечним — автентифікація, авторизація, валідація вхідних даних, rate limiting.
  • Продуктивним — кешування, пагінація, мінімальні payloads, зменшення кількості запитів.

Вибір протоколу (HTTP, WebSockets, AMQP, gRPC) та транспортний рівень (TCP/UDP)

Протоколи прикладного рівня визначають, як клієнт і сервер спілкуються. HTTP/HTTPS — основа веб-API, забезпечує запит-відповідь, методи, статус-коди, заголовки. HTTPS додає шифрування (TLS/SSL). WebSockets — дозволяють двобічний реальний час (сервер може самостійно надсилати дані клієнту, наприклад, для чату). Це зменшує затримку та навантаження порівняно з опитуванням HTTP. AMQP (Advanced Message Queuing Protocol) — використовується для асинхронної черги повідомлень; продюсер публікує повідомлення, які зберігаються в черзі, а консюмер витягує їх, коли має ресурс. gRPC — працює поверх HTTP/2, підтримує streaming, найкращий для внутрішньої комунікації серверів.

Транспортний рівень (TCP vs UDP): TCP — надійний, орієнтований на з’єднання, гарантує доставку всіх пакетів у правильному порядку (три-етапне рукостискання), але повільніший. Підходить для платежів, автентифікації, пошти. UDP — швидкий, без встановлення з’єднання, без гарантії доставки, менше накладних витрат. Ідеальний для відео, ігор, стрімінгу, де втрата окремих пакетів допустима.

RESTful API детально: ресурси, CRUD, статус-коди, фільтрація, сортування, пагінація

У REST ресурси — іменники (products, orders). URL будуються як /api/v1/products (колекція) або /api/v1/products/{id} (один елемент). Вкладені ресурси: /products/{id}/reviews. Фільтрація через query parameters: ?category=electronics&inStock=true. Сортування: ?sort=price:asc. Пагінація: ?page=3&limit=10 або ?offset=20&limit=10 або cursor-based.

HTTP методи: GET (читання, безпечний та ідемпотентний), POST (створення, неідемпотентний), PUT (повна заміна), PATCH (часткове оновлення), DELETE (видалення). Статус-коди: 200 OK, 201 Created, 204 No Content; 301, 302 (перенаправлення); 400 Bad Request, 401 Unauthorized, 404 Not Found; 500 Internal Server Error. Кращі практики: використовувати множину для ресурсів, правильні HTTP методи, підтримувати фільтрацію/сортування/пагінацію, версіонувати API (v1, v2) для зворотної сумісності.

GraphQL: схема, запити, мутації, обробка помилок

GraphQL вирішує проблему over-fetching та under-fetching даних. Схема — контракт між клієнтом і сервером, визначає типи (наприклад, type User { id: ID, name: String, posts: [Post] }), запити (query { user(id: 123) { name } }) та мутації (mutation { createPost(title: "...", body: "...") { id, title } }). GraphQL завжди повертає статус 200, а помилки передаються в полі errors у відповіді. Кращі практики: тримати схеми малими та модульними, обмежувати глибину вкладеності, використовувати змістовні імена, для мутацій — вхідні типи.

Автентифікація

Автентифікація відповідає на питання «хто ти?». Розглянуто типи:

  • Basic Authentication — base64-кодування username:password; небезпечний без HTTPS, рідко використовується.
  • Bearer Tokens — токен передається в заголовку Authorization: Bearer <token>; швидко, stateless, стандарт для API.
  • OAuth2 + JWT — користувач входить через провайдера (Google, GitHub), який повертає JWT-токен із даними (user ID, email, термін дії). JWT підписаний, stateless.
  • Access & Refresh Tokens — короткоживучий access token для API-запитів, довгоживучий refresh token для отримання нового access token; refresh token зберігається на сервері для безпеки.
  • SSO (Single Sign-On) — один вхід для кількох сервісів (наприклад, Google — Gmail, Drive, Calendar). Використовує протоколи SAML (XML, застарілий) або OAuth2 (JSON, сучасніший).

Авторизація

Авторизація визначає «що тобі дозволено робити». Три основні моделі:

  1. RBAC (Role-Based Access Control) — користувачам призначаються ролі (admin, editor, viewer) з фіксованими наборами дозволів. Приклад: GitHub — admin має повний доступ, editor може редагувати, viewer — лише читати.
  2. ABAC (Attribute-Based Access Control) — дозвіл залежить від атрибутів користувача (відділ, вік), ресурсу (конфіденційність) та середовища (час, місце). Наприклад: «дозволити доступ, якщо відділ = HR і документ є внутрішнім». Гнучкіше, але складніше.
  3. ACL (Access Control Lists) — кожен ресурс має список користувачів із дозволами (наприклад, Google Doc: Alice — read, Bob — edit). Дуже специфічно, важко масштабувати на мільйони ресурсів, але використовується (Google Drive).

Як це реалізується на практиці: OAuth2 делегує авторизацію (наприклад, Vercel отримує токен із обмеженими правами на GitHub репозиторій). JWT або bearer токени несуть інформацію про ролі та дозволи, а сервер застосовує логіку RBAC/ABAC на основі цього токена.

Безпека API: rate limiting, CORS, SQL/NoSQL ін’єкції

API потребують захисту. Rate Limiting обмежує кількість запитів від клієнта за одиницю часу (наприклад, 100 запитів/хв). Без цього зловмисник може перевантажити систему (DDoS) або зламати пароль перебором. Ліміти можна встановлювати на рівні endpoint, на IP-адресу або загалом (total rate limit) для захисту від ботів. CORS (Cross-Origin Resource Sharing) контролює, які домени можуть викликати API з браузера. Якщо не налаштувати, шкідливий сайт зможе робити запити від імені жертви. Наприклад, дозволяти тільки запити з app.yourdomain.com. SQL/NoSQL ін’єкції — якщо введені користувачем дані безпосередньо підставляються в запит до бази, зловмисник може змінити запит, щоб отримати або знищити дані. Наприклад, вставити в поле email ' OR '1'='1, щоб обійти перевірку.

Параметризовані запити для запобігання ін'єкціям

Автор наголошує, що використання звичайних SQL-запитів, у які безпосередньо вставляються дані від користувача, створює вразливість до SQL-ін'єкцій. Зловмисник може передати в поле введення спеціально сформований SQL-код, який буде виконано в базі даних. Щоб цього уникнути, слід завжди застосовувати параметризовані запити або засоби захисту, вбудовані в ORM (наприклад, Entity Framework, Hibernate). У параметризованих запитах дані передаються окремо від структури запиту, тому будь-який користувацький ввід сприймається лише як значення, а не як виконуваний код. Практичне значення: навіть якщо зловмисник спробує ввести '; DROP TABLE users; --, база даних сприйме це як рядок, а не як команду. Це один із найпростіших і водночас найефективніших способів захисту, який має бути стандартом у будь-якому додатку, що працює з базами даних.

Фаєрволи як фільтр трафіку

Другою важливою технікою автор називає фаєрволи, які діють як "воротарі" між вхідним трафіком і API. Фаєрвол аналізує кожен запит і блокує підозрілі, пропускаючи звичайні. Як приклад наводиться AWS Web Application Firewall (WAF), який може виявляти невідомі патерни атак, зокрема підозрілі SQL-ключові слова або нестандартні HTTP-методи. Таким чином, зловмисні запити не доходять до API, а нормальні – безперешкодно проходять. Висновок автора: фаєрвол є першою лінією оборони, яка знижує навантаження на саму логіку додатку, відсікаючи очевидно шкідливий трафік ще до того, як він потрапить у внутрішню мережу.

VPN для приватних API

Автор пояснює, що не всі API мають бути доступні з публічного інтернету. Деякі з них призначені лише для внутрішнього використання. Для таких випадків застосовують віртуальні приватні мережі (VPN). API, розташований у VPN-мережі, можуть досягти лише ті клієнти, які також під'єднані до тієї ж VPN. Наприклад, якщо ви маєте внутрішню адмін-панель, її API має бути доступним виключно для співробітників, які підключені до корпоративного VPN. Усі запити ззовні блокуються. Аргументація: такий підхід значно зменшує поверхню атаки, адже зловмисник не може навіть "постукати" у двері цього API, якщо він не перебуває всередині безпечної мережі. Це особливо важливо для бекенд-сервісів, панелей адміністрування та внутрішніх інструментів.

CSRF – міжсайтова підробка запитів

Автор детально описує атаку CSRF (Cross-Site Request Forgery). Суть її в тому, що зловмисник змушує браузер уже автентифікованого користувача виконати небажаний запит до чутливого API. Наприклад, користувач увійшов у банківську систему, яка використовує сесійні куки для автентифікації. Якщо ця система не має додаткового захисту, інший шкідливий сайт може підставити куку користувача та відправити прихований запит на переказ грошей. Щоб запобігти цьому, потрібно використовувати CSRF-токени разом із сесійною кукою. Система перевіряє не лише наявність куки, а й те, чи збігається переданий CSRF-токен із тим, що вона очікує. Якщо ні – запит блокується. Практичне значення: CSRF-токени дозволяють відрізняти легітимні запити, які здійснює сам користувач через свій інтерфейс, від підроблених запитів, ініційованих стороннім сайтом. Це стандартний механізм захисту в сучасних веб-фреймворках.

XSS – міжсайтовий скриптинг

Останньою технікою, розглянутою у відео, є захист від XSS (Cross-Site Scripting). Автор пояснює, як атака відбувається на практиці: зловмисник у полі коментаря (або іншому текстовому полі) вставляє шкідливий JavaScript-код замість звичайного тексту. Якщо API зберігає цей код у базу даних без належного екранування, то коли інший користувач завантажує сторінку з цим коментарем, браузер виконує шкідливий скрипт. Цей скрипт може, наприклад, викрасти куки іншого користувача або змінити вміст бази даних. Висновок автора: щоб запобігти XSS, необхідно завжди екранувати (або санітизувати) дані, що надходять від користувачів, перш ніж відображати їх на сторінці. Також слід використовувати заголовки Content Security Policy (CSP) та не допускати зберігання необроблених скриптів у базі.

Завершальна частина: заклик до навчання

Після викладу технік автор переходить до промоції свого курсу DevMastery mentorship. Він зазначає, що теоретичні знання – це лише перші два стовпи курсу, а для справжнього опанування системного дизайну потрібні практичні навички: створення систем з нуля в хмарних провайдерах (наприклад, AWS) і вміння пояснювати архітектурні рішення на співбесідах. Він пропонує 7-денний безкоштовний пробний період, під час якого можна отримати повний курс, реальні проєкти та особистий менторинг. Автор стверджує, що такі навички зроблять розробника незамінним і високооплачуваним незалежно від економічних коливань чи загрози AI.

Сподобався цей підсумок? Кинь будь-яке YouTube-відео нашому боту — отримай свій підсумок за 30 секунд.
Спробувати YTSummarAI

Не маєш 2 години на подкаст?

Кинь YouTube-лінк боту в Telegram — отримай ключові ідеї за 30 секунд. 9 зірок безкоштовно при старті.

Спробувати YTSummarAI