Пошук уроків, статей та іншого контенту
Як база даних переживає навантаження, що перевищує можливості одного сервера.
Реплікація бази даних тримає кілька копій тих самих даних на різних серверах — типова схема primary-replica (раніше — master-slave): усі записи (INSERT/UPDATE/DELETE) йдуть на єдиний primary-сервер, а зміни автоматично поширюються на один чи кілька replica-серверів, які приймають лише читання.
Записи (write) ──────→ Primary
│
(реплікація)
↓
┌───────────┴───────────┐
↓ ↓
Replica 1 Replica 2
↑ ↑
Читання (read) Читання (read)У більшості реальних застосунків операцій читання значно більше, ніж запису (перегляд статей, профілів, каталогу товарів — читання; коментар, замовлення, реєстрація — запис). Спрямування всіх читань на replica-сервери знімає навантаження з primary, лишаючи йому лише запис, — і дозволяє додавати більше replica-серверів для пропускної здатності читання незалежно від пропускної здатності запису.
Реплікація не миттєва — між записом на primary і появою цього запису на replica минає якийсь час (мілісекунди, зазвичай, але не гарантовано нуль). Якщо застосунок одразу після запису читає ті самі дані з replica, він може отримати ще не оновлену, застарілу версію — класична причина заплутаних багів на кшталт «я щойно зберіг форму, а на сторінці підтвердження бачу старі дані».
Типове рішення — читати щойно записані дані з primary (а не replica) одразу після операції запису, і лише пізніші, некритичні до свіжості читання спрямовувати на replica.
Коли реплікація не вирішує проблему (сам обсяг даних чи навантаження запису перевищує можливості одного primary-сервера), застосовують шардинг — поділ даних на частини (шарди) за певним ключем (наприклад, за user_id), кожна з яких живе на окремому сервері. На відміну від реплікації (кожен сервер має всі дані), шардинг розподіляє різні дані по різних серверах — жоден сервер не тримає всього набору даних одноосібно.
Шард 1: користувачі з id 1–1000000
Шард 2: користувачі з id 1000001–2000000
Шард 3: користувачі з id 2000001–3000000Шардинг значно складніший за реплікацію: запити, що охоплюють кілька шардів одночасно (наприклад, агрегація по всіх користувачах), стають значно дорожчими — потрібно опитати всі шарди й об'єднати результат на рівні застосунку, а не одним простим SQL-запитом до однієї бази даних. Шардинг вартий свого ускладнення лише тоді, коли реплікації дійсно недостатньо.
Читати щойно записані дані з replica без урахування можливої затримки реплікації — призводить до показу застарілих даних одразу після власної ж дії користувача.
Впроваджувати шардинг передчасно, коли простої реплікації read-навантаження було б цілком достатньо, — додає значну складність запитів заради проблеми, якої ще немає.
Обирати ключ шардингу без урахування реальних патернів запитів — поганий вибір ключа може призвести до нерівномірного навантаження («гарячий шард»), що зводить нанівець вигоду від розділення даних.
Реплікація тримає кілька копій усіх даних (primary для запису, replica для читання), розподіляючи read-навантаження — ціною затримки реплікації, яку варто враховувати при читанні щойно записаних даних. Шардинг розділяє самі дані на частини по різних серверах, коли обсяг чи навантаження запису перевищують можливості одного сервера, — значно складніший за реплікацію через ціну запитів, що охоплюють кілька шардів, і вартий застосування лише тоді, коли реплікації справді недостатньо.