В прошлом году Tarantool исполнилось 15 лет. Он прошел долгий путь от обычного кэша до платформы управления данными с десятками разных внутренних продуктов и расширений. Такое обилие инструментов создает множество возможностей — и в этой статье мы расскажем о десяти, о которых многие забывают или попросту не знают.
Кластерный конфиг
Одно из главных нововведений в последней мажорной версии Tarantool — единая точка конфигурации.
Настраивать Tarantool через box.cfg слишком сложно? Неудобно хранить настройки в Lua-файлах или передавать их через env? В Tarantool 3.0 появилась возможность создать общий кластерный конфиг для всех узлов Tarantool.
Чтобы запустить Tarantool, вам понадобится конфиг следующего вида:
# объявляем пользователей в кластере credentials: users: guest: roles: [super] # объявляем настройки для подключения к узлу iproto: listen: - uri: 'unix/:./{{ instance_name }}.iproto' # описываем топологию кластера и настройки всех узлов groups: group-001: replicasets: replicaset-001: instances: instance-001: {}
Потом понадобится выполнить следующую команду:
tarantool --config config.yaml --name instance-001
Что можно указать в конфигурационном файле:
-
все параметры для настройки Tarantool (то, что раньше указывалось в box.cfg);
-
топологию, в том числе и для шардированного кластера;
-
параметры и роли приложений (похожим образом, как в картридже);
-
параметры фейловера — в скором времени мы добавим их еще больше.
В Tarantool Enterprise конфиг можно хранить в etcd, и обновления будут загружаться в Tarantool автоматически.
Больше примеров лежит в гитхабе.
Персистентность и WAL
Многие все еще думают о Tarantool как о простом кэше, который нельзя использовать для хранения важных данных. Когда-то это было так, но все давно изменилось. Персистентность в Tarantool включена по умолчанию: он всегда сохраняет данные на диске, перед тем как отдать пользователю подтверждение записи.
Но вы всегда можете превратить Tarantool в кэш всего одной настройкой:
box.cfg{wal_mode = 'none'} -- делаем из Tarantool кэш
А для автоматического удаления устаревших данных можно использовать наш модуль expirationd:
local expirationd = require("expirationd") function is_expired(args, tuple) return true end function delete_tuple(space, args, tuple) box.space[space]:delete{tuple[1]} end expirationd.start(job_name, space.id, is_expired, { process_expired_tuple = delete_tuple, args = nil, tuples_per_iteration = 50, full_scan_time = 3600 })
Синхра и рафт
Вам нужны дополнительные гарантии при записи? Вас пугает асинхронная репликация? Попробуйте синхру! А если вы хотите автоматическое переключение лидера, не забудьте настроить рафт.
Мы писали о рафте и синхре на Хабре много раз, но, если вы пропустили, рекомендуем ознакомиться подробнее в предыдущих статьях:
-
Балансируем между консистентностью и доступностью в распределенной системе: опыт Tarantool
-
Raft (не)всемогущий: какие надстройки повышают надежность алгоритма
Как пользоваться синхрой и рафтом?
Первый узел:
# объявляем пользователей в кластере credentials: users: admin: password: 'passwd' roles: [super] # объявляем настройки для общения инстансов между собой # (их также можно задавать на уровне узлов, репликасетов и групп) iproto: listen: - uri: 'unix/:./{{ instance_name }}.iproto' advertise: peer: login: 'admin' # включаем автоматический фейловер на базе Raft replication: failover: election # описываем топологию кластера и настройки всех узлов groups: group-001: replicasets: replicaset-001: instances: instance-001: {} instance-002: {} instance-003: {}
Запускаем кластер:
tarantool --config config.yaml --name instance-001 tarantool --config config.yaml --name instance-002 tarantool --config config.yaml --name instance-003
Снова на первом узле:
box.ctl.promote() box.schema.space.create('employees', {is_sync = true}) box.space.customers:format({ {name = 'id', type = 'integer'}, {name = 'name', type = 'string'}, {name = 'salary', type = 'integer'}, {name = 'department', type = 'string'}, }) box.space.employees:create_index('pk', {parts = {'id'}) -- теперь можно работать с данными: box.space.customers:insert{...}
Хранение на диске с Vinyl
Tarantool, как и все современные базы данных, умеет сохранять данные на диске.
Процесс создания дискового спейса в Tarantool ничем не отличается от спейсов в памяти:
-- создаем спейс с дисковым движком box.schema.create_space('former_employees', {engine = 'vinyl'}) box.space.former_employees:format({ {name = 'id', type = 'integer'}, {name = 'name', type = 'string'}, {name = 'salary', type = 'integer'}, {name = 'department', type = 'string'}, {name = 'end_date', type = 'datetime'}, }) box.space.former_employees:create_index('pk', {parts = {'employee_id'}}) -- переносим устаревшие данные в холодное хранилище box.begin() for key, tuple in box.space.employees.index.end_date:pairs(now, {iterator = 'LE'}) do box.space.former_employees:insert(tuple) box.space.employees:delete(key) end box.commit()
При работе с vinyl всегда стоит помнить о том, что Tarantool в первую очередь in-memory-технология. У дискового движка есть серьезные ограничения — например, мы не рекомендуем создавать больше одного индекса для таких данных и делать апдейты в сохраненных данных.
Подробнее о vinyl можно прочитать в статье на Хабре.
Констрейнты и внешние ключи
Хотите, чтобы было как в SQL? Попробуйте констрейнты и внешние ключи.
-- Define a tuple constraint function -- box.schema.func.create('check_dates', { language = 'LUA', is_deterministic = true, body = [[function(t) if t.end_date then return t.start_date < t.end_date end return end]] }) -- Define a field constraint function -- box.schema.func.create('check_salary', { language = 'LUA', is_deterministic = true, body = 'function(f) return f > 0 and f < 10^9 end' }) box.schema.space.create('departments') box.space.deparments:format({ {name = 'id', type = 'string'}, {name = 'name', type = 'string'}, {name = 'manager', type = 'string'}, }) box.space.deparments:create_index('pk', {parts = {'id'}}) box.schema.space.create('employees', {constraint = 'check_dates'}) box.space.customers:format({ {name = 'id', type = 'integer'}, {name = 'name', type = 'string'}, {name = 'salary', type = 'integer', constraint = 'check_salary'}, {name = 'department', type = 'string', foreign_key = {space = 'departments', field = 'id'}}, {name = 'start_date', type = 'datetime'}, {name = 'end_date', type = 'datetime', is_nullable = true}, }) box.space.employees:create_index('pk', {parts = {'id'})
Помните, что для некоторых изменений формата вам потребуется произвести дополнительные миграции.
Транзакции, стримы и отменяемые запросы
Вы привыкли, что в транзакциях в Tarantool нельзя идлить? Привыкли к тому, что все транзакции по умолчанию serializable? Хотите более гибкого контроля над транзакциями? Используйте MVCC-движок:
local fiber = require('fiber') local log = require('log') box.cfg{memtx_use_mvcc_engine = true} box.schema.create_space('test') box.space.test:format{{name='first', type='string'}, {name='second', type='integer'}} box.space.test:create_index('pk', {parts = {'first'}}) box.space.test:put{'value', 1} fiber.new(function() v1 = box.space.test:select() end) -- этот код исполнится после йилда box.atomic(function() box.space.test:put{'value', 2} fiber.yield() v2 = box.space.test:select() box.space.test:put{'value', 3} end) v3 = box.space.test:select() log.info(v1, v2, v3) --- # это значение в момент йилда в транзакции, # транзакция не завершена, поэтому мы получаем старое значение - - ['value', 1] # это значение, прочитанное в транзакции # в рамках самой транзакции эти данные уже существуют, поэтому здесь 2 - - ['value', 2] # это значение, полученное после завершения транзакции - - ['value', 3] ...
Вы также можете использовать интерактивные транзакции или выбирать время, через которое долгие запросы будут отменены:
fiber.set_max_slice{warn = 0.5, err = 1.0}
SQL
Вы страдаете от того, что нужно писать сложные запросы на Lua? Боитесь, что ваши аналитики не справятся с Tarantool? Напишите запросы на SQL! (Или прочитайте статью про сложные запросы в Tarantool).
Вот так можно создать таблицу и написать к ней запросы на SQL.
1. Для начала вам потребуется поменять язык в тарантульной консоли (если вы работаете через подключение к узлу) с помощью \set language sql
или позвать команду box.execute
и передать туда свой SQL-запрос.
Создаем таблицы:
CREATE TABLE employees ( id INTEGER, name STRING, salary INTEGER, department STRING, PRIMARY KEY (id) ); CREATE TABLE departments ( id STRING, manager STRING, PRIMARY KEY (id) );
2. Создаем индексы:
CREATE INDEX salary ON employees (salary);
3. Вставляем данные:
INSERT INTO departments VALUES ('Sales', 'Mighty Manager'); ... INSERT INTO employees VALUES (1, 'John', 100000, 'Sales'); ...
4. Пишем запросы:
SET SESSION "sql_seq_scan" = true; SELECT department, AVG(salary) FROM employees GROUP BY department; --- - metadata: - name: department type: string - name: COLUMN_1 type: integer rows: - ['Sales', 100000]
5. Пишем джойны:
SELECT employees.name, employees.salary, employees.department, department.manager FROM employees JOIN departments ON (employees.department = departments.id); - metadata: - name: name type: string - name: salary type: integer - name: department type: string - name: manager type: string rows: - ['John', 100000, 'Sales', 'Mighty Manager']
Больше примеров — в гайде по Tarantool.
И помните, что с любыми тарантульными спейсами можно работать как из Lua, так и из SQL, меняя подход в зависимости от задачи.
Шардирование
Шардирование — стандартный подход к масштабированию баз данных. В отличие от многих реляционных БД, в Tarantool шардирование давно стало стандартным модулем и поддерживается в конфиге. Все, что нужно сделать, — установить модуль vshard (tt rocks install vshard
) и написать кластерный конфиг для Tarantool:
credentials: users: admin: password: 'passwd' roles: [super] iproto: listen: - uri: 'unix/:./{{ instance_name }}.iproto' advertise: peer: login: 'admin' sharding: login: 'admin' sharding: bucket_count: 10000 replication: failover: election groups: storages: sharding: roles: [storage] replicasets: storages-001: instances: storage-001: iproto: listen: - uri: 'localhost:3301' storage-002: iproto: listen: - uri: 'localhost:3302' storages-002: instances: storage-003: iproto: listen: - uri: 'localhost:3303' storage-004: iproto: listen: - uri: 'localhost:3304' routers: replicasets: routers-001: sharding: roles: [router] instances: router-001: iproto: listen: - uri: 'localhost:3300' tt connect admin:passwd@localhost:3300
Чтобы начать работать с шардом, надо забутстрапить кластер:
vshard.router.bootstrap()
Теперь можно вставлять данные. На роутере:
vshard.router.callrw('box.space.test_space:insert', {...})
Хранение данных в различных парадигмах
Современный Tarantool позволяет вам применять различные парадигмы для работы с данными. Вот некоторые из примеров различных подходов, которые вы можете комбинировать в Tarantool:
-
key-value, document. Настройки формата в Tarantool позволяют вам не применять никакой формат вообще, что дает вам построить документное или kv-хранилище.
-
cache/master-storage. Tarantool можно использовать в качестве кэша (см. выше) или надежно хранить там важные данные.
-
in-memory/disk. Держите ваши спейсы в памяти, сгрузите все на диск или сделайте и то, и другое.
-
graph. Вы можете написать графовое хранилище самостоятельно, воспользовавшись нашими R-TREE-индексами, или взять готовый Tarantool Graph DB (Enterprise only).
-
column. Что? Хранение данных в колонках в памяти? В Tarantool? Да, с недавнего времени в Tarantool ЕЕ появился новый движок для хранения колонок.
-
queue. На Tarantool построено огромное количество очередей. Есть как бесплатные Tarantool queue и Sharded-queue, а есть Tarantool Queue Enterprise. Подробнее об очередях можно почитать в статье на Хабре.
-
cluster, multi-cluster. Tarantool отлично работает в кластерном режиме. Вы можете строить свои шардированные хранилища на базе опенсорсных vshard и Cartridge, а можете взять энтерпрайзные TDG или TDB. Также на Tarantool можно создать два кластера, которые полностью дублируют свои данные, с помощью Tarantool Clusters Federation.
Графический интерфейс
Управлять кластером всегда проще, когда можно взглянуть на страницу с обновляющимися онлайн статусами. Tarantool есть что вам предложить.
Grafana Dashboard
Тарантульный дашборд с метриками предоставляет все возможные параметры, за которыми можно следить. Все, что вам нужно знать о вашем тарантульном кластере, находится здесь: память, CPU и все возможные параметры рантайма в одном месте. Подробнее в статье на Хабре.
Если вы не любите настраивать кластеры через консоль или вам просто нужен удобный дашборд, где можно быстро узнать статус кластера и исправить известные проблемы в несколько кликов мышки, то вам следует попробовать один из наших продуктов с графическим интерфейсом.
Cartridge
Для Tarantool 1.10 / 2.х есть Cartridge — как создать первое приложение c его помощью, можно прочитать по ссылке. Помимо отображения информации о состоянии кластера, Cartridge занимается управлением кластерами и предоставляет свое API для различных настроек в кластере.
Tarantool Cluster Manager
Для новых кластеров на Tarantool 3.х есть Tarantool Cluster Manager (EE-only). В отличие от Cartridge, в TCM меньше управления кластером Tarantool (теперь кластерными вещами занимается сам Tarantool), но при этом больше возможностей для мониторинга и управления отдельными узлами, в том числе в разных кластерах.
Заключение
Это далеко не все возможности, которые может вам предложить современный Tarantool: достойны упоминания триггеры, кастомные аллокаторы, подключение к узлу из разных потоков и метрики в ядре по умолчанию. Но в одной статье все не перечислишь. Поэтому если вы пользуетесь Tarantool, следите за обновлениями. А если еще нет — обязательно попробуйте, у Tarantool наверняка есть что вам предложить.
Узнавайте о новых релизах, вебинарах и выходящих статьях в телеграм-канале Tarantool News.
Задать вопросы команде разработчиков про использование Tarantool можно в официальном канале сообщества.
О принципах и примерах работы продуктов Tarantool читайте в блоге на сайте.
ссылка на оригинал статьи https://habr.com/ru/articles/843068/
Добавить комментарий