Проектування систем: Спрощений посібник для початківців – все, що вам потрібно знати (Частина 1)

pic

Привіт усім, це Лоренцо з новим випуском "The Software Frontier"!

У кожному наступному випуску The Software Frontier ми періодично досліджуватимемо ключові проблеми та інновації, які визначають майбутнє програмної інженерії, DevOps програмування та новітніх технологій. Через призму інженерів-менеджерів та старших інженерів ми розглянемо найкращі практики для масштабування систем, оптимізації CI/CD пайплайнів, керування хмарною інфраструктурою та використання передових інструментів, що формують технологічну індустрію, намагаючись пояснити їх простими словами.

Отримуйте щотижневі аналітичні матеріали, погляди експертів та практичні поради щодо сучасної розробки програмного забезпечення та операцій, прямо на вашу поштову скриньку. Зануртесь глибше у складнощі цієї галузі з ексклюзивним контентом на моєму Substack. Підписуйтесь зараз:

The Software Frontier | Lorenzo Bradanini | Substack.

Цей блог створено для повних новачків, які не мають попереднього досвіду в системному дизайні. Він пропонує покроковий посібник з освоєння концепцій системного дизайну, що дозволяє впевнено відповідати на запитання під час співбесід і отримати цінні знання для вашої кар'єри. Окрім теоретичних аспектів, цей серіал занурюється у практичні реалізації, забезпечуючи набуття не лише інтерв’ю-орієнтованих навичок, але й розуміння принципів системного дизайну в реальному світі.

Протягом цього серіалу ми розглянемо кілька важливих питань, зокрема:

  • Що таке системний дизайн і чому він важливий у програмній інженерії?
  • Як підходити до розподілу складних систем на керовані компоненти?
  • Які основні принципи масштабованості, надійності та підтримуваності?
  • Як розробляти системи, що можуть обробляти великий трафік?
  • Які найкращі практики забезпечення високої доступності та відмовостійкості в розподілених системах?
  • Які реальні приклади проблем системного дизайну в сучасних технологічних компаніях?

До кінця цього серіалу ви не лише отримаєте чітке розуміння теорії системного дизайну, а й практичний досвід, необхідний для вирішення реальних проблем з більшою впевненістю.

1. Чому варто вивчати системний дизайн?

На перший погляд це може здатися очевидним питанням, чи не так? Але насправді воно набагато важливіше, ніж здається. Розуміння чому вивчення системного дизайну є необхідним, виходить за межі простого розуміння викликів, пов’язаних з обробкою великих додатків. Справа в тому, щоб оцінити складність, що виникає при створенні систем, які повинні бути надійними, безпечними та ефективними, особливо коли йдеться про мільйони або навіть мільярди користувачів. Коли ви тільки починаєте розробляти додатки, особливо під час навчання в університеті чи в особистих проєктах, ви, можливо, створюєте простий бекенд за допомогою фреймворку на кшталт Node.js (або іншої мови чи фреймворку), підключеного до бази даних. Архітектура таких проєктів, як правило, проста: користувач або клієнтське застосування (наприклад, веб-додаток на ReactJS або Android додаток) надсилає запит до бекенду, сервер виконує обчислення або витягує дані, а база даних виконує операції CRUD (Create, Read, Update, Delete), щоб повернути відповідь.

Це працює добре для малих додатків або прототипів, але в реальному світі все значно складніше. Коли ваш додаток має обслуговувати мільйони або мільярди користувачів, базова архітектура, яку ви створили для особистого проєкту, може не витримати навантаження. Вам потрібно розробити систему, яка здатна обробляти величезні обсяги трафіку, забезпечувати відмовостійкість, гарантувати безпеку, підтримувати високу доступність і моніторити продуктивність, щоб забезпечити ефективну роботу системи за будь-яких умов.

Саме тут на допомогу приходить системний дизайн. Системний дизайн — це процес структуризації та планування архітектури вашої системи, щоб успішно вирішувати реальні виклики.
Це передбачає роздуми про різні компоненти вашої системи, їх взаємодію та те, як забезпечити їх безперебійну та ефективну роботу, особливо на великих масштабах.

Масштабування

Коли ви починаєте працювати з мільйонами або, у деяких випадках, мільярдами користувачів, система повинна бути спроектована для масштабування, щоб справлятися зі збільшенням навантаження. Простими додатками, що працюють на одному сервері — або навіть кількох серверах — не вдасться обробити навантаження десятків тисяч запитів на секунду. Масштабування вашого додатку є важливим для забезпечення його гарної продуктивності у міру зростання трафіку. Це включає як вертикальне масштабування (додавання ресурсів до одного сервера), так і горизонтальне масштабування (розподіл навантаження на кілька серверів). Такі концепції ставлять кілька важливих питань, одне з яких:

Як обрати між вертикальним та горизонтальним масштабуванням для вашого додатку?

Ми детально розглянемо це питання та багато інших у наступних розділах, щоб надати точні відповіді та допомогти вам орієнтуватися в складнощах системного дизайну.

Відмовостійкість

У реальному світі сервери неминуче виходять з ладу, а збої в мережі трапляються. Проєктування систем, здатних граціозно обробляти такі збої без краху, є необхідним для підтримання надійності. Відмовостійкість — це здатність системи продовжувати функціонувати належним чином навіть тоді, коли окремі компоненти виходять з ладу. Це важливо для того, щоб перерви в одній частині системи не впливали на загальний користувацький досвід.

Щоб досягти відмовостійкості, потрібно спроектувати систему з такими ключовими механізмами:

  • Резервування: Це передбачає наявність кількох копій критичних компонентів, чи то сервери, бази даних або сервіси. Резервування забезпечує, що якщо один екземпляр виходить з ладу, інший може взяти на себе роботу без перерв. Наприклад, наявність кількох реплік бази даних може забезпечити доступність даних, якщо основний сервер бази даних вийде з ладу.
  • Реплікація: Реплікація даних означає створення копій ваших даних і розподіл їх по різних серверах або географічних локаціях. Це особливо важливо для баз даних і розподілених систем. Реплікація даних на кількох вузлах дозволяє підтримувати доступність і цілісність даних, навіть якщо один сервер або дата-центр стає недоступним.
  • Механізми перемикання на резерв: Перемикання на резерв — це процес автоматичного переходу на резервну систему у разі збою. Наприклад, якщо один сервер або екземпляр бази даних стає нереспонсивним, система перемикання на резерв автоматично перенаправить трафік до здорового сервера або репліки. Це забезпечує високу доступність та мінімальні перерви для користувачів.
  • Балансування навантаження: Балансування навантаження розподіляє вхідний мережевий трафік між кількома серверами або екземплярами, допомагаючи забезпечити, щоб жоден сервер не був перевантажений. У разі збою балансувальники навантаження можуть виявити неактивний сервер і перенаправити трафік до доступних екземплярів, що додатково підвищує надійність системи.
  • Запобіжники та граціозне зниження продуктивності: У архітектурах мікросервісів запобіжники (circuit breakers) використовуються для запобігання каскадним збоям. Якщо якийсь сервіс починає давати збій, запобіжник забороняє подальші запити до нього, даючи сервісу час на відновлення. Граціозне зниження продуктивності гарантує, що навіть якщо деякі частини системи вийдуть з ладу, загальна система продовжує працювати, хоч і з деяким зниженням потужностей.

Інтегруючи ці стратегії, ви можете забезпечити, що ваша система залишатиметься працездатною навіть під час збоїв. Це не лише підвищує надійність, але й створює довіру у користувачів, адже вони можуть продовжувати взаємодіяти з вашим додатком без значних перерв або зупинок.

Безпека

Коли йдеться про обробку великих обсягів користувацьких даних, безпека стає пріоритетним питанням.
Без належних заходів безпеки ваша система може стати вразливою до різноманітних атак, включаючи витоки даних, SQL ін'єкції (SQL injection), міжсайтові скрипти (XSS) та розподілені атаки відмови в обслуговуванні (DDoS). Ці типи атак можуть скомпрометувати чутливу інформацію користувачів, порушити роботу сервісів і завдати серйозної шкоди вашій репутації.

Для проєктування безпечної системи необхідно зосередитися на кількох ключових аспектах. По-перше, автентифікація (authentication) та авторизація (authorization) є фундаментальними. Автентифікація гарантує, що користувачі, які отримують доступ до вашої системи, є тими, за кого себе видають. Зазвичай це здійснюється через методи на кшталт імен користувачів і паролів, з додатковими шарами безпеки, такими як багатофакторна автентифікація (MFA), для забезпечення додаткової захищеності. Авторизація, у свою чергу, гарантує, що автентифіковані користувачі мають доступ лише до ресурсів та дій, до яких вони мають право доступу. Наприклад, звичайний користувач не повинен мати доступу до адміністративних функцій.

Іншим важливим заходом є шифрування даних (data encryption). Усі чутливі дані, які передаються через мережу, повинні бути зашифровані під час передачі, щоб захистити їх від перехоплення зловмисниками. Протоколи, як-от HTTPS, є необхідними для захисту даних під час їх пересування між користувачами та вашими серверами. Так само важливо зашифровувати дані в стані спокою — це означає шифрування чутливої інформації, що зберігається у ваших базах даних чи файлах. Навіть якщо хтось отримає несанкціонований доступ до вашої системи зберігання, зашифровані дані будуть незрозумілі без відповідних ключів дешифрування.

Для запобігання таким атакам, як SQL ін'єкція (SQL injection) та XSS, також необхідно вивіряти та санітувати (sanitize) введені користувачем дані. Коли користувачі відправляють дані — будь то через форми, URL або API — важливо переконатися, що ці дані безпечні та не містять шкідливого коду. Завдяки санітації введених даних можна уникнути можливості для зловмисників вставляти шкідливі скрипти чи запити, які можуть скомпрометувати безпеку вашої системи.

Обмеження швидкості (rate limiting) та уповільнення (throttling) також є ключовими стратегіями в захисті від атак DDoS та спроб підбору паролів. Обмеживши кількість запитів, які користувач або сервіс може здійснити за короткий проміжок часу, ви можете запобігти тому, щоб зловмисники не навантажили вашу систему надмірним трафіком або не намагалися відгадати паролі.

Нарешті, безпека — це постійний процес. Регулярні аудити (audits) та поточне оновлення (patching) необхідні для підтримки вашої системи в безпеці. Проведення регулярних аудиторських перевірок дозволяє виявляти вразливості до того, як зловмисники їх використають. Також важливо підтримувати оновленими ваше програмне забезпечення, бібліотеки та залежності, оскільки регулярно випускаються патчі для виправлення нововиявлених вразливостей.

Інтегруючи ці практики в дизайн вашої системи, ви можете забезпечити збереження та безпеку даних користувачів. Добре захищена система не лише захищає користувачів від небезпеки, а й створює довіру, гарантуючи, що ваш додаток залишатиметься надійним та працездатним перед потенційними загрозами.

Моніторинг та спостережуваність

Якщо ваша система вже працює в реальному середовищі та обробляє реальний трафік, важливо мати інструменти для моніторингу її стану та спостереження за її продуктивністю. Без належного моніторингу стає важко виявляти проблеми або зниження продуктивності, поки це не буде занадто пізно. Це може призвести до розчарованих користувачів, збоїв у роботі сервісів чи навіть до простоїв системи. Інтегруючи логування (logging), моніторинг (monitoring) та системи сповіщення (alerting), ви можете проактивно виявляти та вирішувати проблеми, перш ніж вони вплинуть на ваших користувачів. Наприклад, логи можуть зафіксувати детальну інформацію про операції системи, допомагаючи виявити проблеми в реальному часі.

Моніторинг надає інформацію про загальний стан вашої системи, відстежуючи важливі метрики, як-от час відповіді, рівень помилок та використання ресурсів (наприклад, CPU, пам'ять, диск).
З цими метриками у вас є змога швидко помітити аномалії чи вузькі місця, які можуть вказувати на проблему.

Системи сповіщення (Alerting) також важливі, оскільки вони миттєво повідомляють вас, коли щось йде не так — чи то раптове збільшення кількості помилок, висока затримка, чи несподіване зниження трафіку. Це дозволяє вжити заходів до того, як проблема стане серйознішою і вплине на користувачів.

Спостережуваність (Observability) виходить за межі базового моніторингу, дозволяючи відслідковувати потік запитів через різні сервіси в розподіленій системі. Це означає, що ви можете відстежувати, як дані рухаються через різні компоненти, виявляти, де відбуваються збої, і визначати першопричину проблем. Спостережуваність допомагає краще розуміти поведінку системи та її продуктивність, що полегшує підтримку високого рівня надійності та покращує загальний досвід користувачів.

Надійність

Як забезпечити, щоб ваша система залишалася надійною при обробці мільйонів або навіть мільярдів користувачів?

У таких масштабних системах надійність (reliability) є критично важливою. Ви не можете дозволити собі часті простої або погану продуктивність, оскільки це може суттєво вплинути на досвід користувачів та довіру до вашої системи. Це вимагає проєктування систем, які не тільки працюють добре, але й можуть швидко відновлюватися, коли щось йде не так. Наприклад, забезпечення узгодженості даних (data consistency) в розподілених системах, обробка мережевих розділень (network partitions) та наявність механізмів швидкого відновлення (quick recovery) є важливими елементами підтримки надійності. Орієнтуючись на ці аспекти, ви можете створити системи, які залишаються стійкими та чуйними навіть під час збоїв чи непередбачуваних проблем.

Ефективність

Коли ви працюєте з масштабними системами, ефективність стає критичним фактором, який потрібно враховувати не лише з точки зору продуктивності, а й з точки зору витрат. Система, яка працює добре, але споживає надмірні ресурси, може швидко стати дорогою в обслуговуванні, особливо на великих масштабах. Важливо проєктувати системи, які є як високопродуктивними (highly performant), так і економічно ефективними (cost-effective). Оптимізація продуктивності означає забезпечення того, щоб ваша система швидко реагувала на запити користувачів, водночас зберігаючи ефективне використання ресурсів, таких як пам'ять, процесор і сховище. Це безпосередньо впливає як на досвід користувачів, так і на загальні операційні витрати.

Щоб досягти цієї рівноваги, потрібно звернути увагу на різні аспекти архітектури системи. Моделі даних (Data models) повинні бути спроєктовані для ефективності, щоб структура даних підтримувала швидкі запити та мінімальне споживання ресурсів. Оптимізація запитів (Query optimization) також є важливою, оскільки неефективні запити до бази даних можуть швидко стати вузьким місцем, сповільнюючи систему та збільшуючи навантаження на вашу інфраструктуру. Тонка настройка запитів, додавання індексів та аналіз планів виконання дозволяють значно покращити час відгуку.

Крім того, кешування (caching) відіграє важливу роль в підвищенні ефективності системи. Зберігаючи часто запитувані дані в пам'яті (наприклад, використовуючи Redis або Memcached), ви можете зменшити потребу в повторних запитах до повільніших баз даних, що призведе до швидших часів відгуку та зменшення навантаження на бекенд системи. Добра стратегія кешування забезпечує, щоб ваша система залишалася чуйною навіть під час великих навантажень, одночасно економлячи обчислювальні ресурси.

2. Розуміння серверів

Що таке сервер?

Ви, мабуть, вже чули термін сервер (server), але якщо ви тільки починаєте, давайте пояснимо це так, щоб було зрозуміло. В основному, сервер (server) — це просто фізична або віртуальна машина — можна подумати про неї як про потужний комп'ютер — який хостить додатки та робить їх доступними через інтернет. Якщо ви коли-небудь створювали простий додаток за допомогою ReactJS або NodeJS, ваш додаток, ймовірно, працює на

http://localhost:8080,

де localhost означає ваш комп'ютер, а 8080 — це порт, на якому ваш додаток чекає на вхідні запити.
Це підходить для тестування та розробки, але якщо ви хочете зробити свій додаток доступним для інших, вам потрібно використовувати сервер.

Коли ви хочете зайти на вебсайт, наприклад,

https://abc.com,

ваш браузер робить кілька специфічних операцій. Спочатку він звертається до системи під назвою DNS (Система доменних імен) для того, щоб перетворити доменне ім'я на IP-адресу — унікальний ідентифікатор сервера в інтернеті. Це схоже на пошук адреси когось у телефонному довіднику, щоб надіслати йому листа. Наприклад, abc.com може перетворюватися на IP-адресу, як-от 35.154.33.64. Це фізична адреса сервера, який хостить вебсайт. Коли браузер отримує IP-адресу сервера, він надсилає запит на той контент, який вам потрібен. Сервери, подібно до вашого комп'ютера, часто виконують багато різних додатків. Для того, щоб сервер знав, на який додаток реагувати, він використовує порти. Число 443 в URL

https://abc.com:443

вказує серверу, що запит стосується захищеної веб-сторінки (HTTPS), яку потрібно обробити за допомогою правильного додатку. Порти діють як двері, які спрямовують трафік до певних сервісів, що працюють на сервері. Одне з ключових спостережень тут: хоча технічно можна звертатися до сервера за його IP-адресою (наприклад, 35.154.33.64:443), доменно-іменні адреси дозволяють нам зручніше орієнтуватися в інтернеті, не потрібно пам'ятати складні числа. Тому, abc.com — це просто зручний спосіб доступу до 35.154.33.64.

Як розгорнути додаток

Тепер давайте поговоримо про те, як можна взяти ваш додаток, який, можливо, працює локально на вашому комп'ютері, і зробити його доступним для світу.

Уявіть, що ви створили веб-додаток на вашій локальній машині. Зараз він доступний лише через

http://localhost:8080,

але що якщо ви хочете, щоб інші могли відвідати ваш сайт з будь-якої точки світу? Ось тут і входить в гру процес розгортання.

Перший крок — це отримати публічну IP-адресу. На відміну від приватної IP-адреси, яку ваш ноутбук використовує для комунікації з іншими пристроями в локальній мережі, публічна IP-адреса дозволяє кожному звертатися до вашого сервера з інтернету. Технічно ви можете прикріпити свій додаток до публічної IP-адреси вашого ноутбука, зробивши його доступним для світу, але це має кілька суттєвих мінусів. Керування власним сервером, забезпечення його безпеки та вирішення технічних завдань хостингу можуть швидко стати надто складними.

Саме тому більшість розробників обирають орендувати сервери у хмарних постачальників таких як AWS, Azure або Google Cloud Platform (GCP). Ці хмарні постачальники пропонують віртуальні машини — по суті потужні комп'ютери в хмарі — які готові для хостингу вашого додатку. Наприклад, у AWS ця віртуальна машина називається EC2 instance (Elastic Compute Cloud). Це схоже на оренду серверу, але вам не потрібно турбуватися про фізичне обладнання.

Після того як ви орендуєте віртуальну машину у хмарного постачальника, наступний крок — це розгортання (deployment) вашого додатку. Розгортання полягає у перенесенні коду вашого додатку з локальної машини на хмарну віртуальну машину. Після того як ваш код потрапить на сервер, хмарний постачальник призначає цій віртуальній машині публічну IP-адресу, що дозволяє кожному з IP-адресою або доменним ім'ям доступати ваш додаток. Це робить ваш додаток доступним у всьому світі, не потребуючи від вас керування інфраструктурою.

Ключові висновки:

  • Сервер (server) — це машина (фізична або віртуальна), яка запускає додатки і робить їх доступними через інтернет.
  • Коли ви вводите домен на кшталт abc.com, DNS перетворює його на IP-адресу, дозволяючи вашому браузеру надіслати запит до правильного сервера.
  • Публічні IP-адреси (Public IP addresses) використовуються для того, щоб зробити ваш сервер доступним для всього світу.
    Оренда віртуальної машини у хмарного постачальника, такого як AWS чи GCP, спрощує цей процес, надаючи вам потрібну інфраструктуру без необхідності самостійно керувати нею.
  • Розгортання (Deployment) включає перенесення вашого додатку з локальної машини на хмарний сервер, де його можуть використовувати інші.

Питання для обговорення: Як ви думаєте, що сталося б, якщо б сервер не мав публічної IP-адреси або доменного імені, і як це вплинуло б на доступ користувачів до вашого вебсайту?

3. Масштабування та його типи

Коли ви розробляєте програмне забезпечення, яке повинно обробляти великі обсяги трафіку або користувачів, масштабування — це один з найбільш важливих концептів, які потрібно розуміти. Масштабування — це процес налаштування ресурсів вашої системи відповідно до зростаючого попиту. Це дозволяє забезпечити, щоб ваш додаток залишався швидким, надійним і ефективним навіть у міру його зростання. Масштабування є критично важливим для будь-якого додатку, який хоче обробляти мільйони користувачів або мільярди запитів. Давайте детальніше розглянемо різні способи масштабування вашої системи та що включає кожен з цих підходів.

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

Уявіть, що ви створюєте онлайн-магазин. Спочатку ваш додаток може працювати чудово на вашому ноутбуці, з усіма необхідними ресурсами для обробки кількох запитів від ваших друзів. Але з ростом магазину і залученням реальних клієнтів навантаження на ваш додаток збільшується. Початковий сервер може не впоратися, тому вам потрібно масштабуватися. Вертикальне масштабування, також відоме як масштабування вгору, — це один з підходів до вирішення цієї проблеми.

Вертикальне масштабування означає збільшення ресурсів на одній машині. Це можна зробити шляхом оновлення ЦПУ (CPU), ОЗП (RAM) або зберігання (storage) вашого сервера. Тобто замість того, щоб отримати більший склад, ви фактично купуєте більший і потужніший сервер для запуску вашого додатку. З потужнішою машиною ваш додаток зможе обробляти більше трафіку, обробляти більше даних і обслуговувати більше користувачів.

Приклад: Уявіть, що ваш онлайн-магазин працює чудово з 2 ГБ ОЗП і двоядерним процесором. Але під час великої розпродажу попит різко зростає, і вам потрібно збільшити потужність машини. Оновивши сервер до процесора з 16 ядрами та 32 ГБ ОЗП, ваш сервер зможе обробляти набагато більше запитів на секунду, що дозволить вашому онлайн-магазину працювати під час пікових навантажень.

Переваги:

  • Легко впроваджувати. Вам не потрібно змінювати багато в самому додатку, оскільки все працює на одній машині.
  • Швидко масштабувати вгору, якщо ви знаєте, що ваша система потребуватиме більше потужності в короткий проміжок часу.
  • Легше управляти спочатку, порівняно з іншими формами масштабування.

Недоліки:

  • Фізичні обмеження: Незалежно від того, як потужним буде ваш сервер, він все одно має обмеження. Як тільки ви досягнете цього ліміту, покращити продуктивність вже неможливо.
  • Вартість: Високопродуктивні сервери дорогі, і чим більше ви оновлюєте, тим більше платите. Ви фактично орендуєте більшу машину за вищу ціну.
  • Єдина точка відмови: Якщо ця єдина машина виходить з ладу, весь ваш додаток припиняє роботу. Немає резервування для запобігання відключенням.

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

Зі збільшенням вашого додатку, ви з часом перевищите можливості вертикального масштабування. То що відбувається, коли ваш сервер більше не справляється з навантаженням? Рішення — це горизонтальне масштабування, також відоме як масштабування в сторони. Замість того, щоб оновлювати один сервер, горизонтальне масштабування передбачає додавання більше серверів до вашої системи для розподілу навантаження. Це схоже на те, як ви розвиваєте свій онлайн-магазин, додаючи більше співробітників для обслуговування зростаючої кількості клієнтів.

Приклад: Уявіть, що ваш онлайн-магазин швидко розвивається, і ваш сервер вже не може справлятися. Замість того, щоб купувати ще потужніший сервер, ви додаєте багато менших серверів, кожен з яких обробляє частину трафіку. Таким чином, жоден сервер не перевантажений, і ваша система стає набагато більш надійною.

З горизонтальним масштабуванням додаток ділиться на менші, незалежні частини, кожна з яких працює на своєму сервері.
Ключовим моментом є розподілені обчислення (distributed computing) — замість того, щоб один сервер обробляв все, трафік розподіляється між кількома серверами.

Переваги:

  • Краща масштабованість: Ви можете постійно додавати нові сервери для обробки зростаючого попиту, що робить систему більш масштабованою в довгостроковій перспективі.
  • Стійкість до відмов: Якщо один сервер вийде з ладу, інші можуть взяти на себе навантаження, забезпечуючи доступність та надійність вашої системи.
  • Резервування: Більше серверів означає, що ви можете зберігати резервні копії даних на кількох машинах, знижуючи ризик втрати даних.

Недоліки:

  • Складність: Управління кількома серверами вимагає більше налаштувань, моніторингу та конфігурації. Вам потрібно координувати роботу серверів, щоб вони працювали разом безперебійно.
  • Вартість: Більше серверів означає вищі витрати на апаратне забезпечення, електроенергію та обслуговування. Хоча сервери менші, вам все одно знадобиться значно більше їх для обробки того ж трафіку, який може обробити одна потужна машина.

Автоматичне масштабування

Якщо горизонтальне масштабування передбачає додавання серверів вручну, автоматичне масштабування (auto scaling) виводить це на новий рівень. Це динамічна система, де кількість серверів автоматично налаштовується залежно від попиту. Це дозволяє вашій системі масштабуватися в реальному часі, забезпечуючи, щоб використовувалися лише потрібні ресурси в будь-який момент.

Наприклад, уявіть, що ваш гіпотетичний онлайн-магазин має непередбачуваний трафік. В звичайні дні він може мати кілька тисяч відвідувачів, але під час спеціальної акції трафік може різко зрости до мільйонів користувачів. Автоматичне масштабування допомагає вашій системі автоматично адаптуватися до цих змін. Коли трафік високий, додаються нові сервери для задоволення попиту. Коли трафік знижується, сервери видаляються для збереження витрат.

Приклад: Припустимо, ви використовуєте хмарну платформу, таку як AWS. За допомогою автоматичного масштабування ви можете налаштувати правила, наприклад: "Додати більше серверів, коли використання ЦПУ перевищує 80%" або "Видалити сервери, коли трафік знижується нижче певного порогу." Таким чином, система забезпечує оптимальну продуктивність без вашого постійного контролю.

Переваги:

  • Економічність: Ви використовуєте тільки необхідні ресурси в будь-який момент часу, що робить це більш доступним, ніж постійно підтримувати масштабовану інфраструктуру.
  • Автоматичні коригування: Це усуває невизначеність у масштабуванні. Ваша система автоматично збільшує або зменшує кількість серверів залежно від реального попиту, без необхідності постійно моніторити її.
  • Гнучкість: Автоматичне масштабування може справлятися як з передбачуваними, так і з непередбачуваними піками трафіку.

Недоліки:

  • Складність налаштування: Вам потрібно налаштувати правильні правила та пороги для автоматичного масштабування, щоб воно працювало ефективно. Якщо ці параметри налаштовані неправильно, ваша система може масштабуватися неефективно.
  • Проблеми з затримкою: В залежності від того, наскільки швидко включається механізм автоматичного масштабування, може бути невелика затримка при обробці непередбачуваних піків трафіку, що може спричинити тимчасові проблеми з продуктивністю.

Балансування навантаження при масштабуванні

Коли ви масштабуєте горизонтально або використовуєте автоматичне масштабування, балансування навантаження (load balancing) стає ключовим компонентом інфраструктури. Балансувальники навантаження (Load balancers) відповідають за розподіл вхідного трафіку між вашими серверами, щоб жоден з них не був перевантажений, а інші залишалися без роботи.

Без балансувальника навантаження ваш додаток надсилав би весь трафік на один сервер, який може швидко бути перевантаженим, що призведе до уповільнення роботи або навіть до відмови системи. Балансувальник навантаження гарантує, що трафік розподіляється рівномірно, щоб кожен сервер обробляв лише кілька запитів.

Приклад: Уявіть, що у вас є п'ять серверів, які обслуговують ваш онлайн-магазин, кожен з яких обробляє частину трафіку користувачів. Балансувальник навантаження стоїть перед цими серверами і розподіляє вхідні запити користувачів — наприклад, перегляд товарів або оформлення покупок — так, щоб жоден сервер не був під великою навантаженням.
Це робить досвід користувачів більш плавним і надійним.

Переваги:

  • Рівномірний розподіл трафіку: Забезпечує ефективне використання всіх серверів без перевантаження жодного з них.
  • Висока доступність: Якщо один сервер вийде з ладу, балансувальник навантаження може перенаправити трафік на інші сервери, мінімізуючи час простою.
  • Стійкість до відмов: Хороший балансувальник навантаження може автоматично виявляти неполадки на сервері та перенаправляти трафік на інші сервери.

Недоліки:

  • Єдина точка відмови: Якщо сам балансувальник навантаження виходить з ладу, вся система може постраждати. Для балансувальника необхідні конфігурації високої доступності.
  • Навантаження: Балансувальник навантаження додає додатковий рівень складності і може створювати незначне навантаження на продуктивність, коли розподіляє трафік.

Торг між вартістю та продуктивністю

При масштабуванні системи завжди існує тонкий баланс між вартістю та продуктивністю. Додавання більше ресурсів — будь то оновлення одного сервера (вертикальне масштабування) або додавання кількох серверів (горизонтальне масштабування) — підвищує продуктивність, але також збільшує витрати. Ось тут і виникає компроміс.

  • Вертикальне масштабування є найпростішим, але часто найдорожчим для додатків з високим попитом, оскільки оновлення одного сервера потужним апаратним забезпеченням може обійтися дуже дорого.
  • Горизонтальне масштабування пропонує кращу масштабованість, але витрати зростають із кількістю серверів. Воно також вимагає більше управління та інфраструктури, тому хоча воно і ефективне, це не завжди найдешевший варіант у короткостроковій перспективі.
  • Автоматичне масштабування допомагає заощаджувати гроші, масштабуючи ресурси вгору та вниз залежно від реального попиту, але потребує уважної конфігурації, щоб уникнути неефективностей.

Ключове питання: Як балансувати масштабування та витрати, коли трафік непередбачуваний? Які стратегії можна застосувати для оптимізації витрат при збереженні високої продуктивності?

4. Затримка та пропускна здатність

Коли ви проектуєте систему, яка повинна обробляти великі обсяги даних або обслуговувати мільйони користувачів, два ключові показники продуктивності, на які потрібно звертати пильну увагу, — це затримка (latency) та пропускна здатність (throughput). Ці терміни часто зустрічаються в проектуванні систем, особливо коли йдеться про обробку великомасштабного трафіку, швидку обробку даних або відповіді на запити користувачів. Хоча вони можуть здаватися схожими, вони представляють дуже різні аспекти продуктивності системи, і обидва є важливими для створення швидких і ефективних додатків.

Ключові питання для роздумів:

  • Як оптимізувати як затримку, так і пропускну здатність для вашого конкретного випадку?
  • Чи будуєте ви додаток у реальному часі, де затримка є найбільш важливою (наприклад, онлайн-ігри)? Або високонавантажений додаток, де найбільше значення має пропускна здатність (наприклад, електронна комерція під час розпродажів)?
  • Які компроміси між зменшенням затримки та збільшенням пропускної здатності, і як знайти правильний баланс?

Що таке затримка?

Почнемо з затримки (latency). Простими словами, затримка — це час затримки, який проходить між моментом, коли дається інструкція на передачу даних, і моментом, коли ця передача починається. Тобто, затримка — це час, який потрібен системі, щоб відповісти на запит. Якщо ви відвідуєте вебсайт, затримка — це час від моменту, коли ви натискаєте на посилання, до того, як сторінка почне завантажуватися у вашому браузері.

Приклад: Уявіть затримку як подорож. Якщо ви намагаєтесь доїхати з точки A до точки B, затримка — це час, який проходить від моменту, коли ви вирушаєте, до того, як ви досягаєте вашого пункту призначення. Чим пряміший маршрут, тим менша затримка.

Фактори, що впливають на затримку:

  1. Мережеву відстань: Фізична відстань між клієнтом і сервером є суттєвим фактором. Якщо ви звертаєтеся до сервера в іншій країні, дані повинні пройти більшу відстань, що збільшує затримку.
  2. Мережеві затори: Велика кількість трафіку в мережі може спричиняти затримки в передачі даних. Це схоже на затор на дорозі.
    3.
    Продуктивність апаратного забезпечення: Повільні сервери, процесори або операції з дисковим вводу/виводу можуть збільшити затримку, оскільки для обробки запитів потрібно більше часу.
  3. Навантаження протоколів: Різні комунікаційні протоколи (наприклад, HTTP проти HTTPS) мають різні накладні витрати. Захищені з’єднання, такі як HTTPS, хоча і необхідні для безпеки, можуть додавати додаткову затримку.
  4. Затримки в черзі: У сильно навантажених системах запити можуть потрапляти в чергу, чекаючи на обробку. Це збільшує затримку, оскільки запити затримуються до моменту їх обробки.

Приклад: Уявіть, що ви звертаєтесь до онлайн-магазину, який розташований на іншому континенті. Чим довша відстань між вами та сервером, тим вища затримка, оскільки пакети даних займають більше часу на подорож туди і назад.

Оптимізація затримки:

  • Використання мереж доставки контенту (CDN): CDN розподіляє копії ваших даних по географічно розподілених серверах, зменшуючи відстань, яку мають подолати дані, що знижує затримку.
  • Обчислення на краю мережі (Edge Computing): Обробка даних ближче до користувача (на "краю" мережі) зменшує затримку, оскільки запити не потрібно надсилати до центрального сервера.
  • Ефективні протоколи: Оптимізація протоколів, які використовує ваш додаток (наприклад, HTTP/2 або QUIC), може знизити затримку.
  • Кешування: Зберігання часто запитуваних даних ближче до користувача за допомогою систем кешування допомагає уникнути повторних запитів до бази даних, зменшуючи затримку.

Що таке пропускна здатність?

Тепер зосередимося на пропускній здатності (throughput). Якщо затримка стосується того, як швидко система відповідає на один запит, то пропускна здатність пов'язана з обсягом запитів або даних, які можуть бути оброблені за певний проміжок часу. Це часто вимірюється в Запитах на секунду (RPS) або Транзакціях на секунду (TPS) в залежності від типу додатку. Іншими словами, пропускна здатність — це кількість операцій, яку система може обробити за певний період часу. Висока пропускна здатність означає, що система здатна обробляти багато запитів одночасно, а низька пропускна здатність вказує на обмежену здатність системи обробляти запити.

Для додатка пропускна здатність зазвичай означає, скільки даних можна передати, скільки запитів можна обробити або скільки транзакцій можна обробити за секунду. Висока пропускна здатність критична для додатків, які працюють з великими обсягами даних, таких як сервіси потокового відео або платформи електронної комерції.

Фактори, що впливають на пропускну здатність:

  1. Місткість сервера: Ресурси, доступні на сервері (наприклад, процесор, оперативна пам'ять, мережевий канал), можуть вплинути на те, скільки даних можна обробити та передати за певний час.
  2. Мережевий канал: Максимальна швидкість, з якою дані можуть передаватися по мережі, визначає пропускну здатність. Мережа з високою пропускною здатністю здатна обробляти більше даних на більшій швидкості.
  3. Конкурентність та паралелізм: Способність системи обробляти кілька запитів або процесів одночасно може значно вплинути на пропускну здатність. Системи, які можуть обробляти запити паралельно (замість послідовно), зазвичай мають вищу пропускну здатність.
  4. Оптимізація бази даних: Спільна здатність системи працювати з високою пропускною здатністю часто залежить від ефективності її шарів доступу до даних. Наприклад, індексація бази даних, оптимізація запитів та балансування навантаження можуть значно підвищити пропускну здатність.
  5. Вузькі місця в системі: Якщо якийсь компонент системи є повільним або має обмежену потужність, це може створити вузьке місце, зменшуючи загальну пропускну здатність системи.

Приклад: Припустімо, ваш онлайн-магазин може обслуговувати 100 клієнтів на секунду з 10 серверами.
Збільшення кількості серверів або оптимізація запитів до бази даних може дозволити магазину обробляти 500 клієнтів на секунду, тим самим покращуючи пропускну здатність.

Оптимізація пропускної здатності:

  • Балансування навантаження: Розподіл вхідного трафіку між кількома серверами гарантує, що жоден сервер не буде перевантажений, що дозволяє досягти вищої пропускної здатності.
  • Шардинг бази даних: Розподіл даних між кількома базами даних (шардами) дозволяє системі обробляти більше даних і запитів, що покращує пропускну здатність.
  • Кешування: Зберігання часто запитуваних даних в пам'яті зменшує кількість запитів до бази даних, що підвищує пропускну здатність.
  • Асинхронна обробка: Використання асинхронної або фонової обробки для задач, таких як відправка електронної пошти або завантаження файлів, гарантує, що ці задачі не блокують основний додаток, підвищуючи загальну пропускну здатність.

Затримка vs. пропускна здатність: Баланс

Хоча затримка та пропускна здатність є важливими показниками продуктивності, вони часто мають компроміси. Менша затримка бажана для реального часу додатків, таких як онлайн-ігри або трансляція відео в реальному часі, в той час як вища пропускна здатність критична для систем обробки пакетів або додатків, які потребують обробки багатьох запитів одночасно, таких як інтернет-магазин під час Чорної п’ятниці.

Проте покращення одного з параметрів іноді може вплинути на інший. Наприклад, зменшення затримки може вимагати використання серверів з вищою продуктивністю або кращої оптимізації мережі, що може знизити пропускну здатність через обмеження ресурсів системи. З іншого боку, збільшення пропускної здатності шляхом додавання нових серверів може збільшити затримку, якщо система стає більш складною і потребує додаткової координації.

Ключове питання: Як оптимізувати і затримку, і пропускну здатність? Які компроміси прийнятні для вашого конкретного додатка?

Основні висновки

При проектуванні масштабованих систем досягнення балансу між затримкою і пропускною здатністю є важливим для забезпечення оптимального користувацького досвіду та продуктивності системи. Розуміння того, що впливає на кожен з цих показників і як їх оптимізувати, може зробити велику різницю у створенні швидких, надійних і масштабованих додатків.

Ключовим моментом є постійне моніторинг продуктивності вашої системи, застосування правильних оптимізацій у потрібний час та забезпечення того, щоб і затримка, і пропускна здатність відповідали вашим цілям і очікуванням користувачів. Зрештою, це питання надання безперебійного досвіду користувачам, одночасно забезпечуючи, щоб ваша система могла ефективно обробляти зростаючі навантаження та вимоги до трафіку.

5. Балансувальники навантаження

У будь-якій системі, розрахованій на обробку значного трафіку, балансування навантаження стає важливим компонентом. Балансувальник навантаження — це сервер або програмне забезпечення, яке розподіляє вхідні запити між кількома серверами або ресурсами таким чином, щоб жоден сервер не був перевантажений. Завдяки цьому балансувальники навантаження допомагають оптимізувати використання ресурсів, підвищити надійність системи та покращити продуктивність.

Простими словами, балансувальник навантаження виступає в ролі менеджера трафіку, який направляє вхідні запити користувачів до різних серверів на основі певних правил або алгоритмів. Метою є забезпечення того, щоб кожен сервер обробляв оптимальну кількість трафіку, запобігаючи створенню вузьких місць.

Приклад: Уявіть концертний майданчик з кількома входами. Балансувальник навантаження буде направляти натовп до різних дверей залежно від кількості людей, що вже чекають біля кожного входу, щоб жодні двері не стали переповненими.

Чому балансувальники навантаження важливі?

  1. Масштабованість: Зі збільшенням кількості користувачів балансувальники навантаження полегшують горизонтальне масштабування системи шляхом додавання нових серверів і розподілу навантаження.
  2. Надійність: У разі відмови сервера балансувальники навантаження можуть перенаправити трафік до здорових серверів, забезпечуючи безперервну доступність.
  3. Ефективність: Вони забезпечують оптимальне використання кожного сервера, запобігаючи недоотриманню ресурсів.

Алгоритми балансування навантаження

Існує кілька алгоритмів, які балансувальники навантаження використовують для вирішення того, як розподіляти запити.
Кожен алгоритм має свої переваги, і його можна вибрати в залежності від потреб системи.

Загальні алгоритми балансування навантаження:

Round Robin:

  • Це найпростіший та найпоширеніший алгоритм балансування навантаження. Він розподіляє запити за круговим порядком між усіма доступними серверами, по черзі.
  • Приклад: Якщо є три сервери, Сервер 1 обробляє перший запит, Сервер 2 обробляє другий, а Сервер 3 — третій. Потім процес починається знову з Серверу 1.
  • Найкраще для: Систем, де всі сервери мають приблизно рівну потужність, і навантаження рівномірне.

Least Connections:

  • Цей алгоритм направляє трафік на сервер з найменшою кількістю активних підключень. Він корисний, коли навантаження на кожен запит може суттєво варіюватися, оскільки забезпечує, щоб сервер з найменшим навантаженням обробляв наступний запит.
  • Приклад: Якщо один сервер має 10 активних запитів, а інший — 3, балансувальник навантаження перенаправить наступний запит на сервер з 3 активними запитами.
  • Найкраще для: Систем з різним навантаженням на запити, де деякі запити є важчими за інші.

IP Hash:

  • У цьому підході балансувальник навантаження використовує хеш IP-адреси клієнта для того, щоб визначити, який сервер має обробити запит. Це гарантує, що запити конкретного клієнта завжди надходитимуть до одного і того ж сервера.
  • Приклад: Якщо користувач з IP-адресою 192.168.1.1 відвідує сайт, балансувальник навантаження завжди направлятиме його трафік на Сервер 2, базуючись на хеші його IP-адреси.
  • Найкраще для: Додатків, де необхідна збереження сесії (session persistence), або користувачі повинні постійно взаємодіяти з одним і тим самим сервером.

Weighted Round Robin:

  • Це вдосконалення стандартного алгоритму Round Robin. Кожному серверу призначається вага, яка залежить від його потужності, і запити розподіляються пропорційно до цієї ваги. Сервери з вищою потужністю обробляють більше запитів.
  • Приклад: Якщо Сервер 1 має вагу 2, а Сервер 2 має вагу 1, Сервер 1 обробляє два запити за кожен запит, оброблений Сервером 2.
  • Найкраще для: Систем, де деякі сервери є більш потужними за інші та повинні обробляти більшу частину навантаження.

Active-Active vs. Active-Passive конфігурації

При проектуванні систем для високої доступності та стійкості до збоїв важливим рішенням є те, як структурувати конфігурації серверів. Два поширених підходи — це Active-Active та Active-Passive конфігурації. Ці конфігурації визначають, як сервери обробляють трафік, збої та резервування.

Active-Active конфігурація:

У конфігурації Active-Active кілька серверів активно обробляють трафік одночасно. Кожен сервер у пулі обробляє запити та виконує роботу. Балансувальник навантаження розподіляє трафік серед усіх активних серверів, забезпечуючи, щоб жоден сервер не несе надмірного навантаження.

  • Приклад: Уявіть команду співробітників, які одночасно працюють над завданнями. Кожен співробітник активно бере участь, і робота розподіляється рівномірно.
  • Переваги:
    • Висока доступність: Якщо один сервер вийде з ладу, інші сервери продовжують обробляти трафік без простоїв.
    • Масштабованість: Легко додавати нові сервери до пулу для обробки збільшеного навантаження.
    • Найкраще для: Додатків, де критично важливі безперервність роботи та обробка великого обсягу трафіку, і де ресурси мають бути повністю використані.

Active-Passive конфігурація:

У конфігурації Active-Passive лише один сервер (активний сервер) обробляє трафік в будь-який час. Інші сервери (пасивні сервери) знаходяться в режимі очікування і готові прийняти навантаження, якщо активний сервер вийде з ладу.
Коли активний сервер виходить з ладу, пасивний сервер стає активним і починає обробляти трафік.

  • Приклад: Уявіть собі одного співробітника, який працює над усіма завданнями, а інші співробітники готові приєднатися, якщо основний працівник зробить перерву або стане недоступним.
  • Переваги:
    • Простота: Легше налаштувати та управляти, оскільки лише один сервер активно обробляє запити в будь-який момент часу.
    • Економічність: Зазвичай потрібно менше серверів, оскільки лише один сервер обробляє трафік в будь-який момент часу.
  • Недоліки:
    • Єдина точка відмови: Якщо активний сервер вийде з ладу і пасивний сервер не готовий його замінити, може виникнути простої.
    • Недовикористані ресурси: Пасивні сервери залишаються без дії, якщо не трапиться збій.
  • Найкраще для: Додатків, де потрібна висока доступність, але можна дозволити короткі простої під час переходу на резервний сервер, або для систем з меншими обсягами трафіку.

Вибір правильної конфігурації

Вибір між конфігураціями Active-Active та Active-Passive залежить від потреб вашої системи, бюджету та готовності до простоїв.

  • Active-Active є ідеальним для додатків, де критична висока доступність і продуктивність, а трафік високий і потребує ефективного розподілу.
  • Active-Passive найкраще підходить для менших додатків або систем, де важливий бюджет і короткі простої є прийнятними.

Ключові питання:

  • Який рівень доступності може дозволити ваша система?
  • Чи готові ви витрачати більше на інфраструктуру для забезпечення відсутності простоїв (Active-Active)?
  • Чи можете ви дозволити собі деякі простої, маючи інфраструктуру з нижчою вартістю (Active-Passive)?

Висновок: Створення надійних, масштабованих систем за допомогою ефективних принципів проектування

Протягом цього посібника ми охопили ключові елементи проектування систем, які є важливими для створення масштабованих, надійних і високопродуктивних додатків. Ми почали з масштабованості, обговоривши як вертикальне, так і горизонтальне масштабування для обробки зростаючої кількості користувачів. Масштабування — це не лише додавання ресурсів, а й прийняття розумних рішень для забезпечення ефективності та економічності.

Ми також розглянули важливість відмовостійкості, безпеки та надійності, щоб системи залишалися працездатними навіть за умов збоїв або загроз. Алгоритми балансування навантаження на кшталт Round Robin та Least Connections рівномірно розподіляють трафік між серверами. Ми також вивчили конфігурації Active-Active та Active-Passive для керування трафіком та відновлення. І нарешті, ми розглянули необхідність балансування вартості та продуктивності, оптимізуючи ресурси, зберігаючи надійність системи.

Ці принципи є основою для створення сучасних систем. У наступних розділах ми більш детально розглянемо реальні застосування, щоб ви були готові до вирішення задач проектування великих, стійких систем. Поєднуючи теоретичні знання з практичним застосуванням, ви будете добре підготовлені для створення масштабованих, безпечних і стійких систем, які витримають випробування часом.

Перекладено з: System Design Simplified: A Beginner’s Guide to Everything You Need to Know (Part 1)

Leave a Reply

Your email address will not be published. Required fields are marked *