Посібник із розуміння моделей масштабування бази даних

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

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

Тематичне дослідження

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

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

Але з плином часу все більше людей починають реєструватися у вашій системі, оскільки ви - найдешевший сервіс на ринку, завдяки вашій рекламі та рекламі. Ви починаєте бронювати, скажімо, 10 бронювань на хвилину, і повільно кількість збільшується до 20, 30 бронювань на хвилину.

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

Шаблон 1 - Оптимізація запитів та реалізація пулу з'єднань:

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

Ви виявляєте, що ваша база даних, ймовірно, сильно нормалізована, тому ви вводите кілька надлишкових стовпців (ці стовпці часто з’являються в запитах WHEREабо містяться в них JOIN ONу запитах) у широко використовуваних таблицях заради денормалізації. Це зменшує запити на приєднання, розбиває великий запит на кілька менших запитів і додає їх результати на прикладний рівень.

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

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

Виміряйте затримку ваших API і знайдіть, можливо, 20–50% або більше зменшеної затримки. Це хороша оптимізація на даний момент часу.

Тепер ви розширили свій бізнес до одного міста, більше клієнтів підписується, ви починаєте потихеньку робити 80–100 бронювань на хвилину. Ваша система не в змозі впоратися з цим масштабом. Знову ж таки, ви бачите, що затримка API збільшилася, рівень бази даних відмовився, але цього разу жодна оптимізація запитів не дає вам значного збільшення продуктивності. Ви перевіряєте системну метрику, виявляєте, що дисковий простір майже заповнений, процесор зайнятий 80% часу, оперативна пам’ять заповнюється дуже швидко.

Шаблон 2 - Вертикальне масштабування або масштабування:

Вивчивши всі системні показники, ви знаєте, що немає іншого простого рішення, аніж оновлення апаратного забезпечення системи. Ви збільшуєте об'єм оперативної пам'яті в 2 рази, дисковий простір, скажімо, в 3 рази і більше. Це називається вертикальним масштабуванням або збільшенням вашої системи. Ви повідомляєте свою команду інфраструктури, команду devops або сторонніх агентів ЦОД, щоб оновити вашу машину.

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

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

Класно. Ваша система знову працює і працює з підвищеною продуктивністю.

Ваш бізнес розвивається дуже добре, і ви вирішили масштабуватися до ще 3 міст - зараз ви працюєте в 5 містах. Трафік втричі більший, ніж раніше, очікується, що ви будете робити близько 300 бронювань на хвилину. Перш ніж навіть досягти цього цільового бронювання, ви знову стикаєтесь із кризією продуктивності, розмір індексу бази даних значно збільшується в пам'яті, він потребує постійного обслуговування, сканування таблиці за допомогою індексу стає повільнішим, ніж будь-коли. Ви розраховуєте вартість збільшення масштабу машини далі, але не впевнені у вартості. Що ти зараз робиш?

Шаблон 3 - Сегрегація відповідальності за командні запити (CQRS):

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

Тепер ви берете ще дві великі машини і встановлюєте їх відповідно replicaдо поточної машини. Реплікація бази даних подбає про розподіл даних з primaryмашини на replicaмашини. Ви переходите до всіх запитів читання (Query ( Q) in CQRS) до реплік - будь-який replicaможе обслуговувати будь-який запит на читання, ви переходите до всіх запитів на запис (Command ( C) in CQRS) до primary. У реплікації може бути незначне відставання, але відповідно до вашого випадку використання бізнесу це нормально.

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

Тепер ви масштабуєтеся до ще 2 міст, і ви бачите, що ваш primaryне може обробляти всі writeзапити. Багато writeзапитів мають затримку. Більше того, відставання між primary& replicaіноді впливає на клієнтів та водіїв, коли - коли поїздка закінчується, клієнт платить водієві успішно, але водій не може бачити оплату, оскільки діяльність клієнта - це writeзапит, який надходить до primary, тоді як діяльність водія - це readзапит що надходить до однієї з копій. Ваша загальна система настільки повільна, що водій не може бачити оплату принаймні півхвилини - це неприємно як для водія, так і для клієнта. Як це вирішити?

Шаблон 4 - Багатопервинна реплікація

Ви дуже добре масштабували primary-replicaконфігурацію, але тепер вам потрібна більша продуктивність запису. Можливо, ви готові піти на компроміс щодо readпродуктивності запиту. Чому б не розподілити запит на запис replicaтакож до?

У multi-primaryконфігурації всі машини можуть працювати як primary& replica. Ви можете думати про те, multi-primaryяк говорять кола машин A->B->C->D->A. Bможе тиражувати дані з A, Cможе тиражувати дані з B, Dможе тиражувати дані з C, Aможе тиражувати дані з D. Ви можете записувати дані в будь-який вузол, під час читання даних ви можете транслювати запит на всі вузли, хто відповість, це поверне. Усі вузли матимуть однакову схему бази даних, однаковий набір таблиць, індекс і т. Д. Отже, ви повинні переконатися, що idміж вузлами в одній таблиці немає зіткнень , інакше під час трансляції кілька вузлів повертатимуть різні дані для однакових id.

Як правило, це краще використовувати UUIDабо GUIDдля ідентифікатора. Ще одним недоліком цієї методики є те, що readзапити можуть бути неефективними, оскільки вони включають трансляцію запиту та отримання правильного результату - в основному підхід розсіяного збору.

Тепер ви масштабуєтеся до ще 5 міст, і ваша система знову болить. Очікується, що ви обробите приблизно 50 запитів в секунду. Ви вкрай потребуєте обробити велику кількість одночасних запитів. Як ви цього досягнете?

Шаблон 5 - Розбиття:

Ви знаєте, що ваша locationбаза даних - це щось, що отримує високий writeі readтрафік. Ймовірно, write:readкоефіцієнт 7:3. Це чинить великий тиск на існуючі бази даних. У locationтаблицях наведено кілька основних даних , таких як longitude, latitude, timestamp, driver id, і trip idт.д. Це не має багато спільного з користувачем поїздок, призначені для користувача дані, дані платіжних і т.д. Що про поділ locationтаблиць в окремій схемі бази даних? А як щодо розміщення цієї бази даних в окремих машинах із належним налаштуванням primary-replicaчи multi-primaryконфігурацією?

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

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

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

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

Оскільки всі бази даних містять однаковий набір таблиць, ви можете спроектувати систему таким чином, щоб там була локальність даних, тобто; усі пов'язані дані потрапляють в одну машину. Кожна машина може мати свої власні репліки, репліки можна використовувати для відновлення несправностей. Викликається кожна з баз даних shard. Фізична машина може мати одну або декілька shards- це залежить від вашого дизайну, як ви хочете. Вам потрібно прийняти рішення sharding keyтаким чином, щоб одинарний sharding keyзавжди посилався на одну машину. Отже, ви можете собі уявити безліч машин, які містять пов’язані дані в одному наборі таблиць, read/writeзапити на той самий рядок або той самий набір ресурсів на одній машині бази даних.

Взагалі шардінг важкий - принаймні інженери різних компаній говорять про це. Але коли ви відправляєте мільйони або мільярди запитів, вам доводиться приймати таке жорстке рішення.

Я буду обговорювати shardingбільш докладно в моєму наступному дописі, тому стримуючи спокусу обговорити більше в цьому дописі.

Тепер, коли у вас є шардінг, ви впевнені, що зможете масштабуватися до багатьох країн. Ваш бізнес настільки зріс, що інвестори підштовхують вас до масштабування бізнесу на різних континентах. Ви знову бачите тут якусь проблему. Знову затримка API. Ваша послуга розміщується в США, а люди з В’єтнаму важко їздять по книгах. Чому? Що ти з цим робиш?

Шаблон 7 - Мудрий розділ центру обробки даних:

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

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

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

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

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

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

Стаття оригінально опублікована на авторському носії: //medium.com/@kousiknath/understanding-database-scaling-patterns-ac24e5223522