Шардирование¶
Масштабирование баз данных – это увеличение вычислительных ресурсов для хранения и обработки нарастающего количества данных. Если отдельный сервер не справляется с нагрузкой, используются средства масштабирования:
вертикальное масштабирование – увеличиваются вычислительные мощности узлов, при этом следует учитывать аппаратные ограничения;
горизонтальное масштабирование – данные делятся на части, которые хранятся на отдельных узлах независимо друг от друга.
Шардирование с помощью встроенного модуля vshard – это принцип горизонтального масштабирования, при котором набор данных
распределяется (шардируется) по множеству узлов, на каждом из которых находится экземпляр сервера Tarantool DB.
Каждый экземпляр обрабатывает лишь подмножество от общего набора данных, так что увеличение нагрузки можно
компенсировать добавлением новых серверов.
Подробная информация о механизме шардирования приведена в документации платформы Tarantool.
Архитектура¶
Кластер делится на несколько шардов. Каждый шард представляет собой набор реплик, одна из которых является мастер-узлом и обрабатывает все запросы на чтение и запись. Для выполнения операций над шардированными данными в кластере используется модуль CRUD.
Кортежи распределяются не по физическим узлам, а по множеству абстрактных виртуальных сегментов (buckets).
Каждый сегмент содержит уникальный набор кортежей.
Сегменты распределяются между всеми шардами кластера, причем каждый шард хранит уникальное подмножество сегментов.
Мастер-узел в наборе реплик хранит данные сегментов, распределенные на этот шард, в системном спейсе _bucket.
Полная информация о соответствии всех шардов и их сегментов хранится в системном спейсе Tarantool DB.
Каждому сегменту присваивается уникальный номер от 1 до N (общее количество сегментов), который используется как
идентификатор сегмента (bucket_id).
Чтобы шардировать спейс, в его схему нужно добавить поле bucket_id и индекс по этому полю.
Хеширование bucket_id в большое количестве сегментов позволяет незаметно для пользователя изменять количество
серверов в кластере.
При добавлении или удалении серверов механизм балансировки распределяет сегменты между шардами.
Таким образом, шардированный кластер состоит из следующих элементов:
один или несколько шардов (наборов реплик). Набор реплик состоит из узлов хранилища, каждый из узлов имеет роль мастер или реплика. Узел хранилища содержит подмножество набора данных;
один или несколько экземпляров роутеров. Роутер – это узел, который обеспечивает маршрутизацию запросов чтения и записи от клиентского приложения к шардам. Все запросы из приложения приходят в шардированный кластер через роутер;
балансировщик – фоновый процесс балансировки, обеспечивающий распределение сегментов по шардам. Во время балансировки происходит миграция сегментов по наборам реплик.
Создание шардированного спейса в миграции¶
При создании шардированного спейса в миграции необходимо выполнить следующие условия:
добавить поле
bucket_idдля записи номера сегмента;задать вторичный индекс по полю
bucket_id;указать ключ шардирования – поле, по которому нужно шардировать спейс. В миграции это можно задать в функции
helpers.register_sharding_key(), которая обновляет запись о ключе в системном спейсе_ddl_sharding_key.
Когда клиентское приложение обращается к кластеру, модуль CRUD на основе ключа шардирования определяет, куда писать и
откуда читать кортежи в шардированном спейсе.
CRUD вычисляет номер сегмента bucket_id по полям, указанным в ключе шардирования – по ним считается целочисленный хэш,
составляющий номер сегмента.
Если в качестве ключа шардирования выбран первичный индекс, то этот индекс используется по умолчанию.
Информация о том, на каком шарде находятся данные сегмента, вычисляется по таблице маршрутизации.
В миграции в качестве ключа шардирования обычно указывается поле первичного индекса (в примере это id):
local helpers = require('tt-migrations.helpers') -- Подключить вспомогательный модуль
local function apply() -- Функция, выполняющая миграцию
-- Создать спейс
local space_bands = box.schema.space.create('bands', {
if_not_exists = true,
format = {
{ name = 'id', type = 'integer' },
{ name = 'bucket_id', type = 'unsigned' }, -- Задать служебное поле с ключом шардирования
{ name = 'band_name', type = 'string' },
{ name = 'year', type = 'integer' },
},
})
space_bands:create_index('primary_key', { parts = {'id'}, if_not_exists = true}) -- Создать первичный индекс
space_bands:create_index('bucket_id', { parts = {'bucket_id'}, unique = false, if_not_exists = true}) -- Создать вторичный индекс по полю bucket_id
helpers.register_sharding_key(space_bands.name, {'id'}) -- Указать, по какому полю шардировать спейс
return true
end
return {
apply = {
scenario = apply,
}
}
Примечание
В шардированном спейсе уникальность по вторичным индексам гарантируется только внутри одного шарда, а не на уровне всего кластера.