Коннекторы: Python, Go, Java

Рейтинг: 56.5% · 9 голосов
Исчерпывающий курс по Tarantool 3.x: модель данных, движки memtx и vinyl, Lua и файберы, транзакции и MVCC, SQL, конфигурация (box.cfg и декларативная 3.x), репликация и Raft, шардирование vshard, эксплуатация, безопасность. 47 уроков со схемами.
Ответить
Аватара пользователя
denis_tnt
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Коннекторы: Python, Go, Java

Сообщение denis_tnt »

Оглавление курса (47)
  1. Что такое Tarantool: in-memory СУБД и сервер приложений
  2. Архитектура изнутри: процесс, потоки, event-loop
  3. Установка и первый запуск: tt CLI, пакеты, Docker
  4. Интерактив: консоль, admin-консоль, первые команды
  5. Спейсы и кортежи: форматы, типы данных
  6. Типы индексов и их применимость
  7. Движки хранения: memtx vs vinyl
  8. DDL: схема, создание спейсов и индексов, миграции
  9. DML и выборки: insert/update/upsert, итераторы
  10. Персистентность: WAL, снапшоты, recovery
  11. Внутренности memtx: аллокаторы slab/arena, память
  12. Внутренности vinyl: LSM, компакция, тюнинг
  13. Lua и LuaJIT в Tarantool: box, модули, rocks
  14. Файберы: кооперативная многозадачность, каналы
  15. Транзакции: ACID, изоляция, MVCC
  16. Хранимые процедуры, модули, организация приложения
  17. net.box: удалённые вызовы, async
  18. Пулы соединений, балансировка, реконнект
  19. Ошибки и диагностика: box.error, pcall
  20. Типы и сериализация: MsgPack, decimal, datetime, uuid
  21. SQL в Tarantool: возможности и связь с box
  22. SQL: таблицы, JOIN, подзапросы, представления
  23. SQL: подготовленные выражения, транзакции, Lua-интероп
  24. Классическая конфигурация box.cfg (legacy 1.x/2.x)
  25. Декларативная конфигурация 3.x: config.yaml, иерархия
  26. Роли и приложения в 3.x
  27. Централизованная конфигурация: etcd / config storage
  28. tt CLI глубоко: разработка, сборка, запуск
  29. Cartridge (официальный legacy) и миграция на 3.x
  30. Репликация: replicaset, топологии
  31. Механика репликации: WAL-стриминг, vclock
  32. Синхронная репликация и выборы лидера (Raft)
  33. Жизненный цикл узла: bootstrap, join, rejoin
  34. vshard: router/storage, виртуальные бакеты
  35. Решардинг и rebalancing бакетов
  36. Запросы поверх шардов: map-reduce, crud
  37. Мониторинг: метрики, Prometheus, Grafana
  38. Логирование и аудит
  39. Бэкапы и восстановление
  40. Безопасность: аутентификация, RBAC, TLS
  41. Производительность: профилирование, тюнинг
  42. Обновления: схема, rolling upgrade
  43. Деплой в продакшен: Docker, топология (официальные паттерны)
  44. Администрирование через официальный TCM (Tarantool Cluster Manager)
  45. Коннекторы: Python, Go, Java (вы здесь)
  46. Ключевые модули (rocks): crud, metrics, queue, expirationd
  47. Capstone: шардированный отказоустойчивый кластер
Обзор: зачем нужны коннекторы

Коннектор (драйвер) - это библиотека для конкретного языка, которая позволяет приложению общаться с Tarantool по сети, не зная деталей бинарного протокола. Снаружи это выглядит как обычный клиент БД: открыл соединение, вызвал insert/select/call, получил данные в виде нативных объектов языка. Внутри коннектор делает всю грязную работу - сериализует запрос в MsgPack, кладёт его в TCP-сокет, сопоставляет ответ с запросом и десериализует результат обратно.

Все коннекторы Tarantool делятся на две группы: те, что поддерживает команда Tarantool, и общественные. Официально командой ведутся: Go (go-tarantool), Python (tarantool-python), Java (Tarantool Java SDK), а также C (high-level C API) и C++. Остальные - community, и поддержка новых фич там может запаздывать.
Важно понимать: коннектор - это НЕ часть ядра Tarantool. Он ставится отдельно (pip, go get, Maven) и развивается своим репозиторием со своим версионированием. Сервер не знает, какой клиент к нему подключился - он видит только байты протокола iproto.
Как это устроено внутри: протокол iproto

Все коннекторы говорят с сервером на одном языке - бинарном протоколе iproto поверх TCP (порт по умолчанию 3301). Понимание этого протокола - ключ к пониманию любого коннектора.

Структура запроса. Каждый запрос начинается с заголовка переменной длины. В заголовке лежат: тип запроса (код операции - insert=02, select, call, eval и т.д.), идентификатор запроса (sync id), идентификатор инстанса, LSN. Перед заголовком всегда идёт его длина - это упрощает чтение для клиента и для прокси. Тело запроса (space id, ключ, кортеж) кодируется в MsgPack - компактный бинарный аналог JSON.

Асинхронность и мультиплексирование. Главная архитектурная черта iproto: сервер отвечает на запрос, как только ответ готов, а в заголовке ответа повторяет тот же sync id, что был в запросе. Поэтому ответы могут приходить В ЛЮБОМ ПОРЯДКЕ, а клиент сопоставляет их по id. Это значит, что по ОДНОМУ соединению можно одновременно держать в полёте десятки запросов, не дожидаясь предыдущего. Именно на этом строится производительность всех хороших коннекторов: один сокет - много параллельных операций.

Что делает коннектор поверх протокола. Помимо сериализации, зрелый драйвер берёт на себя:
  • подгрузку схемы (fetch schema) - чтобы можно было обращаться к спейсам и индексам по именам, а не по числовым id;
  • переподключение (reconnect) при обрыве и проверку живости соединения;
  • пул соединений и обнаружение мастера в кластере;
  • поддержку MsgPack-расширений: decimal, uuid, datetime, interval, error;
  • вотчеры (watchers) и box.session.push() для серверных событий;
  • IPROTO_ID - обмен списком поддерживаемых фич при коннекте.
Изображение
Коннекторы говорят с Tarantool по iproto через MsgPack

Python: tarantool-python

Официальный синхронный коннектор. Ставится через pip:

Код: Выделить всё

pip install tarantool
Минимальный сценарий: подключиться, поработать с данными, вызвать процедуру, закрыться.

Код: Выделить всё

import tarantool

conn = tarantool.Connection('127.0.0.1', 3301,
                            user='sampleuser', password='secret')

conn.insert('bands', (1, 'Roxette', 1986))
conn.select('bands', 1)                 # по первичному ключу
conn.select('bands', 'The Beatles', index='name')  # по вторичному
conn.update('bands', 2, [('=', 2, 'Pink Floyd')])
conn.replace('bands', (1, 'Queen', 1970))
conn.delete('bands', 5)
conn.call('get_bands_older_than', (2000,))  # хранимая процедура
conn.close()
Ключевые свойства: автоматический schema reload, transparent reconnect (reconnect_max_attempts, reconnect_delay), пул соединений с обнаружением мастера, поддержка PEP 249 (DB-API), CRUD-модуль для шардированных кластеров. Чего НЕТ: асинхронности (синхронный по природе) и доступа к полям кортежа по именам. Если нужен asyncio - сообщество предлагает asynctnt.

Go: go-tarantool v2

Официальный коннектор, для продакшена берём именно ветку v2 (стабильный API). MsgPack под капотом - vmihailenco/msgpack.

Код: Выделить всё

go get github.com/tarantool/go-tarantool/v2
Идиома Go - запросы через объекты Request и фьючеры (Future) для асинхронности:

Код: Выделить всё

dialer := tarantool.NetDialer{
    Address: "127.0.0.1:3301",
    User:    "sampleuser", Password: "secret",
}
ctx := context.Background()
conn, _ := tarantool.Connect(ctx, dialer, tarantool.Opts{})

// асинхронно: получаем Future, ждём позже
fut := conn.Do(tarantool.NewInsertRequest("bands").
    Tuple([]interface{}{1, "Roxette", 1986}))
resp, _ := fut.Get()

// синхронно
data, _ := conn.Do(tarantool.NewSelectRequest("bands").
    Index("primary").Iterator(tarantool.IterEq).
    Key([]interface{}{uint(1)})).Get()

conn.CloseGraceful()
Документация прямо рекомендует делать запросы асинхронно - это естественно ложится на мультиплексирование iproto. Есть типизированные select-ы (распаковка кортежа в Go-структуру через теги msgpack), пул соединений с round-robin failover, вотчеры, пагинация. Закрывать соединение лучше через CloseGraceful() - он дожидается завершения запросов в полёте.

Java: Tarantool Java SDK

Сейчас основной и активно развиваемый Java-коннектор - Tarantool Java SDK. Он поддерживает актуальные версии и фичи Tarantool, а интеграции со Spring Data и Testcontainers идут модулями того же проекта.
Грабли версий Java: старый tarantool-java (с JDBC) НЕ поддерживается и не умеет фичи 2.x и кластеры. cartridge-java тоже помечен как deprecated/планируется к выводу. Для новых проектов - только Tarantool Java SDK.
Частые заблуждения и грабли
  • Связь версий клиента и сервера. Коннектор версионируется отдельно от сервера. v1 go-tarantool ещё встречается в старом коде, но для продакшена нужен v2. Старый tarantool-java живёт своей жизнью и устарел.
  • guest без пароля. Примеры часто коннектятся под guest без прав. В реальности нужен пользователь с grant на read/write/execute по конкретным спейсам и функциям, иначе - access denied.
  • select по вторичному индексу. По умолчанию select идёт по первичному ключу. Чтобы искать по другому полю, нужно явно указать индекс (index= в Python, .Index() в Go) и заранее иметь этот индекс в схеме.
  • Шифрование - только Enterprise. Шифрование трафика iproto доступно лишь в Tarantool Enterprise Edition. В Community-версии трафик идёт открытым - выносите его в защищённую сеть или туннель.
  • eval против call. При вызове функции через call коннектор делает доп. преобразования возвращаемых значений (скаляры заворачиваются в кортежи). При прямом eval-слое преобразований нет - результат приходит как голый MsgPack. Это объясняет, почему одна и та же Lua-функция даёт разную форму ответа.
  • Кортеж - всегда массив. Tarantool всегда возвращает результат как массив кортежей, даже если совпал один. Не забывайте брать нулевой элемент.
  • CRUD для кластера. Для одного инстанса хватает обычных insert/select. Для шардированного кластера используйте модуль CRUD (tarantool.crud в Python, пакет crud в Go) - он сам маршрутизирует запрос по бакетам.
Мини-лаба

Подготовьте сервер (один инстанс) и через любой коннектор повторите полный цикл. Сначала на сервере:

Код: Выделить всё

box.cfg{listen = 3301}
box.schema.space.create('bands')
box.space.bands:format({{name='id', type='unsigned'},
                        {name='name', type='string'},
                        {name='year', type='unsigned'}})
box.space.bands:create_index('primary', {parts = {'id'}})
box.space.bands:create_index('name', {parts = {'name'}, unique = true})
box.schema.user.create('sampleuser', {password = 'secret'})
box.schema.user.grant('sampleuser', 'read,write', 'space', 'bands')
Задание: на Python или Go вставьте 3 кортежа, выберите один по первичному ключу и один по индексу name, обновите год у одной группы и удалите одну запись. Проверьте, что select по name возвращает массив из одного кортежа.

Контрольные вопросы
  • За счёт какого поля заголовка iproto клиент может держать много запросов в полёте по одному соединению и сопоставлять ответы, пришедшие не по порядку?
  • Почему доступ к спейсам и индексам по именам возможен только после fetch schema, и что произойдёт при изменении схемы на сервере?
  • Чем отличается форма ответа при вызове функции через call и через eval, и почему?
  • Какой Go-коннектор и какая его ветка рекомендованы для продакшена, и зачем перед закрытием соединения вызывать CloseGraceful()?
👍4 ❤️2 🔥2 😄 🤔3
Ответить
← Предыдущая глава
Администрирование через официальный TCM (Tarantool Cluster Manager)
Следующая глава →
Ключевые модули (rocks): crud, metrics, queue, expirationd

Все главы курса «Tarantool: in-memory СУБД и сервер приложений с нуля до продакшена»

Поделиться темой: ✈ Telegram VK

Вернуться в «Tarantool: СУБД и сервер приложений»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя