Содержание

Масштабировать базу данных стоит по ступеням: сначала оптимизировать запросы и индексы, затем увеличить сервер, затем вынести чтение на реплики и только в крайнем случае разделить данные на шарды. Большинству продуктов хватает первых трёх шагов на годы вперёд, а шардирование резко усложняет разработку и эксплуатацию.

Разберём, как работает репликация, какие у неё подводные камни, что такое партиционирование и шардирование и когда к ним переходить.

Когда база данных становится узким местом?

База становится узким местом, когда растут время ответа запросов, загрузка процессора и диска сервера базы, а очередь соединений не успевает разбираться. Но прежде чем масштабировать, стоит проверить, не решается ли проблема дешевле.

Порядок действий:

  1. Оптимизация запросов. Медленные запросы без индексов, проблемы N+1 и лишние выборки — частая причина нагрузки; подробнее в статье индексы в PostgreSQL.
  2. Кеширование. Часто читаемые данные — в кеш, статья кеширование в веб-приложении.
  3. Пул соединений. Тысячи соединений от приложения перегружают базу сильнее, чем запросы.
  4. Вертикальное масштабирование. Больше процессоров, памяти и быстрые диски — самый простой шаг.
  5. Реплики для чтения. Когда большая часть нагрузки — чтение.
  6. Шардирование. Когда не справляется запись или данные не помещаются на один сервер.

Как работает репликация?

Репликация — это копирование изменений с основного сервера базы на один или несколько дополнительных. Основной сервер принимает запись, реплики получают поток изменений и применяют его у себя. Читать можно с реплик, разгружая основной сервер.

Задача Как помогает репликация
Нагрузка на чтение Отчёты, каталоги и поиск читают с реплик
Отказоустойчивость При падении основного сервера реплика становится основной
Аналитика Тяжёлые запросы аналитиков не мешают пользователям
Обслуживание Обновления проводят поочерёдно, без остановки

Зеркало в узорной раме отражает голубое небо Фото: Unsplash

Какие проблемы создаёт задержка репликации?

Реплика отстаёт от основного сервера на миллисекунды, а под нагрузкой — на секунды. Если пользователь сохранил профиль, а следующая страница читается с реплики, он может увидеть старые данные и решить, что сохранение не сработало.

Как с этим работать:

  • после записи читайте данные того же пользователя с основного сервера в течение короткого времени;
  • критичные проверки — остатки, балансы, права доступа — делайте только на основном сервере;
  • следите за задержкой репликации и выводите отстающую реплику из работы;
  • не используйте реплики внутри транзакций, которые потом пишут данные.
// Laravel: после записи в рамках запроса чтение идёт с основного сервера
'mysql' => [
    'read'   => ['host' => ['replica-1', 'replica-2']],
    'write'  => ['host' => ['primary']],
    'sticky' => true,
],

Что такое партиционирование и шардирование?

Партиционирование делит большую таблицу на части внутри одного сервера — например, по месяцам. Шардирование распределяет данные по разным серверам — например, по идентификатору клиента. Партиционирование почти не усложняет приложение, шардирование — сильно.

Что усложняет шардирование:

  • запросы и отчёты по всем данным нужно собирать с нескольких серверов;
  • транзакции между шардами практически недоступны;
  • перебалансировка данных при добавлении шарда — отдельный сложный проект;
  • миграции схемы, бэкапы и мониторинг множатся по числу шардов.

Хорошее естественное разбиение — по клиенту в B2B SaaS: данные клиентов почти не пересекаются. Подробнее — в статье мультитенантность в SaaS.

Когда переходить к шардированию?

К шардированию переходят, когда один сервер не выдерживает нагрузку на запись даже после оптимизации и максимального вертикального масштабирования или когда объём данных не помещается на самый большой доступный сервер. Для большинства продуктов этот момент не наступает никогда.

Перед решением:

  • соберите статистику: что именно нагружает базу — чтение или запись;
  • проверьте, не помогут ли партиционирование и архивация старых данных;
  • оцените, нельзя ли вынести аналитику в отдельное хранилище — статья ClickHouse для аналитики;
  • выберите ключ шардирования, по которому почти все запросы попадают в один шард.

Коротко

  • Масштабируйте по ступеням: запросы, кеш, сервер побольше, реплики, шарды.
  • Реплики разгружают чтение и дают отказоустойчивость, но отстают от основного сервера.
  • Критичные данные читайте с основного сервера, особенно сразу после записи.
  • Партиционирование делит таблицу внутри сервера, шардирование — данные между серверами.
  • Шардирование — крайняя мера, к которой большинству продуктов переходить не нужно.

Частые вопросы

  • Реплика заменяет резервную копию?

    Нет. Реплика мгновенно повторяет все изменения, включая ошибочное удаление данных. Резервные копии нужны отдельно — они позволяют вернуться в момент до ошибки.

  • Сколько реплик нужно?

    Для отказоустойчивости достаточно одной реплики в другой зоне доступности. Дополнительные реплики добавляют, когда нагрузку на чтение не выдерживает одна.

  • Шардирование можно включить без изменения кода?

    Есть расширения и прокси, которые прячут шардирование от приложения, но запросы между шардами и транзакции всё равно ведут себя иначе. Почти всегда код и схему данных приходится адаптировать.