Масштабирование баз данных — партиционирование, репликация и шардирование
СУБД очень часто становится «узким местом» в производительности веб‑приложений, влияющим на общее быстродействие и устойчивость к высоким нагрузкам. В современных высоконагруженных системах эффективное управление данными невозможно без использования методов масштабирования и обеспечения отказоустойчивости. Репликация, партиционирование и шардирование — ключевые подходы, которые позволяют распределять данные, повышать производительность и гарантировать доступность.
В этой статье разберём каждый из них подробно, если же хотите просто понять суть этих подходов без погружения в детали, то рекомендуем другую нашу статью — «Просто о сложном: что такое репликация, партиционирование и шардирование?».
Масштабирование «железа» и адекватная настройка
Первое, что стоит сделать, если скорость работы базы данных не удовлетворяет требованиям, это проверить адекватность настройки СУБД относительно имеющихся ресурсов, а также убедиться, что при проектировании БД были учтены используемые запросы. Если, например, СУБД работает с настройками «из коробки», а при обработке запросов не используются индексы, то не нужно масштабировать СУБД — достаточно просто откорректировать конфигурацию работы сервера баз данных и обновить схему используемой базы данных под профиль нагрузки. Иногда также проще увеличить выделение ресурсов под сервер баз данных — количество оперативной памяти и скорость работы дисковой подсистемы оказывают существенное воздействие на скорость работы СУБД. Нередко даже небольшое увеличение RAM и переход на SSD повышают производительность в разы или даже на порядок.
Масштабирование через партиционирование, репликацию и шардирование (SQL и NoSQL)
В момент, когда даже корректно настроенный сервер баз данных на достаточно мощном железе уже недостаточно хорошо справляется с нагрузками, производится масштабирование при помощи партиционирования, репликации и шардирования. Далее рассмотрим эти способы увеличения производительности СУБД.
Описанные ниже схемы масштабирования применимы как для реляционных баз данных, так и для NoSQL‑хранилищ. Разумеется, у всех баз данных и хранилищ есть своя специфика, поэтому мы рассмотрим только основные направления, а в детали реализации вдаваться не будем.
Репликация (replication)
Репликация — это синхронное или асинхронное копирование данных между несколькими серверами. Ведущие серверы часто называют мастерами (master), а ведомые серверы — слейвами (slaves), иногда используются и другие названия — лидер и фолловеры (leader & followers), праймари и реплики (primary & replicas). Один ведущий узел (мастер, лидер, праймари) принимает запросы как на запись, так и на чтение, а ведомые (реплики, слейвы или фолловеры) синхронизируются с ним и обслуживают только запросы на чтение.
В классической схеме репликации обычно один мастер и несколько слейвов, так как в большей части веб‑проектов операций чтения на несколько порядков больше, чем операций записи, поэтому масштабировать систему целесообразно в направлении увеличения производительности запросов на чтение; с этой задачей отлично справляются схемы с несколькими слейвами. Однако в более сложных схемах репликации может быть и несколько мастеров.
Репликация бывает синхронной и асинхронной. При синхронной репликации как минимум один слейв должен быть на 100% актуален, а при асинхронной — допустима некоторая задержка в репликации данных от мастера к слейвам. Таким образом, при асинхронной репликации мы получаем высокую скорость работы, но при выходе из строя мастер‑сервера вероятна потеря некоторого количества данных. Синхронная же репликация предусматривает, что транзакции подтверждаются мастером только после записи на заданное количество слейвов — в итоге получается крайне высокая согласованность данных, но низкая производительность. Подробнее о выборе между быстродействием и согласованностью — см. PACELC‑теорему.
С практической точки зрения, создание нескольких дополнительных slave‑серверов позволяет снять с основного сервера нагрузку по запросам на чтение и повысить общую производительность системы, а также организовать слейвы под конкретные ресурсоёмкие задачи и таким образом, например, упростить составление серьёзных аналитических отчётов — используемый для этих целей slave может быть нагружен на 100%, но на работу других пользователей приложения это не повлияет. Если нужна максимальная надёжность и сохранность данных при адекватной производительности, то обычно достаточно реализовать синхронную репликацию на 1–2 слейва при большем общем их количестве.
Партиционирование (partitioning)
Партиционирование — это разбиение таблиц, содержащих большое количество записей, на логические части по неким выбранным администратором критериям. Партиционирование таблиц делит весь объём операций по обработке данных на несколько независимых и параллельно выполняющихся потоков, что может существенно ускорить работу СУБД. По сути, это разделение таблицы на логические части (партиции) для ускорения запросов и управления большими объёмами данных. Партиционировать таблицы можно горизонтально (на уровне строк, например, через разделение на партиции по диапазонам значений) и вертикально (на уровне столбцов, например, через вынесение редко используемых полей в отдельную таблицу). В результате запросы выполняются быстрее за счёт работы с меньшими объёмами данных, а управление информацией упрощается (в частности, при архивации старых партиций или при разделении данных на «горячие» и «холодные»).
Например, на новостных сайтах имеет смысл партиционировать записи по дате публикации, так как свежие новости на несколько порядков более востребованы и чаще требуется работа именно с ними, а не со всем архивом за годы существования новостного ресурса.
Шардинг (sharding)
Шардинг — это прием, который позволяет распределять данные между разными физическими серверами. Процесс шардинга предполагает разнесение данных между отдельными шардами на основе некоторого ключа шардинга. Связанные одинаковым значением ключа шардинга сущности группируются в набор данных по заданному ключу, а этот набор хранится в пределах одного физического шарда. Это существенно облегчает обработку данных. По сути, это горизонтальное разделение данных между независимыми базами (шардами), которые могут находиться на разных серверах.
Стратегии шардирования могут отличаться в зависимости от задач. Ключевой шардинг (Key-Based) — данные распределяются по шардам посредством хэш‑функции или через остаток от деления (например, user_id % N). Диапазонный шардинг (Range-Based) — шарды хранят данные из определённых диапазонов (например, пользователи A–M, N–Z). Географический шардинг — данные хранятся ближе к пользователям (шард для РФ, шард для ЕС, шард для США).
Например, в системах типа социальных сетей ключом для шардинга может быть ID пользователя: таким образом, все данные пользователя будут храниться и обрабатываться на одном сервере, а не собираться по частям с нескольких серверов.
Использование репликации, шардирования и партиционирования
Репликация, партиционирование и шардирование — взаимодополняющие технологии; их выбор зависит от требований к масштабируемости, отказоустойчивости и производительности.
Репликация на практике используется наиболее часто. Благодаря ей достигается отказоустойчивость и масштабируются запросы на чтение, которых почти во всех прикладных системах сильно больше. Сочетание репликации с шардингом позволяет масштабировать крупные системы, обеспечивая при этом отказоустойчивость.
Партиционирование и шардинг используются относительно реже. Обе эти техники ускоряют выполнение запросов внутри одной партиции / шарда, так как количество обрабатываемых данных внутри отдельной партиции или отдельного шарда меньше, нежели их общее количество. Шардинг также позволяет горизонтально масштабироваться и повышает устойчивость к сбоям — падение одного шарда приводит к деградации сервиса, но не к падению всей системы.
Стоит помнить, что репликация и шардинг (как вместе, так и по отдельности) превращают систему в распределённую, поэтому при разработке надо учитывать ограничения по теореме CAP: нельзя одновременно гарантировать согласованность данных (C — consistency), доступность (A — availability) и устойчивость к разделению сети (P — partition tolerance). В лучшем случае можно получить только два свойства из трёх перечисленных. В финтехе, например, обычный выбор — C+P, а в системах с менее значимой информацией — A+P.
С практической точки зрения, репликация бывает полезна для проектов любого масштаба, где нужна отказоустойчивость и высокая сохранность данных. Наличие реплики позволяет сохранить данные и быстро восстановить работоспособность сервиса даже при полной потере мастера. Масштабирование под нагрузку обычно тоже первоначально производится при помощи репликации БД, реже — через партиционирование. Шардинг же обычно рационально использовать только в достаточно крупных системах с очень большим количеством данных.
Тематические статьи
Теоремы CAP и PACELC объясняют ограничения, возникающие в распределённых системах, и позволяют проектировать решения, обеспечивающие правильный баланс между доступностью, согласованностью и быстродействием.
Простыми словами объясним эти подходы к масштабированию систем хранения данных. На понятном примере и без использования сложной терминологии.
Базы данных служат для хранения и обработки данных. Бывают реляционные (SQL) и нереляционные (NoSQL) системы управления базами данных. Реляционные системы управления базами данных (SQL) хранят данные в таблицах и наиболее часто используются в качестве основного хранилища для веб‑приложений. Они очень стабильны, и их надёжность проверена временем. Нереляционные СУБД (NoSQL) заметно отличаются по структуре хранения данных и работе с ними. Для специфических типов данных и задач они зачастую быстрее и удобнее классических SQL СУБД, но обычно это преимущество достигается за счёт снижения надёжности хранения.
PostgreSQL — это популярная объектно-реляционная система управления базами данных. PostgreSQL базируется на языке SQL, отличается высокой надёжностью и имеет широкие возможности. В PostgreSQL нет ограничений на максимальный размер базы данных, количество записей и индексов в таблицах. В СУБД встроены мощные и надёжные механизмы транзакций, есть возможности для репликации, шардинга и партиционирования. СУБД отличает лёгкая расширяемость и возможность тонкой настройки.
MySQL — это реляционная система управления базами данных с открытым исходным кодом. В настоящее время эта СУБД одна из наиболее популярных в веб‑приложениях — подавляющее большинство CMS использует именно MySQL (часто только её, без альтернатив), а почти все веб‑фреймворки поддерживают MySQL уже на уровне базовой конфигурации (без дополнительных модулей).
MariaDB — ответвление реляционной СУБД MySQL, разрабатываемое сообществом под лицензией GPL. MariaDB совместима с большинством приложений, использующих MySQL, а переход на эту СУБД оправдан тем, что MySQL уже не так активно развивается.
SQL‑инъекции — это один из распространённых способов взлома сайтов и веб‑приложений, работающих с реляционными базами данных. SQL‑инъекции основаны на внедрении в выполняемый приложением запрос к базе данных произвольного SQL‑кода, переданного злоумышленником. Последствиями SQL‑инъекций могут стать кража, модификация или удаление данных, а также полный взлом атакуемой системы — например, получение привилегированного доступа.
MongoDB — это NoSQL‑хранилище данных, крайне удобное для хранения информации, которая не может быть нормально структурирована в рамках реляционных баз данных. MongoDB — это СУБД с открытым исходным кодом по лицензии SSPL, не требующая описания схемы таблиц. Документы в MongoDB хранятся в JSON или BSON, с такой моделью проще кодировать и управлять, а внутренняя группировка релевантных данных обеспечивает дополнительный выигрыш в быстродействии.