Tarantool CE/EE Documentation portal logo
Помощь
Обновлена 15 сентября 2026 г. в 08:55

Создание шардированного кластера

Пример на GitHub: sharded_cluster_crud

В этом руководстве описывается, как запустить шардированный кластер на локальной машине и управлять им с помощью утилиты tt. В этом кластере используются следующие внешние модули:

  • vshard обеспечивает шардирование в кластере.

  • crud обеспечивает управление данными в шардированном кластере. Кластер, создаваемый в этом руководстве, включает 5 экземпляров: один роутер и 4 хранилища, которые составляют два набора реплик.

Cluster topology

Предварительные требования

Перед началом работы:

Создание приложения кластера

Команда tt create используется для создания приложения на основе предопределённого или пользовательского шаблона. Например, с помощью встроенного шаблона vshard_cluster можно создать готовое к запуску приложение шардированного кластера.

В этом руководстве структура приложения подготавливается вручную:

  1. Создайте окружение tt в текущем каталоге, выполнив команду tt init.
  2. В пустом каталоге instances.enabled созданного окружения tt создайте каталог sharded_cluster_crud.
  3. В каталоге instances.enabled/sharded_cluster_crud создайте следующие файлы:
    • instances.yml –- задаёт экземпляры для запуска в текущем окружении.
    • config.yaml –- задаёт конфигурацию кластера.
    • storage.lua –- содержит код для хранилищ.
    • router.lua –- содержит код для роутера.
    • sharded_cluster_crud-scm-1.rockspec –- задаёт внешние зависимости, необходимые приложению.

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

Разработка приложения

Настройка запускаемых экземпляров

Откройте файл instances.yml и добавьте следующее содержимое:

storage-a-001:storage-a-002:storage-b-001:storage-b-002:router-a-001:

Этот файл задаёт экземпляры для запуска в текущем окружении.

Настройка кластера

В этом разделе описывается настройка кластера в файле config.yaml.

Шаг 1. Настройка учётных данных

Добавьте раздел конфигурации credentials:

credentials:  users:    replicator:      password: 'topsecret'      roles: [ replication ]    storage:      password: 'secret'      roles: [ sharding ]

В этом разделе создаются два пользователя с указанными паролями:

  • Пользователь replicator с ролью replication.
  • Пользователь storage с ролью sharding.

Эти пользователи предназначены для обеспечения репликации и шардирования в кластере.

Шаг 2. Указание URI для объявления

Добавьте раздел iproto.advertise:

iproto:  advertise:    peer:      login: replicator    sharding:      login: storage

В этом разделе настраиваются следующие параметры:

  • iproto.advertise.peer –- задаёт способ объявления текущего экземпляра другим членам кластера. В частности, этот параметр сообщает другим членам набора реплик, что для подключения к текущему экземпляру следует использовать пользователя replicator.
  • iproto.advertise.sharding –- задаёт способ объявления текущего экземпляра роутеру и балансировщику.

Топология кластера, определяемая в следующем разделе, также задаёт параметр iproto.advertise.client для каждого экземпляра. Этот параметр принимает URI, используемый для объявления экземпляра клиентам. Например, Tarantool Cluster Manager использует эти URI для подключения к экземплярам кластера.

Шаг 3. Настройка количества бакетов

Задайте общее количество бакетов в шардированном кластере с помощью параметра sharding.bucket_count:

sharding:  bucket_count: 1000

Шаг 4. Определение топологии кластера

Определите топологию кластера в разделе groups. Кластер включает две группы:

  • storages включает два набора реплик. Каждый набор реплик содержит два экземпляра.

  • routers включает один экземпляр роутера. Ниже представлена схема топологии кластера:

groups:  storages:    replicasets:      storage-a:        # ...      storage-b:        # ...  routers:    replicasets:      router-a:        # ...

Чтобы настроить хранилища, добавьте следующий код в раздел groups:

storages:  roles: [ roles.crud-storage ]  app:    module: storage  sharding:    roles: [ storage ]  replication:    failover: manual  replicasets:    storage-a:      leader: storage-a-001      instances:        storage-a-001:          iproto:            listen:            - uri: '127.0.0.1:3302'            advertise:              client: '127.0.0.1:3302'        storage-a-002:          iproto:            listen:            - uri: '127.0.0.1:3303'            advertise:              client: '127.0.0.1:3303'    storage-b:      leader: storage-b-001      instances:        storage-b-001:          iproto:            listen:            - uri: '127.0.0.1:3304'            advertise:              client: '127.0.0.1:3304'        storage-b-002:          iproto:            listen:            - uri: '127.0.0.1:3305'            advertise:              client: '127.0.0.1:3305'

Основные параметры на уровне группы:

  • roles: этот параметр включает роль roles.crud-storage, предоставляемую модулем CRUD, для всех экземпляров хранилищ.

  • app: параметр app.module указывает, что код для хранилищ должен загружаться из модуля storage. Это описано ниже в разделе Добавление кода хранилища.

  • sharding: параметр sharding.roles указывает, что все экземпляры в этой группе выступают в роли хранилищ. Балансировщик выбирается автоматически из двух master-экземпляров.

  • replication: параметр replication.failover указывает, что лидер в каждом наборе реплик должен быть задан вручную.

  • replicasets: в этом разделе настраиваются два набора реплик, составляющих хранилища кластера.

Чтобы настроить роутер, добавьте следующий код в раздел groups:

routers:  roles: [ roles.crud-router ]  app:    module: router  sharding:    roles: [ router ]  replicasets:    router-a:      instances:        router-a-001:          iproto:            listen:            - uri: '127.0.0.1:3301'            advertise:              client: '127.0.0.1:3301'

Основные параметры на уровне группы:

  • roles: этот параметр включает роль roles.crud-router, предоставляемую модулем CRUD, для экземпляра роутера.
  • app: параметр app.module указывает, что код для роутера должен загружаться из модуля router. Это описано ниже в разделе Добавление кода роутера.
  • sharding: параметр sharding.roles указывает, что экземпляр в этой группе выступает в роли роутера.
  • replicasets: в этом разделе настраивается набор реплик с одним экземпляром роутера.

Итоговая конфигурация

Полученный файл config.yaml должен выглядеть следующим образом:

credentials:  users:    replicator:      password: 'topsecret'      roles: [ replication ]    storage:      password: 'secret'      roles: [ sharding ]
iproto:  advertise:    peer:      login: replicator    sharding:      login: storage
sharding:  bucket_count: 1000
storages:  roles: [ roles.crud-storage ]  app:    module: storage  sharding:    roles: [ storage ]  replication:    failover: manual  replicasets:    storage-a:      leader: storage-a-001      instances:        storage-a-001:          iproto:            listen:            - uri: '127.0.0.1:3302'            advertise:              client: '127.0.0.1:3302'        storage-a-002:          iproto:            listen:            - uri: '127.0.0.1:3303'            advertise:              client: '127.0.0.1:3303'    storage-b:      leader: storage-b-001      instances:        storage-b-001:          iproto:            listen:            - uri: '127.0.0.1:3304'            advertise:              client: '127.0.0.1:3304'        storage-b-002:          iproto:            listen:            - uri: '127.0.0.1:3305'            advertise:              client: '127.0.0.1:3305'
routers:  roles: [ roles.crud-router ]  app:    module: router  sharding:    roles: [ router ]  replicasets:    router-a:      instances:        router-a-001:          iproto:            listen:            - uri: '127.0.0.1:3301'            advertise:              client: '127.0.0.1:3301'
roles: [ roles.crud-router ]app:  module: routersharding:  roles: [ router ]replicasets:  router-a:    instances:      router-a-001:        iproto:          listen:          - uri: '127.0.0.1:3301'          advertise:            client: '127.0.0.1:3301'
roles: [ roles.crud-storage ]  app:    module: storage  sharding:    roles: [ storage ]  replication:    failover: manual  replicasets:    storage-a:      leader: storage-a-001      instances:        storage-a-001:          iproto:            listen:            - uri: '127.0.0.1:3302'            advertise:              client: '127.0.0.1:3302'        storage-a-002:          iproto:            listen:            - uri: '127.0.0.1:3303'            advertise:              client: '127.0.0.1:3303'    storage-b:      leader: storage-b-001      instances:        storage-b-001:          iproto:            listen:            - uri: '127.0.0.1:3304'            advertise:              client: '127.0.0.1:3304'        storage-b-002:          iproto:            listen:            - uri: '127.0.0.1:3305'            advertise:              client: '127.0.0.1:3305'routers:  roles: [ roles.crud-router ]  app:    module: router  sharding:    roles: [ router ]  replicasets:    router-a:      instances:        router-a-001:          iproto:            listen:            - uri: '127.0.0.1:3301'            advertise:              client: '127.0.0.1:3301'

Добавление кода хранилища

Откройте файл storage.lua и определите спейс и индексы внутри box.watch() следующим образом:

box.watch('box.status', function()    if box.info.ro then        return    end    box.schema.create_space('bands', {        format = {            { name = 'id', type = 'unsigned' },            { name = 'bucket_id', type = 'unsigned' },            { name = 'band_name', type = 'string' },            { name = 'year', type = 'unsigned' }        },        if_not_exists = true    })    box.space.bands:create_index('id', { parts = { 'id' }, if_not_exists = true })    box.space.bands:create_index('bucket_id', { parts = { 'bucket_id' }, unique = false, if_not_exists = true })end)
  • Функция box.schema.create_space() создает спейс. Обратите внимание, что созданный спейс bands содержит поле bucket_id. Это поле представляет ключ шардирования, используемый для распределения набора данных по разным экземплярам хранилищ.

Добавление кода роутера

Откройте файл router.lua и загрузите модуль vshard следующим образом:

local vshard = require('vshard')

Настройка параметров сборки

Откройте файл sharded_cluster_crud-scm-1.rockspec и добавьте следующее содержимое:

package = 'sharded_cluster_crud'version = 'scm-1'source  = {    url = '/dev/null',}dependencies = {    'vshard == 0.1.27',    'crud == 1.5.2'}build = {    type = 'none';}

Раздел dependencies включает указанные версии модулей vshard и crud.

Чтобы установить зависимости, необходимо собрать приложение.

Сборка приложения

В терминале перейдите в каталог окружения tt. Затем выполните команду tt build:

$ tt build sharded_cluster_crud   • Running rocks makeNo existing manifest. Attempting to rebuild...   • Application was successfully built

При этом модули vshard и crud, указанные в файле *.rockspec, устанавливаются в каталог .rocks.

Работа с кластером

Запуск экземпляров

Чтобы запустить все экземпляры в кластере, выполните команду tt start:

$ tt start sharded_cluster_crud   • Starting an instance [sharded_cluster_crud:storage-a-001]...   • Starting an instance [sharded_cluster_crud:storage-a-002]...   • Starting an instance [sharded_cluster_crud:storage-b-001]...   • Starting an instance [sharded_cluster_crud:storage-b-002]...   • Starting an instance [sharded_cluster_crud:router-a-001]...

Начальная загрузка кластера

После запуска экземпляров необходимо выполнить начальную загрузку кластера:

  1. Подключитесь к экземпляру роутера с помощью tt connect:

    $ tt connect sharded_cluster_crud:router-a-001   • Connecting to the instance...   • Connected to sharded_cluster_crud:router-a-001
  2. Вызовите vshard.router.bootstrap() выполнения начальной загрузки кластера и распределения всех бакетов по наборам реплик:

sharded_cluster_crud:router-a-001> vshard.router.bootstrap()---- true

Проверка статуса кластера

Чтобы проверить статус кластера, выполните vshard.router.info() на роутере:

sharded_cluster_crud::router-a-001> vshard.router.info()---- replicasets:    storage-b:      replica:        network_timeout: 0.5        status: available        uri: storage@127.0.0.1:3305        name: storage-b-002      bucket:        available_rw: 500      master:        network_timeout: 0.5        status: available        uri: storage@127.0.0.1:3304        name: storage-b-001      name: storage-b    storage-a:      replica:        network_timeout: 0.5        status: available        uri: storage@127.0.0.1:3303        name: storage-a-002      bucket:        available_rw: 500      master:        network_timeout: 0.5        status: available        uri: storage@127.0.0.1:3302        name: storage-a-001      name: storage-a  bucket:    unreachable: 0    available_ro: 0    unknown: 0    available_rw: 1000  status: 0  alerts: ...

Вывод включает следующие разделы:

  • replicasets: содержит информацию о хранилищах и их доступности.
  • bucket: отображает общее количество бакетов для чтения-записи и только для чтения, доступных в данный момент для этого роутера.
  • status: число от 0 до 3, показывающее наличие проблем в кластере. Значение 0 означает отсутствие проблем.
  • alerts: может содержать описание конкретных проблем, связанных с начальной загрузкой кластера, например, проблем с подключением, событий failover или неидентифицированных бакетов.

Запись и выборка данных

  1. Чтобы вставить тестовые данные, вызовите crud.insert_many() на роутере:
crud.insert_many('bands', {     { 1, box.NULL, 'Roxette', 1986 },     { 2, box.NULL, 'Scorpions', 1965 },     { 3, box.NULL, 'Ace of Base', 1987 },     { 4, box.NULL, 'The Beatles', 1960 },     { 5, box.NULL, 'Pink Floyd', 1965 },     { 6, box.NULL, 'The Rolling Stones', 1962 },     { 7, box.NULL, 'The Doors', 1965 },     { 8, box.NULL, 'Nirvana', 1987 },     { 9, box.NULL, 'Led Zeppelin', 1968 },     { 10, box.NULL, 'Queen', 1970 }})

Вызов этой функции распределяет данные равномерно по узлам кластера.

  1. Чтобы получить кортеж по указанному ID, вызовите функцию crud.get():
sharded_cluster_crud:router-a-001> crud.get('bands', 4)---- rows:- [4, 161, 'The Beatles', 1960] metadata: [{'name': 'id','type': 'unsigned'}, {'name': 'bucket_id', 'type':'unsigned'}, {'name': 'band_name', 'type': 'string'},{'name': 'year', 'type': 'unsigned'}] - null
  1. Чтобы вставить новый кортеж, вызовите crud.insert():
sharded_cluster_crud:router-a-001> crud.insert('bands', {11, box.NULL, 'The Who', 1962})---- rows:- [11, 652, 'The Who', 1962] metadata: [{'name': 'id','type': 'unsigned'}, {'name': 'bucket_id', 'type':'unsigned'}, {'name': 'band_name', 'type': 'string'},{'name': 'year', 'type': 'unsigned'}] - null

Проверка распределения данных

Чтобы проверить, как данные распределены по наборам реплик, выполните следующие шаги:

  1. Подключитесь к любому хранилищу в наборе реплик storage-a:
$ tt connect sharded_cluster_crud:storage-a-001   • Connecting to the instance...   • Connected to sharded_cluster_crud:storage-a-001

Затем выберите все кортежи в спейсе bands:

sharded_cluster_crud:storage-a-001> box.space.bands:select()---- - [1, 477, 'Roxette', 1986]- [2, 401, 'Scorpions', 1965]- [4, 161, 'The Beatles', 1960]- [5, 172, 'Pink Floyd', 1965]- [6, 64, 'The Rolling Stones', 1962]- [8, 185, 'Nirvana', 1987]
  1. Подключитесь к любому хранилищу в наборе реплик storage-b:
$ tt connect sharded_cluster_crud:storage-b-001   • Connecting to the instance...   • Connected to sharded_cluster_crud:storage-b-001

Выберите все кортежи в спейсе bands, чтобы убедиться, что он содержит другое подмножество данных:

sharded_cluster_crud:storage-b-001> box.space.bands:select()---- - [3, 804, 'Ace of Base', 1987]- [7, 693, 'The Doors', 1965]- [9, 644, 'Led Zeppelin', 1968]- [10, 569, 'Queen', 1970]- [11, 652, 'The Who', 1962]