Как стать автором
Обновить
48.05

Как заставить вашу базу данных летать, а не ползать. Часть 2 – когда репликации недостаточно и пора использовать шардинг

Уровень сложностиСредний
Время на прочтение8 мин
Количество просмотров4K

Всем привет! На связи снова Илья Криволапов — системный аналитик в SENSE, где мы трудимся на проекте одного из цветных банков РФ. Работаю в профессии уже пятый год и, несмотря на мою фамилию, с продом у нас в целом тёплые отношения. 

Помимо боевых задач, я преподаю курс «Хранение и обработка больших объемов данных» и за это время накопил немало практических кейсов и наблюдений. Всё это добро я решил не держать при себе и собрал все самое полезное в виде ультимативного гайда по оптимизации и грамотному проектированию баз данных с расчетом на масштабирование, который публикую на Хабре.

Цикл состоит из 3 частей. В первой мы обсудили два базовых подхода к масштабированию БД: вертикальный и горизонтальный. Поговорили о плюсах, минусах и о том, как делать точно не стоит. 

Во второй части – то есть сейчас – мы нырнём глубже в мир горизонтального масштабирования и разберем три первых способа шардирования: по диапазону, по хэшу и по географическим зонам. Я расскажу, как каждый из них работает, где пригодится и в каких случаях может дать сбой.

Материал по-прежнему будет полезен всем, кто заботится о «здоровье» базы данных: DBA, архитекторам, DevOps-инженерам, аналитикам и разработчикам.

Ах да, в комментариях к предыдущей статье коллеги советовали добавить во введение информацию о том, что статья написана простым языком, с приведением большого количества бытовых сравнений. Сделано это намеренно, для 100% понимания и раскрытия сути паттернов :)

Ну что же, готовы продолжать? Тогда поехали!

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

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

Шардинг на практике – это метод горизонтального масштабирования, при котором данные разделяются на части (шарды) и распределяются между разными серверами. Каждый шард содержит только свою порцию данных.

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

Основные типы шардинга:

1. Хэш-шардирование: когда данные делятся «по справедливости»

Представьте, что у вас есть огромный склад с товарами (это ваша база данных). Если всё свалить в одну кучу, искать нужное будет долго и неудобно. Решение? Разделить склад на несколько зон (шардов), чтобы быстрее находить данные. И каждую из зон перенести в географически удобные локации (чем-то напоминает фордовскую децентрализацию), ведь речь о методе шардирования, а не партиционирования. 

Но как решить, что в какую зону класть?

Вот тут на помощь приходит хэш-шардирование — метод, который распределяет данные по шардам с помощью хэша, алгоритма, который преобразует входные данные произвольной длины (называемые "ключом" или "сообщением") в выходные данные фиксированной длины (называемые "хэшем" или "хэш-кодом").

Ключ и хэш-функция: как распределить заказы

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

  • ID клиента (если заказы распределяются по пользователям);

  • Номер заказа (если важно равномерное распределение).

Выбор ключа критичен! Если взять дату заказа, все заказы на «Черную пятницу» попадут в один шард, и он «захлебнется».

Хэш-функция — это алгоритм, который превращает ключ в число (хэш). Хорошая хэш-функция:
Всегда выдаёт одно и то же число для одного ключа (иначе заказы Клиента №5 будут разбросаны по разным шардам);
Распределяет ключи равномерно (чтобы не получилось, что 90% заказов попадают в один шард);
Работает быстро (иначе система будет тормозить на каждом запросе).

Как данные попадают в нужный шард?

Допустим, у нас 4 шарда (Шард 0, Шард 1, Шард 2, Шард 3).

  1. Берём ключ (например, user_id = 123);

  2. Пропускаем его через хэш-функцию → получаем число (например, 347);

  3. Делим это число на количество шардов и берем остаток:

347 : 4 = 3  →  значит, данные попадут в Шард 3.

Теперь при запросе заказов пользователя 123 система сразу знает, где их искать!

Кто всем этим управляет?

В системе есть два главных героя:

Шарды — это отдельные «склады» (серверы, базы данных или разделы), где хранятся данные.
Координатор (Router) — это «диспетчер», который решает, куда отправить запрос. Когда приходит новый заказ, он:

  • считает хэш от ключа;

  • определяет шард;

  • отправляет данные туда.

Координатор может быть отдельным сервисом или частью приложения.

Плюсы и минусы: когда хэш-шардирование — отличный выбор?

 Подойдет, если важны:

✅ Масштабируемость — можно добавлять новые шарды, когда данных становится больше;

✅ Равномерная нагрузка — если хэш-функция хорошая, данные распределяются без «перекосов»;

✅ Параллельная работа — запросы к разным шардам выполняются одновременно.

Может принести с собой:

❗️ Проблемы с изменением числа шардов — если добавить новый шард, придётся пересчитывать хэши и перемещать данные (это сложно!);

❗️ «Горячие точки» — если ключи плохие (например, 80% заказов от топовых клиентов), один шард будет перегружен;

❗️ Сложные запросы — если нужно собрать данные из нескольких шардов, придётся писать дополнительную логику.

Где используют?

  • Базы данных (SQL и NoSQL) — чтобы распределять данные между серверами;

  • Кэши (например, Memcached) — для хранения ключей на разных узлах;

  • Очереди сообщений (например, Kafka) — чтобы партиции не перегружались.

Вывод: когда выбирать хэш-шардирование?

✅ Подходит, если:

  • Нужно равномерное распределение данных;

  • Запросы чаще всего идут по одному ключу (например, «показать заказы пользователя X»);

  • Вы готовы к сложностям при масштабировании.

❗️ Не подходит, если:

  • Часто требуются аналитические запросы по всем данным (например, «сколько заказов за месяц»);

  • Ключи плохо распределены (например, 70% действий делают 10% пользователей).

Хэш-шардирование — как разделение пиццы на равные куски: если сделать правильно, всем достанется поровну. Но если кто-то захочет добавки, придётся перекраивать всю пиццу заново. Такой вот аттракцион!

2. Диапазонное шардирование: когда данные живут «по соседству»

Представьте библиотеку, где книги расставлены не по алфавиту, а по годам издания:

  • 1900–1950 → первый стеллаж;

  • 1951–2000 → второй стеллаж;

  • 2001–2024 → третий стеллаж.

Это и есть диапазонное шардирование – данные распределяются не «в случайном порядке» (как в хэш-шардировании), а логическими блоками. Разберём, как это работает и когда полезно.

Ключ и диапазоны: как делим данные?

Главное условие: ключ должен быть упорядочиваемым (можно сравнить: больше/меньше). Примеры:

  • Дата (заказы по месяцам);

  • ID пользователя (если они выдаются последовательно);

  • Буквенный код (A–F, G–M и т.д.).

Диапазоны задаются вручную или автоматически. Например:

  • Шард 1: заказы с ID 1–1000

  • Шард 2: заказы с ID 1001–2000  

  • Шард 3: заказы с ID 2001–3000 

Если новый заказ имеет ID 1500 → он попадёт в Шард 2.

Как система находит нужный шард?

Здесь нет хэш-функций — только таблица маршрутизации, которая хранит правила:

  • Диапазон 1–1000 → Шард 1  

  • Диапазон 1001–2000 → Шард 2  

  • ...

Координатор (роутер) проверяет ключ и отправляет запрос в нужный шард. Всё как в почтовом отделении, где письма сортируют по индексам!

Плюсы и минусы: когда выбирать?

Подойдет, если важны:

✅ Быстрые запросы по диапазону — например, «показать заказы за январь 2024» (данные лежат в одном шарде);

✅ Локальность данных — связанные записи (например, заказы одного клиента) хранятся рядом;

✅ Простота — легче реализовать, чем хэш-шардирование с consistent hashing.

Может принести с собой:

❗️ «Горячие точки» — если 90% заказов приходятся на январь, один шард будет перегружен;

❗️ Сложное масштабирование — добавление нового шарда требует перераспределения данных;

❗️ Зависимость от ключа — плохой выбор ключа (например, «дата рождения») может испортить распределение.

Как бороться с неравномерной нагрузкой?

  • Предварительное разделение — если знаете, что данные будут кластеризованы (например, праздничные заказы), заранее разбейте «горячий» диапазон на несколько шардов;

  • Динамическое деление — автоматически дробить перегруженные шарды (как в MongoDB);

  • Составные ключи — например, «дата + регион», чтобы равномернее распределить нагрузку.

Где используют?

  • Временные ряды (логи по дням/месяцам);

  • Биллинг-системы (транзакции по ID пользователя);

  • Аналитические базы данных (запросы по диапазону дат).

Вывод: когда подходит диапазонное шардирование?

✅ Выбирайте, если:

  • Часто выполняются  запросы в стиле «показать данные от X до Y»;

  • Ключ имеет естественную упорядоченность (даты, последовательные ID);

  • Нужна простота реализации.

❗️ Избегайте, если:

  • Данные распределены неравномерно (например, 80% активности в одном месяце);

  • Часто меняется количество шардов.

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

P.S. Для «горячих» данных лучше комбинировать с другими методами (например, хэш-шардированием внутри диапазона).

3. Геошардирование: когда данные живут «по соседству». Буквально.

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

Ключ и зоны: как делим мир, Пинки?

Ключ — это координаты (широта/долгота) или географический объект: город, район или даже произвольная фигура на карте.

Методы разделения:

  • Прямоугольные зоны — как разрезать карту на квадраты (просто, но неточно);

  • Геохеши — кодируем координаты в строку (например, u4pruy — это центр Осло). Чем длиннее хэш, тем точнее зона;

  • Границы городов/стран — данные группируются по административному делению;

  • Иерархия — сначала страны, потом регионы, затем города (как почтовые индексы).

Пример:

  • Шард 1: Нью-Йорк (40.7°N, 74.0°W)  

  • Шард 2: Париж (48.8°N, 2.3°E)  

  • Шард 3: Токио (35.6°N, 139.6°E)  

Запрос с координатами Эйфелевой башни попадает в Шард 2.

Как система находит нужный шард?

Здесь работает пространственный индекс — специальная структура данных, которая быстро определяет, куда отправить запрос. Популярные варианты:

  • R-дерево — группирует объекты в «виртуальные прямоугольники»;

  • Квадродерево — рекурсивно делит карту на четверти;

  • Геохеш-индекс — ищет зону по строковому коду.

Координатор использует этот индекс, как навигатор: получил координаты → проверил индекс → направил запрос в нужный шард.

Плюсы и минусы: когда выбирать?

Подойдет, если важны:
✅ Молниеносные геозапросы
— например, «кафе в радиусе 1 км» (данные уже лежат в одном шарде);
✅ Локальность данных — рестораны одного района хранятся вместе;
✅ Георепликация — можно разместить шарды ближе к пользователям (европейские данные — в Париже, азиатские — в Сингапуре);

Может принести с собой:
❗️ «Перекос данных» — в Москве миллион мест, а в Антарктиде — три (один шард перегружен, другие пустуют);
❗️ Граничные запросы — если пользователь стоит на границе двух шардов, система должна опрашивать оба;
❗️Динамические границы — если город расширяется, придется перераспределять данные.

Как бороться с проблемами?

  • Адаптивные зоны — автоматически дробить «густонаселенные» шарды (например, делить Нью-Йорк на Манхэттен, Бруклин и т.д.);

  • Геохеши + иерархия — сначала страна (первые 4 символа геохеша), потом город (еще 2 символа);

  • Репликация горячих точек — скопировать данные популярных мест в соседние шарды.

Где используют?

  • Картографические сервисы (Google Maps, Яндекс.Карты);

  • Такси и доставка (Uber, Bolt);

  • Соцсети (Instagram с геометками, Foursquare);

  • Игры с дополненной реальностью (Pokémon Go).

Вывод: когда подходит геошардирование?

✅ Выбирайте, если:

  • Данные привязаны к местоположению (чекины, заказы, датчики IoT);

  • Критичны быстрые геозапросы («показать всё рядом»);

  • Пользователи распределены по миру (и нужно уменьшить задержки).

❗️ Избегайте, если:

  • Данные распределены неравномерно (например, 90% активности в 3 городах);

  • Часто меняются границы зон (например, стартап, который ежедневно добавляет новые регионы).

Геошардирование — как раскладка товаров в супермаркете: молоко рядом с молоком, вино рядом с вином. Но если на районе все любят мороженое — очередь будет в одном холодильнике.

P.S. Для глобальных сервисов часто комбинируют геошардирование с репликацией — так данные становятся ближе к пользователям.


Итак, во второй части мы познакомились с тремя базовыми способами шардирования: по диапазону, по хэшу и по географическим зонам. Разобрались, как они работают, где помогают, а где могут устроить весёлую жизнь разработчикам, поддержке, аналитикам, CTO, гендиру... В общем, штука серьезная и подход должен быть соответствующий :)

Надо понимать, как данные живут, растут, какую нагрузку испытывают сервера и !с какой столкнутся в будущем! (да-да, несите кофейную гущу, будем гадать). 

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

А пока расскажите, применяете ли Вы принципы шардинга в своих системах? Что пробовали, что подошло, а что не очень? Буду рад обсудить ваши кейсы в комментах!

Теги:
Хабы:
+1
Комментарии0

Публикации

Информация

Сайт
sense-group.ru
Дата регистрации
Дата основания
Численность
201–500 человек