Методи масштабування реляційних баз даних: переваги, недоліки та кейси використання
Привіт! Мене звати Максим, я Lead Back-end Engineer у продуктовій ІТ-компанії OBRIO з екосистеми Genesis, беру участь у розвитку застосунку Nebula. У бекенд-розробці працюю понад пʼять років, мій основний стек — NodeJS і PHP.
Масштабування реляційних баз даних відіграє ключову роль у підтримці високої продуктивності та доступності високонавантажених систем. Є чимало підходів: реплікація Master/Slave та Master/Master, функціональне та горизонтальне партиціювання, шардинг, денормалізація. У цій статті розповім про переваги та недоліки кожного з них, нюанси використання та навести кейси, коли ці методи працюють найкраще.
Реплікація
Реплікація — це процес створення та підтримки копій баз даних на різних вузлах з метою забезпечення високої доступності, збереження даних та розподілу навантаження. Це базовий підхід до масштабування реляційних БД, сама реплікація має дві схеми роботи: Master/Slave і Master/Master.
Master/Slave
Найпоширеніший та один з найефективніших підходів до масштабування. У ньому є головний (Master) вузол, який копіює дані на одну або декілька реплік (Slave). Це також може відбуватися у вигляді дерева, де Slave копіює дані в інші репліки.
Зазвичай у підході Master/Slave всі зміни (такі як insert/update/delete тощо) відбуваються на головному вузлі. Звідти їх отримують та зберігають репліки. Виходить, що Master відповідає за запис та читання, а Slave — тільки за читання.
Такий підхід може використовуватися для резервного копіювання, але в контексті масштабування — для розподілу навантаження. Маючи декілька копій БД, ми можемо балансувати запити залежно від навантаження кожного вузла. Це допомагає, якщо ви хочете на головному вузлі мати найменшу затримку оновлення даних.
Наприклад, у вас є мобільний застосунок, яким щодня користуються мільйони людей. Через велику кількість запитів основна база даних матиме велике навантаження, що призведе до уповільнення часу відгуку сервера. У той час, коли більшість користувачів лише читають контент (наприклад, переглядають пости та коментарі), база даних опрацьовує як запити на читання, так і на запис. Використовуючи підхід Master/Slave, ви можете розділити операції читання на декілька серверів, що зменшить час завантаження контенту і покращить користувацький досвід.
Переваги:
- чітке розділення ролей: один сервер БД виконує тільки функцію запису, а інші — тільки читання;
- простота налаштування: порівняно з Master/Master реплікацією, Master/Slave є простішою в налаштуванні та управлінні;
- відсутність конфліктів, оскільки лише один сервер БД (Master) опрацьовує записи;
- оптимізація ресурсів: завдяки розподілу ролей, можна налаштувати сервер під конкретну задачу. Наприклад, для ролі Slave можна виділити більше RAM для кешування;
- вузол Slave може служити для резервного копіювання і не впливатиме на інші сервери.
Недоліки:
- ризик втрати даних, якщо Master вийде з ладу до того, як всі дані реплікуються на Slave;
- додаткова складна логіка, щоби Slave зробити головним вузлом, якщо той вийде з ладу.
Master/Master
Підхід реплікації Master/Master корисний, коли вашій системі потрібно виконувати операції запису у великій кількості.
Наприклад, у вас є вебсайт, яким користуються люди з різних країн світу: створюють, редагують та видаляють контент. Щоби забезпечити найшвидший час відповіді в усіх регіонах, ви хочете розмістити сервери баз даних у різних географічних локаціях. Ваше завдання — забезпечити, щоб усі зміни були консистентні та синхронізовані між усіма вузлами в реальному часі.
Підхід Master/Master допоможе розв’язати цю проблему: зміни, внесені користувачем на одному сервері, автоматично реплікуються на всі інші, забезпечуючи консистентність даних у будь-якій точці світу.
Переваги:
- доступність: якщо один із серверів БД виходить з ладу, система продовжує працювати без збою, адже його роль можуть виконувати інші репліки;
- балансування: є можливість розділити навантаження всіх операцій;
- географічна розподіленість: для кращого відгуку репліки можна розділити за регіонами.
Недоліки:
- конфлікти записів: якщо два сервери одночасно вносять зміни в один рядок, виникає конфлікт, який потребує ручного втручання або специфічних стратегій вирішення;
- Master/Master конфігурація може бути складнішою для налаштування та обслуговування порівняно з Master/Slave;
- якщо використовується автоінкрементація для створення унікальних ID, потрібно налаштовувати репліки, щоби вони не генерували однакові ідентифікатори;
- безпека — оскільки декілька серверів БД можуть писати дані, можливі додаткові напрямки атак;
- збільшений ризик втрати даних: проблема, що виникла на одному сервері, може швидко поширитися на інші через реплікацію.
Спільні недоліки реплікації для Master/Slave і Master/Master:
- необхідність логіки в коді, яка буде перенаправляти запити на потрібний сервер БД або додатковий рівень для балансування навантаження між репліками;
- затримка оновлення даних: що більше ми маємо копій вузлів, то більше потрібно реплікувати даних, і це призводить до затримки;
- затримка відповіді: якщо відбувається забагато запитів на запис, то репліки не зможуть швидко обслуговувати в тому числі запити читання;
- збільшення інфраструктури: додаткові сервери потребують ресурсів на підтримку.
Функціональне партиціювання
Функціональне партиціювання (Functional Partitioning/Database Federation) — це стратегія розділення бази даних на менші, спираючись на їхні функції.
Наприклад, у вас є застосунок, у якому користувачі можуть спілкуватися у чатах та здійснювати покупки. Якщо все розмістити на одному сервері БД, будь-яке збільшення навантаження на один компонент може вплинути на продуктивність всієї системи. Цю монолітну базу даних можна розділити на три маленьких: Chat, User, Purchase, — тоді кожна частина системи зможе масштабуватися незалежно від інших, враховуючи індивідуальні потреби та навантаження. Це покращить загальну продуктивність системи та забезпечить більшу стабільність: проблеми в одному компоненті не будуть безпосередньо впливати на інші.
Переваги:
- зменшення кількості запитів, що зменшує час реплікації та відгуку відповідно;
- збільшення можливості кешування завдяки меншим розмірам бази даних;
- зменшення витрат на інфраструктуру;
- паралельне виконання запитів;
- збільшення ізольованості певного функціонала.
Недоліки:
- ускладнення логіки на рівні коду: потрібно правильно визначити, до якої бази робити запит;
- складність інфраструктури;
- об’єднання даних із різних БД стає непростим завданням;
- труднощі роботи з транзакціями.
Шардинг
Суть цього методу — розділення однієї таблиці на декілька частин (шардів), кожна з яких зберігається на різних серверах.
Наприклад, у вас є популярна соціальна мережа з мільйонами користувачів. Щодня вони генерують великі об’єми даних: публікації, коментарі, лайки тощо. Одна база даних не зможе ефективно обробляти цей обсяг інформації, що призведе до уповільнення та можливих відмов. Використовуючи шардинг, ви зменшуєте навантаження на окремий сервер, розподіляючи дані та обробку запитів між декількома сегментами. Кожен із них має менший об’єм даних для обробки, завдяки чому зменшується час відгуку. Коли зʼявляється необхідність, ми можете додавати нові шарди, у такий спосіб масштабуючи систему.
Якщо ваш застосунок має глобальну аудиторію, можна розбити дані за регіонами, забезпечуючи швидкий відгук для користувачів із різних частин світу. Проте в такій реалізації може виникати нерівномірний розподіл навантаження, якщо певна група користувачів значно менше користується застосунком.
Переваги:
- зниження кількості запитів до сервера, часу реплікації та відповіді;
- збільшення даних в кеші через менші розміри бази даних;
- зменшення розміру індексу та часу запису;
- стабільність: якщо один шард вийде з ладу, інші працюватимуть;
- паралельний доступ до даних.
Недоліки:
- ускладнення логіки на рівні коду, що вимагає навичок роботи з шардами;
- складність об’єднання даних із різних сегментів;
- потреба в збільшенні інфраструктури та її підтримці;
- нерівномірне навантаження;
- проблеми з транзакціями при роботі з даними з різних шардів.
Денормалізація
Цей підхід передбачає дублювання даних або їхнє групування в БД, порушуючи правила нормалізації. Як це працює: ми дублюємо інформацію, щоб уникнути ресурсомістких операцій об’єднання (Join) та звернення до різних таблиць. У такий спосіб продуктивність запитів читання покращується шляхом запису.
Уявимо, що у вас є застосунок, у якому користувачі можуть спілкуватися в чатах з експертами. Вам потрібно віддавати клієнту список чатів разом з іменами співбесідників. Операція Join між двома дуже великими таблицями буде займати чимало часу. Ситуація погіршиться, якщо таких запитів буде багато. Щоби прискорити вибірку, можна перенести імена співбесідників до таблиці Chats, — тоді нам не потрібно робити Join.
Цей метод — досить ефективний, але потрібно відчувати межу, щоби дублі не повторювалися занадто часто. Інакше це призведе до неконсистентності даних.
Переваги:
- швидкість запиту: підвищення продуктивності вибірки за допомогою уникнення низки операцій Join в запиті;
- спрощена структура бази даних, якщо правильно застосувати цей метод.
Недоліки:
- дублювання даних;
- збільшення об’єму даних на диску: через дублювання обсяг зберігання може зростати, що підвищує вартість інфраструктури;
- неконсистентність даних: при дублюванні існує ризик, що оновлення може не пройти всюди, де треба;
- складність: забагато дублікатів може ускладнити систему, тому цей метод не можна використовувати надмірно.
Горизонтальне партиціювання
Цей метод передбачає розділення таблиці на сегменти (партиції) на одному сервері за визначеною логікою, наприклад за часом створення запису. Зазвичай у такому підході ви звертаєтеся до однієї віртуальної таблиці, а СУБД вирішує, до якої фізичної таблиці звертатися.
Наприклад, у вас є велика база даних для вебмагазину, яка зберігає історію покупок користувачів. Таблиця Замовлення містить мільйони рядків, її обробка та аналіз із часом сповільнюються та стають неефективними. Крім того, резервне копіювання та відновлення такої великої таблиці може бути часозатратним. Можна розділити її на партиції за місяцями або роками. Наприклад, одна частина буде містити всі замовлення за січень 2023 року, інша — за лютий 2023 року тощо. Запити до БД, які обробляють лише певний діапазон даних (наприклад, замовлення за певний місяць), будуть швидше виконуватися, оскільки вони звертатимуться лише до однієї партиції, а не до усієї великої таблиці. Операції з управління даними (наприклад, видалення старих замовлень) можуть бути спрощені, оскільки можна просто видалити цілу частину.
Переваги:
- зменшення розміру індексів, що суттєво прискорює операцію запису;
- швидке видалення даних за певною ознакою, що не блокує інші частини таблиці;
- простота налаштування та використання, адже зазвичай СУБД дає це «з коробки».
Недоліки:
- складність керування транзакціями: коли дані розподілені між підтаблицями, це може призвести до додаткових труднощів, особливо при роботі з декількома партиціями одночасно;
- цей підхід не впливає на доступність системи: якщо сервер БД впаде, вся система не буде працювати.
Висновки
Отже, кожен підхід має свої переваги та недоліки, і вибір залежить від конкретних вимог та цілей бізнесу. Адаптація та гнучкість у виборі методу масштабування дозволяють командам оптимізувати витрати ресурсів, забезпечити стабільність та ефективність роботи їхніх систем.
Тим, кому цікава тема масштабування баз даних, можу порекомендувати книгу «High Performance MySQL: Optimization, Backups, Replication, and More», а також цю статтю.
99 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів