Механизм плагинов¶
В данном разделе описан механизм плагинов, с помощью которых можно расширять функциональность Picodata.
Общие сведения¶
Плагин представляет собой единицу законченной функциональности и работает глобально во всем кластере. Плагин обладает следующими свойствами:
- работает с привязкой к явно заданным тирам. Плагины работают именно с тирами, а не с отдельными репликасетами
- даже если предполагается использование плагина на некоторых тирах кластера, он должен быть развернут на всех узлах кластера. Плагин не будет включен, если он отсутствует или поврежден хотя бы на одном активном инстансе кластера
- плагины расширяют функциональность именно СУБД, но никак не связаны друг с другом
Для разработки плагинов предусмотрена библиотека picodata-plugin
.
Для работы плагина версия Picodata должна совпадать с версией библиотеки
picodata-plugin
, которая использована для его сборки. Если версии
различаются, при установке плагина будет выведена ошибка, содержащая
текущую версию Picodata и ожидаемую версию picodata-plugin
.
Проверку совместимости версий можно отключить, задав следующую переменную окружения:
PICODATA_UNSAFE_DISABLE_PLUGIN_COMPATIBILITY_CHECK=1
Отключение проверки совместимости может негативно повлиять на работу плагина и Picodata, поэтому должно быть хорошо обдумано.
Структура плагина¶
Структурно, плагин состоит из трех компонентов:
- Манифест — файл, в котором описана версия плагина, сервисы, их начальная конфигурация и порядок запуска. Манифест является обязательной и неотъемлемой частью плагина и объединяет в себе все его компоненты
- Сервис — обязательная и основная часть плагина, реализующая его логику на языке Rust. Сервис обладает жизненным циклом и состоянием, а также его можно конфигурировать (например, задать время жизни сообщениям, если ваш сервис вычищает данные из таблицы по TTL). В плагине может быть несколько сервисов
- Миграции — набор файлов с расширением *.db, содержащих DML- и DDL-команды, которые логически связаны с плагином. Плагин определяет набор миграций в манифесте. Миграции выполняются при установке и удалении плагина
На файловом уровне плагин представляет собой набор из файла манифеста,
файлов миграций и некоторого числа скомпилированных разделяемых
библиотек в формате *.so
.
Для работы плагин требует наличия дополнительных сущностей:
- версии плагина
- конфигурации плагина
- информации о тирах, на которых будут работать сервисы плагина
Версия указывается при установке/обновлении/удалении плагина, а
конфигурация представляет собой набор значений в глобальной таблице
_pico_plugin_config
для корректной работы сервисов плагина.
Плагины могут создавать свои схемы данных в системных таблицах с помощью механизма миграций.
См. также:
Манифест¶
Манифест плагина содержит следующие обязательные поля:
name
— уникальное имя плагина (в нижнем регистре без пробелов)description
— произвольный текст, раскрывающий функцию и назначение плагинаversion
— версия плагина в формате Semverservice_order
— список, отражающий порядок запуска сервисовservice
— список сервисов. У каждого сервиса должны быть- заполнены поля
name
(имя),description
(описание) - заданы параметры конфигурации по умолчанию в разделе
default_config
.
Манифест плагина представляет собой многоуровневую конфигурацию. Пример показан ниже:
plugin:
description: my new super plugin
name: my_super_plugin
version: 0.1.0
service_order:
- kafka_connector
service:
- name: kafka_connector
description: my service 1
default_config:
property_1:
property_11: true
property_12: false
property_2: 123
migration:
- create_authors.db
- create_books.db
- create_costs.db
Миграции¶
Миграции задаются в манифесте плагина с помощью
дополнительной секции migration
.
Внутри файл миграций содержит аннотации и SQL-команды. Пример:
-- pico.UP
CREATE TABLE authors (
id int NOT NULL,
name text,
PRIMARY KEY(id)
);
INSERT INTO authors VALUES (1, "Aleksandr Pushkin");
INSERT INTO authors VALUES (2, "Vladimir Mayakovsky");
-- pico.DOWN
DROP TABLE authors;
Аннотации разделяют части миграций, отвечающие за установку и удаление плагина.
Аннотация pico.UP
является обязательной и должна быть указана в первой
строке файла. Аннотация pico.DOWN
опциональна.
Использование параметров конфигурации плагина¶
В миграциях можно ссылаться на значения из установленной
конфигурации плагина установленные в пространстве имен migration_context.
Например, установим значение конфигурации red_tier
:
ALTER PLUGIN myplugin 0.1.0 SET migration_context.red_tier='my_tier';
После этого в теле миграции появляется возможность ссылаться на установленный параметр:
CREATE TABLE T (A INT) ON TIER @_plugin_config.red_tier;
Основной сценарий использования подобной подстановки параметров — задание тиров, на которых будут созданы нужные для работы плагина таблицы. Для этого в синтаксисе создания таблицы существует возможность указать тир. Таким образом, на этапе разработки плагина можно определить, какие объекты БД нужны для работы плагина, и описать их создание в файле миграций.
На этапе разработки плагина необходимо определить, сколько тиров потребуется. Поскольку конкретные имена тиров в кластере еще неизвестны, то имеет смысл указать имена в конфигурации плагина. Посредством подстановки имя тира в кластере становится доступным в миграции.
Сервис¶
Каждый .so
-файл может содержать один или несколько сервисов. Сервис
представляет собой реализацию trait’а Service, а также функцию,
помеченную атрибутом #[service_registrar]
, которая регистрирует сервис
в Picodata. Для того чтобы создать сервис, необходимо воспользоваться
библиотекой picoplugin
, которая предоставляет trait Service и макрос
#[service_registrar]
.
Примечание
Так как Rust не имеет стабильного ABI, то это
значит что мы не можем использовать этот тип при пересечении
“границы” между .so
-файлом и picodata
. Поэтому библиотека
picoplugin
предоставляет специальный тип ServiceBox
который
может безопасно перемещаться между .so
-файлами пользователя и
picodata
. Для реализации такого типа используется библиотека
abi_stable
Трейт Service¶
Для создания сервиса плагин должен реализовать трейт Service
.
Большинство методов в нем являются необязательными. Для реализации
трейта пользователю необходимо, как минимум, реализовать метод name
и
указать тип для конфигурации (если конфигурация не нужна — следует
указать пустой кортеж ()
).
Код трейта доступен по ссылке.
Регистрация сервиса¶
Вторым шагом необходимо зарегистрировать сервис. Для этого создается функция, помеченная специальным макросом. Эту функцию вызовет Picodata для создания экземпляра сервиса. В функции необходимо указать имя сервиса и версию плагина, для которого сервис создан. Пример такой функции:
#[service_registrar]
fn my_registrar(registry: &mut ServiceRegistry) {
registry.add("kafka_connector", "0.1.0", Service1::new)
}
Конфигурация плагина¶
Конфигурация плагина состоит из двух частей:
- топология сервисов плагина (на каких тирах они работают)
- конфигурация самих сервисов
Сервисы запускаются только на явно заданных тирах (нельзя запустить сервис только на конкретном репликасете или узле из тира).
Топология сервисов хранится в глобальной системной таблице
_pico_service
.
Настроить сервис можно c помощью SQL-запроса. Пример:
ALTER PLUGIN <plugin_name> <version>
ADD SERVICE <service_name>
TO TIER ‘red’
OPTION(timeout=...);
Конфигурация сервисов плагина хранится в глобальной служебной таблице
_pico_plugin_config
как набор key
/value
, где key
— всегда
строка. Никаких ограничений на тип value
не накладывается. Это
позволяет использовать в виде отдельных ключей те значения, которые чаще
всего будут настраиваться, что позволит избежать полной перезаписи
конфигурации на каждое изменение.
Пример таблицы с конфигурацией сервиса:
plugin_name | service_name | key | value |
---|---|---|---|
kafka | consumer | mapping | [ { "topic": "my_topic", "autocommit": "false", "table": "my_table" }, { "topic": "my_topic_2", "autocommit": "true", "table": "my_table_2" } ] |
kafka | consumer | kafka_uri | 127.0.0.1:9092 |
Жизненный цикл плагина¶
Жизненный цикл плагина включает в себя следующие этапы:
- установка плагина в кластер
- включение плагина
- отключение плагина
- удаление плагина
- смена конфигурации плагина
Ниже приведены подробности реализации этих этапов. Примеры SQL-команд для работы с плагинами содержатся в руководстве Управление плагинами.
Установка¶
Сначала необходимо заранее скопировать на все узлы кластера .so
-файлы
плагина в директорию share_dir
(задается при запуске инстанса).
Например, можно сделать с помощью роли Ansible.
После этого можно установить манифест плагина — это можно сделать с любого узла кластера.
Установка манифеста проходит в несколько этапов:
- валидация манифеста на узле, с которого происходит установка
- загрузка сериализованной информации из манифеста в системную таблицу
_pico_property
на время установки плагина - централизованная проверка наличия
.so
-файлов на всех живых узлах губернатором в виде вызова.proc_load_plugin_dry_run
- при отсутствии ошибок губернатор заполняет системные таблицы
_pico_plugin
и_pico_service
данными из манифеста с помощью CaS-операции - губернатор удаляет ранее загруженные данные из таблицы
_pico_property
- узлы кластера ожидают очистки таблицы
_pico_property
и затем проверяют таблицу_pico_plugin
на наличие плагина - когда установка плагина подтверждена всеми узлами, выполняются миграции
Включение¶
Установленный в кластере плагин по умолчанию находится в выключенном
состоянии: в системной таблице _pico_plugin
задано значение enable =
false
. Включение проходит следующим образом:
- губернатор проверяет, что значение
pending_plugin_enable
в системной таблице_pico_property
свободно - Raft-лидер инициирует операцию
OpPluginEnable{ plugin_name, on_start_timeout }
на каждом узле кластера - на каждом узле в рамках операции OpPluginEnable происходит выборка
сервисов из таблицы
_pico_service
и локально создается запись в таблице_pico_property
с ключомpending_plugin_enable
и значением{ plugin_name, service_list, on_start_timeout }
- губернатор реагирует на появление ключа
pending_plugin_enable
и отправляет всем живым узлам кластера RPC-запрос.proc_enable_plugin
- плагин включается на узлах кластера, которые используют метаинформацию из указанных выше системных таблиц
- в зависимости от топологии кластера (принадлежности узла к нужному
тиру), на отдельных узлах валидируются и включаются сервисы
плагина. Для каждого сервиса запускаются коллбэки
on_start
, результат возвращается губернатору - в случае успеха губернатор обновляет системную таблицу
_pico_plugin
и устанавливает для плагина свойствоenable = true
, а также заполняет таблицу_pico_service_route
(маршрутизация для RPC) - губернатор очищает значение ключа
pending_plugin_enable
- узлы кластера ожидают очистки
pending_plugin_enable
и после этого проверяют в таблице_pico_plugin
свойствоenable
Отключение¶
Отключение плагина происходит локально на отдельных узлах с последующим подтверждением через Raft:
- узел проверят, что поле
pending_plugin_disable
в системной таблице_pico_property
не заполнено - Raft-лидер инициирует операцию
OpPluginDisable{ plugin_name }
на каждом узле кластера - узел собирает метаинформацию из таблицы
_pico_plugin
и устанавливает для плагина значениеenable=false
- узел в асинхронном режиме вызывает коллбэк
on_stop
для запущенных сервисов - губернатор удаляет информацию о плагине и его сервисах из таблиц
_pico_service_route
и_pico_property
, очищая, в том числе, значение ключаpending_plugin_disable
- узлы кластера ожидают очистки
pending_plugin_disable
Удаление¶
Удаление плагина может быть инициировано на любом узле кластера. Каждый
отдельный узел должен сначала убедиться в том, что плагин отключен (в
таблице _pico_plugin
для плагина установлено значение enable =
false
)
Далее Raft инициирует операцию PluginRemove { plugin_name }
. По
получению этой операции каждый узел очищает таблицы _pico_plugin
и
_pico_service
.