awesome-everything EN
↑ Обратно к восхождению

Базы данных

Выбор ключа шарда: стратегии hash, range, list и directory

Суть Хороший ключ шарда обладает четырьмя свойствами — селективностью, равномерным распределением, стабильностью и доступностью во время маршрутизации. Стратегии hash, range, list и directory по-разному компромиссируют режимы отказа.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 12 min

Две команды шардируют свой Postgres по customer_id. Одна использует хеш-шардирование; через шесть месяцев у них нет горячих шардов. Другая использует range-шардирование с тем же ключом; у них постоянный горячий хвост на шарде с самыми большими ID клиентов, потому что все новые регистрации попадают туда. Одна колонка, разные стратегии, противоположный результат.

Четыре свойства хорошего ключа шарда

Ключ шарда должен одновременно удовлетворять всем четырём условиям:

  1. Селективность: 95%+ ваших запросов фильтруют по нему. Запросы без ключа шарда должны обходить все шарды — это дорого и медленно.
  2. Равномерное распределение: каждый шард получает примерно равное количество данных и трафика. Неравномерные ключи порождают горячие шарды.
  3. Стабильность: значение никогда не меняется для данной строки. Изменение ключа шарда потребовало бы перемещения строки на другой шард — проблема, которую нельзя решить во время обновления.
  4. Доступность во время маршрутизации: каждый API-запрос, касающийся этих данных, должен содержать ключ шарда. Если запросы приходят без него, нельзя маршрутизировать без кросс-шард сканирования.

Для мультиарендного B2B SaaS tenant_id почти всегда удовлетворяет всем четырём. Для B2C — user_id. Для геораспределённых систем — region. Схемы данных, в которых нет колонки, отвечающей всем четырём свойствам — красные флаги; разбейте модель данных до тех пор, пока такая колонка не появится.

Четыре стратегии

СтратегияКак работаетПреимуществоРиск
Hashshard = hash(key) mod NРавномерность при равномерных ключахГорячий шард при скошенных ключах; изменение N перемещает большинство строк
RangeКаждый шард владеет диапазоном ключей (например, tenant_id 1–1000)Естественен для time-series; легко добавить шард в хвостГорячий хвост: все новые записи на одном шарде
ListЯвный маппинг: ключ → шардМаксимальный контрольНе масштабируется до миллионов ключей
DirectoryВнешняя lookup-таблица маппит ключ → шард; перемещение клиентов — обновление одной строкиПеремещение отдельных клиентов между шардами; изоляция клиентов Citus использует этоСтоимость поиска на каждый запрос; карта шардов — критическая инфраструктура

Хеш-шардирование — это дефолт для большинства OLTP-систем, потому что при равномерном распределении ключей оно распределяет равномерно. Проблема в том, что реальные клиенты распределены по степенному закону: один клиент в 100–1000 раз превышает медианный. Хеш по-прежнему маршрутизирует этого клиента на один шард — горячий шард.

Range-шардирование естественно для time-series данных (шард по месяцу), но по умолчанию создаёт горячий хвост: все новые записи идут на последний шард, пока старые шарды простаивают. Продакшн-системы time-series обычно сочетают range (по временному бакету) с hash (внутри бакета) для распределения нагрузки записи.

Directory-based шардирование — наиболее гибкое: lookup-таблица маппит tenant_id → connection_string. Перемещение клиента означает обновление одной строки. Это основа примитива изоляции клиентов Citus и маршрутизации на уровне приложения в мультиарендном SaaS. Цена — lookup-таблица становится инфраструктурой первого уровня критичности: она должна быть высокодоступной, малолатентной и агрессивно кешироваться.

Consistent hashing — вариант хеша, используемый в основном в кешах (Memcached, Redis Cluster), где добавление или удаление шарда перемещает только K/N ключей вместо большинства. Некоторые конфигурации шардирования Postgres используют directory-based consistent hashing для онлайн-ребалансировки шардов.

Контракт ключа шарда на практике

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

Почему это работает

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

Викторина

В SaaS есть 5000 клиентов, где топ-5 клиентов генерируют 60% трафика. Какой подход к шардированию лучший?

Викторина

Запрос ищет пользователей по email глобально (tenant_id недоступен). Что происходит в кластере, шардированном по tenant_id?

Расставь шаги по порядку

Упорядочьте шаги оценки ключа шарда перед принятием решения для мультиарендного B2B SaaS:

  1. 1 Аудит паттернов запросов: составить список колонок WHERE в топ-100 запросов по частоте
  2. 2 Проверить, что ключ есть в 95%+ запросов и доступен в каждом API-запросе
  3. 3 Измерить распределение размеров клиентов в продакшн-данных — найти топ-5% по трафику и объёму данных
  4. 4 Убедиться, что ключ стабилен (никогда не обновляется) и не null на каждой шардированной таблице
  5. 5 Спроектировать политику для исключений: клиенты выше X% трафика кластера получают выделенные шарды
  6. 6 Зафиксировать ключ в ADR и задокументировать стоимость решардинга, если понадобится его изменить
Вспомните перед уходом
  1. 01
    Назовите четыре обязательных свойства хорошего ключа шарда и объясните, почему каждое важно.
  2. 02
    В чём главный режим отказа range-шардирования по ключу time-series и как продакшн-системы его смягчают?
  3. 03
    Почему ключ шарда должен быть частью первичного ключа каждой шардированной таблицы?
Итог

Ключ шарда должен одновременно удовлетворять четырём свойствам: селективности (в 95%+ запросов), равномерному распределению (ни один шард не перегружен), стабильности (никогда не обновляется) и доступности во время маршрутизации. Хеш-шардирование распределяет равномерно при равномерных ключах, но создаёт горячие шарды при перекосе клиентов; range-шардирование естественно для time-series, но создаёт горячий хвост; directory-based шардирование наиболее гибко и используется примитивом изоляции клиентов Citus. Проверяйте ключ против реальных продакшн-паттернов доступа и распределения размеров клиентов перед принятием решения — изменение ключа позже обходится в месяцы перемещения каждой строки.

Связанные уроки
встречается в258
Продолжить восхождение ↑Партиционирование против шардирования: одно слово, два разных понятия
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.