Шардирование

В данном разделе рассматриваются способы шардирования динамических таблиц. Приводится описание алгоритма автоматического шардирования.

Динамические таблицы делятся на таблеты (шарды), являющиеся единицей параллелизма.

Сортированные таблицы

Каждый таблет сортированной таблицы отвечает за некоторый диапазон ключей. Граничные ключи таблетов (также называемые pivot-ключами) доступны в атрибуте pivot_keys таблицы. Таблет с индексом k отвечает за ключи, лежащие между k-м граничным ключом (включительно) и k+1-м (не включительно).

Каждый граничный ключ состоит из некоторого префикса ключевых колонок таблицы. Например, для таблицы с тремя ключевыми колонками типов int64, string, double допустимы граничные ключи [], [10], [50; foo], [100; bar; 1.234]. Граничные ключи таблетов должны строго возрастать. Первый граничный ключ обязательно должен быть пустым.

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

Упорядоченные таблицы

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

Реплицированные таблицы

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

  • Каждый таблет сортированной реплицированной таблицы отвечает за диапазон ключей и хранит лог репликации ключей из этого диапазона.
  • Каждый таблет упорядоченной реплицированной таблицы является независимой очередью. Для соответствия таблетов реплицированной таблицы и реплик необходимо использовать атрибут preserve_tablet_index.

Шардирование сортированной реплицированной таблицы не обязано совпадать с шардированием реплик. Разные реплики одной таблицы также могут быть шардированы по-разному.

Непустую реплицированную таблицу решардировать невозможно. При необходимости это сделать нужно пересоздать таблицу с нужными граничными ключами.

Ручное шардирование

Для решардирования таблицы используется команда reshard-table. Перед выполнением команды таблица должна быть отмонтирована.

yt unmount-table //path --sync

# Reshard with tablet count
yt reshard-table //path --tablet-count 10 --sync
# --enable-slicing is used to pick pivots more precisely in case of small tables
yt reshard-table //path --tablet-count 100 --enable-slicing --sync
# Reshard with pivot keys
yt reshard-table //path '[]' '[10;foo]' '[20]' --sync

yt mount-table //path --sync
yt.unmount_table("//path", sync=True)

# Reshard with tablet count
yt.reshard_table("//path", tablet_count=10, sync=True)

# enable_slicing is used to pick pivots more precisely in case of small tables
yt.reshard_table("//path", tablet_count=10, enable_slicing=True, sync=True)

# Reshard with pivot keys
yt.reshard_table("//path", [[], [10, "foo"], [20]], sync=True)

yt.mount_table("//path", sync=True)

Про параметр sync

Команды unmount-table, reshard-table и mount-table асинхронные, поэтому при их использовании рекомендуется дожидаться завершения выполнения. Для этого используется флаг --sync или параметр sync=True. Unmount-table на практике может выполняться долго, поэтому ожидание для неё необходимо. Reshard-table и mount-table типично завершаются мгновенно, поэтому при ручных запусках ожидание можно опускать, однако в скриптах рекомендуется использовать sync.

При указании параметра tablet_count система попробует автоматически выбрать подходящие граничные ключи. Если таблица достаточно маленькая (меньше 200 МБ на таблет), итоговых таблетов может оказаться меньше, чем запрошено. В этом случае для уточнения поиска граничных ключей рекомендуется использовать опцию enable_slicing.

Узнать число таблетов можно через атрибут @tablet_count.

Шардирование по хешу

Для равномерного распределения нагрузки можно воспользоваться стандартным приёмом: добавить первой вспомогательную ключевую колонку, в которую записывать хеш от той части ключа, по которой выполнять шардирование (например, хеш от первой колонки). В результате получится таблица, ключи которой равномерно распределены в диапазоне [0, 264 – 1].

Для разбиения такой таблицы на k таблетов достаточно разбить диапазон [0, 264-1] на k частей. Для этого можно использовать команду reshard-table с флагом --uniform: при указании tablet_count система выставит граничные ключи [], [264 / k], [264 * 2 / k] и т. д.

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

Вычисляемые колонки

Система YTsaurus поддерживает возможность автоматического вычисления значения ключевой колонки по формуле. Данную формулу необходимо указать в схеме этой колонки в поле expression. Ключевая колонка может зависеть только от невычисляемых ключевых колонок. При записи строки или поиска строки по ключу вычисляемые колонки необходимо пропускать.

Для равномерного распределения будет лучше указать "expression" = "farm_hash(key)", где key — префикс исходного ключа (farm_hash — это встроенная функция, вычисляющая FarmHash от аргументов).

При использовании автоматически вычисляемых колонок стоит учитывать, что для оптимизации работы операция select_rows выводит из предиката диапазон затрагиваемых ключей. Если в предикате некоторые значения вычисляемых колонок не заданы явно, то YTsaurus попробует дополнить условие значением вычисляемых колонок. В текущей реализации результат будет успешным, только в том случае если те колонки, от которых зависит вычисляемая, в предикате определяются равенством или с помощью оператора IN. Вычисление явно заданных значений вычисляемых колонок в выводе диапазонов не происходит.

Пример использования вычисляемых колонок

Пусть имеется таблица с колонками hash, key, value, причём hash и key ключевые, а для hash в схеме указана формула expression = "farm_hash(key)". Тогда для операций вставки, удаления и чтения по ключу нужно указывать только key и value. Чтобы операция select_rows работала эффективно, в предикате нужно точно определить key, тогда система YTsaurus сможет вычислить какие значения hash нужно рассматривать. Например, в запросе можно указать WHERE key = key_value или WHERE key IN (key_value1, key_value2).

Если же указать WHERE key > key_lower_bound and key < key_upper_bound, то, диапазон для hash вывести нельзя. В некоторых случаях возможен перебор значений вычисляемых колонок. Перебор происходит в следующих случаях:

  1. Выражение вычисляемой колонки имеет вид expression = "f(key / divisor)" , при этом key и divisor должны быть целочисленными. В данном случае происходит перебор всех таких значений key, которые порождают различные значения expression. Такое поведение обобщается на случай с несколькими вычисляемыми колонками и несколькими вхождениями keyc различными делителями.
  2. Выражение имеет вид expression = "f(key) % mod". В данном случае происходит перебор значений expression в пределах значения mod, а также в перебор включается значение null.

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