Использование спейсов на движке vinyl | Tdb
Руководство пользователя Работа с движками базы данных Использование спейсов на движке vinyl

Использование спейсов на движке vinyl

Доступно с версии 3.0.0.

В этом руководстве описаны создание спейса vinyl, его настройка, а также выполнение операций с этим спейсом через модуль CRUD.

Рекомендации по настройке параметров vinyl приведены в разделе Методика настройки движка vinyl в Tarantool DB.

Пререквизиты

Для выполнения примера вам понадобятся:

  • установленный Docker-образ Tarantool DB;

  • приложение Docker Compose;

  • утилита tt CLI;

  • исходные файлы примера vinyl.

    Примечание

    Есть два способа получить исходные файлы примера:

    • Архив с полной документацией Tarantool DB, полученный по почте или скачанный в личном кабинете tarantool.io. Пример архива: tarantooldb-documentation-3.0.0.tar.gz. Пример vinyl расположен в таком архиве в директории ./doc/examples/vinyl/.

    • Отдельный архив vinyl.tar.gz, скачанный c сайта Tarantool.

Запуск стенда

Для успешного запуска стенда должны быть свободны следующие порты:

  • 2379

  • 3300–3308

  • 8081

Перейдите в папку с примером vinyl:

cd ./doc/examples/vinyl/

Запустите стенд:

make start

После выполнения команды будет развернут следующий стенд:

  • кластер Tarantool DB:

    • 2 роутера;

    • 2 набора реплик по 3 хранилища;

  • кластер etcd из 3 узлов;

  • веб-интерфейс Tarantool Cluster Manager (TCM).

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

Также после запуска кластера становится доступен веб-интерфейс TCM. Через TCM вы можете управлять кластером и подключаться к его узлам. Для входа в TCM откройте в браузере адрес http://localhost:8081. Логин и пароль для входа:

  • Username: admin

  • Password: secret

Особенности работы с vinyl

При работе с дисковым движком vinyl необходимо учитывать следующие особенности, отличающие его от движка memtx:

  • функция len() возвращает только приблизительное количество кортежей в спейсе. Если необходимо точное количество кортежей, используйте функцию count() или pairs():length(), но имейте в виду, что эти операции значительно медленнее;

  • операция delete не возвращает удалённый кортеж. Если нужно получить значение удаленного кортежа, перед его удалением выполните операцию get;

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

Подробнее о различиях между vinyl и memtx можно узнать в документации Tarantool.

Создание спейса vinyl

В руководстве при запуске кластера применяется миграция из файла ./cluster/migrations/scenario/001_messages.lua примера vinyl. В этой миграции создан на движке vinyl шардированный спейс messages для хранения пользовательских сообщений:

if is_storage() then
    box.schema.space.create('messages', { engine = 'vinyl', if_not_exists = true })
    box.space.messages:format({
        { name = 'id', type = 'number' },
        { name = 'bucket_id', type = 'unsigned' },
        { name = 'text', type = 'string' },
        { name = 'created_at', type = 'datetime' },
    })

    box.space.messages:create_index('bucket_id', { parts = { 'bucket_id', 'id' }, if_not_exists = true })

    helpers.register_sharding_key('messages', { 'id' })

Составной первичный индекс

Спейс messages использует составной первичный индекс по двум полям:

box.space.messages:create_index('bucket_id', { parts = { 'bucket_id', 'id' }, if_not_exists = true })

Здесь:

  • bucket_id – идентификатор виртуального сегмента, используемый для шардирования;

  • id – идентификатор сообщения.

При использовании движка vinyl создание отдельного вторичного индекса по bucket_id избыточно и неэффективно по двум причинам:

  • каждый вторичный индекс в vinyl представляет собой отдельное LSM-дерево, требующее дополнительное место на диске;

  • при поиске по вторичному индексу Tarantool сначала находит первичный ключ во вторичном индексе, а затем обращается к первичному индексу для получения полной записи. При выполнении range-запроса это приводит к случайным чтениям с диска.

Использование составного первичного индекса { bucket_id, id } дает возможность шардирования без издержек вторичного индекса.

Для настройки производительности индексов в vinyl доступны следующие параметры конфигурации:

  • vinyl.bloom_fpr – коэффициент ложноположительного срабатывания фильтра Блума. Чем ниже значение, тем точнее фильтр, но больше потребление памяти. Значение по умолчанию: 0.05;

  • vinyl.page_size – размер страницы при чтении и записи в байтах. Значение по умолчанию: 8192;

  • vinyl.range_size – максимальный размер диапазона по умолчанию (в байтах);

  • vinyl.run_count_per_level – максимальное количество .run-файлов на каждом уровне LSM-дерева. Чем больше значение, тем шире LSM-дерево. Значение по умолчанию: 2;

  • vinyl.run_size_ratio – соотношение между размерами уровней в LSM-дереве. Чем меньше значение, тем выше LSM-дерево. Значение по умолчанию: 3.5.

Задать настройки спейса, связанные с движком vinyl, можно двумя способами:

  • в YAML-конфигурации кластера в секции vinyl;

  • в опции index_opts при создании индекса через space_object:create_index().

Подробную информацию о поддерживаемых опциях конфигурации для движка vinyl можно найти в документации Tarantool.

Регистрация ключа шардирования

Модуль CRUD по умолчанию вычисляет bucket_id по первичному ключу, поэтому в миграции необходимо явно указать id в качестве ключа шардирования:

helpers.register_sharding_key('messages', { 'id' })

Работа с данными через модуль CRUD

Чтобы начать работу с базой данных через интерактивную консоль Tarantool, нужно подключиться к узлу кластера. Это можно сделать двумя способами:

  • через веб-интерфейс TCM;

  • через терминал с помощью утилиты tt CLI:

    tt connect admin:secret-cluster-cookie@localhost:3301
    

Подключитесь к роутеру router-msk, используя первый способ – через TCM. Для этого:

  1. Перейдите в раздел Stateboard.

  2. Нажмите на набор реплик router-msk.

  3. Выберите узел router-msk и в открывшемся окне перейдите на вкладку Terminal (TT Connect).

Теперь вы находитесь в интерактивной консоли Tarantool и можете выполнять запросы к кластеру.

Определение вспомогательной функции

Для удобства ввода данных добавьте в консоль следующую вспомогательную функцию:

  • now() – функция возвращает текущее время:

    function now()
        local datetime = require('datetime')
        return datetime.now()
    end
    

Вставка данных

Во вкладке Terminal добавьте несколько сообщений в спейс messages с помощью метода crud.insert_object_many:

crud.insert_object_many('messages', {
    { id = 1, text = 'Привет!', created_at = now() },
    { id = 2, text = 'Hello world', created_at = now() },
    { id = 3, text = 'Bye', created_at = now() },
    { id = 4, text = 'Ok', created_at = now() },
    { id = 5, text = 'Hi', created_at = now() },
})

Выборка данных

Посмотрите содержимое спейса, используя операцию crud.select():

crud.select('messages')

Вывод:

---
- rows:
  - [1, 12477, 'Привет!', '2025-08-28T11:12:09.028308Z']
  - [3, 11804, 'Bye', '2025-08-28T11:12:09.028313Z']
  - [5, 1172, 'Hi', '2025-08-28T11:12:09.028333Z']
  - [2, 21401, 'Hello world', '2025-08-28T11:12:09.028312Z']
  - [4, 28161, 'Ok', '2025-08-28T11:12:09.028330Z']
  metadata: [{'name': 'id', 'type': 'number'}, {'name': 'bucket_id', 'type': 'unsigned'},
    {'name': 'text', 'type': 'string'}, {'name': 'created_at', 'type': 'datetime'}]
- null
...

Получение одной записи

Прочитайте запись с id = 1:

crud.get('messages', { box.NULL, 1 })

Вывод:

---
- rows:
  - [1, 12477, 'Привет!', '2025-08-28T11:12:09.028308Z']
  metadata: [{'name': 'id', 'type': 'number'}, {'name': 'bucket_id', 'type': 'unsigned'},
    {'name': 'text', 'type': 'string'}, {'name': 'created_at', 'type': 'datetime'}]
- null
...

Обновление записи

Обновите сообщение с id = 2, изменив его текст:

crud.update('messages', { box.NULL, 2 }, { {'=', 'text', 'Some text'} })

Вывод:

---
- rows:
  - [2, 21401, 'Some text', '2025-08-28T11:12:09.028312Z']
  metadata: [{'name': 'id', 'type': 'number'}, {'name': 'bucket_id', 'type': 'unsigned'},
    {'name': 'text', 'type': 'string'}, {'name': 'created_at', 'type': 'datetime'}]
- null
...

Удаление записи

Удалите сообщение с id = 1:

crud.delete('messages', { box.NULL, 1 })

Вывод:

---
- rows: []
  metadata: [{'name': 'id', 'type': 'number'}, {'name': 'bucket_id', 'type': 'unsigned'},
    {'name': 'text', 'type': 'string'}, {'name': 'created_at', 'type': 'datetime'}]
- null
...

Примечание

Операция delete в vinyl не возвращает удалённый кортеж.

Остановка стенда

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

make stop
Нашли ответ на свой вопрос?
Обратная связь