Updated at 2024-04-27 03:30:08.190255

1. Руководство по разработке приложений

Систем-источников сложных бизнес-объектов много, и они разрабатываются разными командами. Даже если системы работают с одними и теми же сущностями, их представление и структура, как правило, отличаются от системы к системе.

Чтобы унифицированно строить запросы по объектам из разных источников, система TDG приводит такие объекты к одному каноническому формату. Для задания формата используется специализированный высокоуровневый язык. Он позволяет описывать структуру объектов, связи между ними и накладываемые на них ограничения.

Чтобы создать приложение для TDG, необходимо описать, разработать и организовать:

  1. Доменную модель (канонический формат объектов), используя соответствующий язык;

  2. Само приложение, взаимодействующее с компонентами TDG и использующее программный интерфейс репозитория для управления объектами модели;

  3. Версионирование модели (согласно ее представлению) и всех необходимых компонентов приложения для поддержания обратной совместимости;

  4. Тесты для проверки логики модулей TDG и приложения на соответствие требованиям.

Данное руководство описывает каждый из данных шагов и содержит сведения, необходимые для их выполнения.

Содержание

1.1. Разработка доменной модели

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

1.1.1. Язык доменной модели

В терминологии системы TDG язык описания является языком доменной модели, при этом домен — синоним понятия предметная область.

Язык доменной модели состоит из двух элементов:

В качестве такого языка используется Avro Schema. Он не сложный и достаточно распространен в сообществе и разрабатываемых им сторонних приложениях.

В стандарте Avro Schema есть два «контейнера», содержащих описания типов: протокол и схема. Оба — JSON-файлы с расширением .avsc.

Приложение использует схему в качестве формата и понимает ее в виде массива типов:

[
    {"name": "TypeA", "type": "record", ...},
    {"name": "TypeB", "type": "record", ...}
]

Каждый тип соответствует стандарту Avro Schema, за исключением расширений для системы TDG. Расширения обратно совместимы, а модель, описанная с их помощью, должна успешно преобразовываться стандартными парсерами (синтаксическими анализаторами).

1.1.2. Объекты модели: агрегат, сущность, значение

В дополнение к типичной для UML (Unified Model Language) терминологии «агрегация и композиция», в TDG есть три дополнительных понятия:

Эти понятия — часть словаря Domain Driven Design. Они описывают классы объектов с точки зрения идентичности и принадлежности.

Идентичность определяет, есть ли у объекта жизненный цикл во времени. Объект имеет идентичность, если остается тем же самым объектом, даже когда его свойства меняются.

Примером класса, объекты которого имеют идентичность, является класс клиент (бизнеса). Изменение имени клиента или его адреса не делает его другим клиентом — это тот же человек. С другой стороны, его адрес не имеет собственной идентичности, потому что смена улицы и дома сделает его другим адресом.

Принадлежность определяет, может ли объект существовать отдельно от другого. Объект самостоятелен, если его создание не требует существования других объектов или если можно удалить тот объект, который на него ссылается, в то время как самостоятельный объект будет жив.

Примером сущности, которая не может существовать отдельно, является паспорт. Паспорта выдаются только существующим людям, и, даже если они были выданы «мертвым душам», полное удаление информации о «душах» потребует удаления информации об их паспортах.

Примером сущности, которая может существовать отдельно, является как сам клиент, так и его договоры. Если договоры или другие объекты, ссылающиеся на пользователя, будут удалены, существование объекта пользователя все еще будет иметь смысл. С другой стороны, если клиент пропал и был удален из системы, например, при компактизации данных или при их повреждении, существование его договоров тоже все еще будет иметь смысл, например, для построения финансовой отчетности.

Является ли объект агрегатом, сущностью или значением, важно не только для контроля жизненного цикла, но и для указания границ транзакционности и возможности ссылаться на объекты.

В пределах одного агрегата все его подчиненные сущности и значения можно обновить транзакционно и атомарно. Любая логика, работающая на уровне агрегата, может на это рассчитывать. Между агрегатами таких гарантий нет, то есть логика, обновляющая несколько агрегатов, является всегда согласованной в конечном счете (eventually consistent).

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

1.1.3. Пример описания на языке доменной модели

Предположим, в системе требуется хранить информацию о клиентах (Client), их паспортах (Passport), адресах (Address), договорах (Contract), счетах (Account) и операциях (Operation) по ним.

Рассмотрим следующую диаграмму объектов в качестве примера:

../../_images/domain-model.svg

В примере:

Из схемы также видны отношения:

Опишем данную структуру на языке доменной модели:

[
    {
        "name": "Passport",
        "type": "record",
        "logicalType": "Entity",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "passport_series", "type": "string"},
            {"name": "passport_number", "type": "string"},
            {"name": "expired_flag", "type": "boolean"}
        ],
        "indexes": [
            "id",
            {
                "name": "passport",
                "parts": ["passport_series", "passport_number"]
            }
        ]
    },
    {
        "name": "Address",
        "type": "record",
        "logicalType": "ValueObject",
        "fields": [
            {"name": "country", "type": "string"},
            {"name": "city", "type": "string"},
            {"name": "street", "type": "string"},
            {"name": "building", "type": "int"}
        ]
    },
    {
        "name": "Client",
        "type": "record",
        "logicalType": "Aggregate",
        "doc": "Клиент",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "first_name", "type": "string"},
            {"name": "last_name", "type": "string"},
            {"name": "passports", "type": {"type": "array", "items": "Passport"}},
            {"name": "address", "type": "Address"}
        ],
        "indexes": ["id"],
        "relations": [
            {"name": "contracts", "to": "Contract", "count": "many",
             "from_fields": "id", "to_fields": "client_id"}
        ]
    },
    {
        "name": "Contract",
        "type": "record",
        "logicalType": "Aggregate",
        "doc": "Договор",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "client_id", "type": "long"},
            {"name": "header", "type": "string"},
            {"name": "body", "type": "string"},
            {"name": "date", "type": {"type": "string", "logicalType": "Date"}}
        ],
        "indexes": [
            "id",
            "client_id"
        ],
        "relations": [
            {"name": "accounts", "to": "Account", "count": "many",
             "from_fields": "id", "to_fields": "contract_id"}
        ]
    },
    {
        "name": "Account",
        "type": "record",
        "logicalType": "Aggregate",
        "doc": "Счет",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "contract_id", "type": "long"},
            {"name": "date", "type": {"type": "string", "logicalType": "Date"}}
        ],
        "indexes": [
            "id",
            "contract_id"
        ],
        "relations": [
            {"name": "operations", "to": "Operation", "count": "many",
             "from_fields": "id", "to_fields": "account_id"}
        ]
    },
    {
        "name": "Operation",
        "type": "record",
        "logicalType": "Aggregate",
        "doc": "Операция",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "account_id", "type": "long"},
            {"name": "amount", "type": "double"},
            {"name": "type", "type": "string"},
            {"name": "timestamp", "type": {"type": "string", "logicalType": "DateTime"}}
        ],
        "indexes": [
            "id",
            "account_id"
        ]
    }
]

Примечание

Если какое-то поле является опциональным, в доменной модели его тип описывают с помощью union — массива, содержащего основной тип для этого поля и тип null. Например:

{"name": "amount", "type": ["null","double"]}

При описании мы использовали расширения для TDG. Следующий раздел подробно описывает каждое расширение.

1.1.4. Расширения доменной модели для TDG

Расширения дополняют спецификацию Avro Schema и позволяют воспользоваться функциональностью приложения.

TDG понимает следующие расширения:

1.1.4.1. Расширение для агрегатов, сущностей и значений

Для указания признака агрегата, сущности или значения используется логический тип Avro Schema (Logical Type). Тип указывает приложению трактовать себя специальным образом.

В документации Avro Schema сказано, что логические типы можно использовать, например, для представления даты и времени. Наше приложение использует для оперирования датами и временем объекты DateTime, но на уровне сериализации и хранения они имеют строковый тип.

Поэтому даты, например, задаются так:

{ "type": "string", "logicalType": "Date"}

Стандарт Avro Schema не предписывает ничего по поводу допустимых значений logicalType, поэтому мы можем его использовать, чтобы придать типам дополнительный смысл.

TDG понимает следующие допустимые значения logicalType для типов модели:

  • Aggregate (агрегат);

  • Entity (сущность);

  • ValueObject (значение).

В коде модели мы задали типы всем классам объектов. Например, клиенту:

 {
     "name": "Client",
     "type": "record",
     "logicalType": "Aggregate",
     "fields": [...]
 }

Если logicalType не указан, по умолчанию подразумевается ValueObject.

1.1.4.2. Расширение для задания отношений между объектами

Явное задание отношений между объектами нужно для двух целей:

  • Валидация внешних ключей при вставке объектов;

  • Запрос связанных объектов через graphql.

Для задания связи используется поле relations в теле описания класса объекта. Это поле не является стандартным, но игнорируется существующими парсерами Avro Schema. Связь — логическая конструкция. Связываемые поля (внешние ключи в терминологии SQL) должны быть объявлены на уровне классов.

Например, для связи между клиентом (Client) и его контрактом (Contract) требуются следующие поля:

{
   "name": "Client",
   "type": "record",
   "logicalType": "Aggregate",
   "fields": [
       {"name": "id", "type": "long"},
       {"name": "first_name", "type": "string"},
       {"name": "last_name", "type": "string"},
       {"name": "passports", "type": {"type": "array", "items": "Passport"}},
       {"name": "address", "type": "Address"}
   ],
   "indexes": ["id"],
   // Здесь должно быть поле "relations", формат которого описан ниже.
},
{
   "name": "Contract",
   "type": "record",
   "logicalType": "Aggregate",
   "doc": "Договор",
   "fields": [
       {"name": "id", "type": "long"},
       {"name": "client_id", "type": "long"},
       {"name": "header", "type": "string"},
       {"name": "body", "type": "string"},
       {"name": "date", "type": {"type": "string", "logicalType": "Date"}}
   ],
   "indexes": [
       "id",
       "client_id"
   ],
}

Здесь:

  • Первичный ключ клиента доступен через обращение к его классу — User.id;

  • Внешний ключ находится в классе Contract и доступен аналогично — Contract.client_id.

Чтобы сделать связь явной, определим поле relations в следующем формате:

"relations": [
    {
        // Все параметры обязательные.
        "name": "<имя_отношения>",
        "to": "<класс_объекта>",
        "count": <"one"|"many">, // один к одному или один к многим
        "from_fields": <спецификация_первичного_ключа>,
        "to_fields": <спецификация_внешнего_ключа>
    },
    ...
]

где:

  • name — имя виртуального поля, через которое можно будет получить связанные объекты в graphql-запросах;

  • to — имя класса, с которым устанавливается связь;

  • count — вид связи: один к одному или один ко многим;

  • from_fields — спецификация поля, которое содержит первичный ключ;

  • to_fields — спецификация поля, которое содержит внешний ключ.

Спецификация обоих ключей (from_fields и to_fields) должна быть задана в следующем формате:

"index_name" | "field_name" | ["field_name", "field_name", "field_name", ...]

То есть в полях from_fields и to_fields можно указывать имя индекса, имя поля (если оно одно) или список имен полей (если их больше).

Поле relations можно указать как с одной стороны отношения, так и с обеих. Односторонние отношения имеют смысл тогда, когда запрашивать данные в «обратном направлении» не требуется.

Полный пример задания отношения один ко многим между Client и Contract с возможностью запроса данных в обоих направлениях:

[
    {
      "name": "Client",
      "type": "record",
      "logicalType": "Aggregate",
      "fields": [
          {"name": "id", "type": "long"},
          ...
      ],
      "indexes": ["id"],
      "relations": [
          {"name": "contracts", "to": "Contract", "count": "many",
           "from_fields": "id", "to_fields": "client_id"}
      ]
    },
    {
      "name": "Contract",
      "type": "record",
      "logicalType": "Aggregate",
      "fields": [
          {"name": "id", "type": "long"},
          {"name": "client_id", "type": "long"},
          ...
      ],
      "indexes": [
          "id",
          "client_id"
      ],
      "relations": [
          {"name": "client", "to": "Client", "count": "one",
           "from_fields": "client_id", "to_fields": "id"}
      ]
    },
]

1.1.4.3. Расширение для задания ключей (индексов)

Для задания ключей используется поле indexes в описании класса. Так же как и relations, indexes не является частью спецификации, но не меняет поведения, регулируемого стандартом, а добавляет дополнительные ограничения на хранение и запросы.

Ключи описываются в следующем формате:

[<index1>, <index2>, <index3>, ...]

Где каждый ключ может быть:

  • В виде строки:

    "<field_name>"
    

    где field_name — имя поля, по которому будет сделан ключ.

  • Либо в виде словаря (для составных ключей):

    {
      "name": "<index_name>",
      "parts": ["<field1_name>", "<field2_name>", ...]
      [, "collation"="binary"|"case_sensitivity"|"case_insensitivity"]
    }
    

    где:

    • index_name — имя составного ключа, которое не должно совпадать с именами существующих полей;

    • field<X>_name — имя одного из полей, по которому строится индекс;

    • collation — способ сравнения строк. По умолчанию способ binary — бинарный 'A' < 'B' < 'a'. Значение case_sensitivity включит регистрозависимое сравнение 'a' < 'A' < 'B'. Значение case_insensitivity включит регистронезависимое сравнение 'a' = 'A' < 'B' и 'a' = 'A' = 'á' = 'Á'.

Для указания первичности ключа нет отдельного явного признака. Первичным ключом признается первый ключ в списке.

Примечание

Нужно отметить исключения для так называемого мультиключевого индекса (multikey index), т.е. индекса по полю, содержащему массив:

  • мультиключевой индекс не может быть первичным;

  • мультиключевой индекс нельзя строить по полю, содержащему сложные типы, такие как DateTime, Date, Time, Decimal и др.

Запрос к данным по мультиключевому индексу также имеет специфику (см. подробнее).

Полный пример задания ключей:

{
    "name": "Passport",
    "type": "record",
    "logicalType": "Entity",
    "fields": [
        {"name": "id", "type": "long"},
        {"name": "passport_series", "type": "string"},
        {"name": "passport_number", "type": "string"},
        {"name": "expired_flag", "type": "boolean"}
    ],
    "indexes": [
        "id",
        {
            "name": "passport",
            "parts": ["passport_series", "passport_number"]
        }
    ]
}

Более сложный случай индексации — когда индекс делается по полю, присутствующему не в самом объекте, а в одном из его подобъектов. Такое возможно, если подобъект создается для логической группировки набора стандартных полей.

Например, представим, что операция по счету (Operation) в нашем примере производится по протоколу, требующему определенный заголовок. Создадим соответствующий объект-значение для него и сложный индекс в агрегате операции:

[
    {
        "name": "Header",
        "type": "record",
        "doc": "Заголовок операции",
        "logicalType": "ValueObject",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "header_body", "type": "string"}
        ]
    },
    {
        "name": "Operation",
        "type": "record",
        "logicalType": "Aggregate",
        "doc": "Операция",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "header", "type": "Header"},
            {"name": "account_id", "type": "long"},
            {"name": "amount", "type": "double"},
            {"name": "type", "type": "string"},
            {"name": "timestamp", "type": {"type": "string", "logicalType": "DateTime"}}
        ],
        "indexes": [
            "id",
            "account_id",
            {"name": "header_id", "parts": ["header.id"]}
        ]
    }
]

Header как объект-значение включается непосредственно в агрегат Operation, поэтому индекс может сослаться на поле из Header. Если бы Header был сущностью или агрегатом, модель не прошла бы валидацию.

1.1.4.4. Расширение для задания распределения объектов по хранилищам

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

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

"affinity": <index_name>[, "affinity": index_name, ...]

Директива может содержать только ключи, входящие в первичный ключ.

Например, для распределенного хранения операций по счетам укажем:

{
  "name": "Operation",
  "type": "record",
  "logicalType": "Aggregate",
  "doc": "Операция",
  "fields": [
      {"name": "id", "type": "long"},
      {"name": "account_id", "type": "long"},
      {"name": "amount", "type": "double"},
      {"name": "type", "type": "string"},
      {"name": "timestamp", "type": {"type": "string", "logicalType": "DateTime"}}
  ],
  "indexes": [
      {"name":"pkey", "parts": ["id", "account_id"]},
      "account_id",
  ],
  "affinity": "account_id"
}

Таким образом, операции одного и того же счета будут размещены физически на одном и том же хранилище.

1.1.4.5. Расширение атрибутов полей

Помимо стандартных атрибутов полей, определенных в спецификации Avro Schema, в TDG есть несколько дополнительных атрибутов:

  • default_function — используется для задания динамического значения по умолчанию (в отличие от стандартного атрибута default, задающего статическое значение). В качестве значения атрибута указывается функция, определенная в секции functions в файле конфигурации системы config.yml. При вставке в спейс новой записи будет вызываться указанная функция, и результат ее работы будет записан как значение для данного поля;

  • auto_increment — позволяет сделать поле автоинкрементным (auto-incremental). Может использоваться для задания числового идентификатора, который будет уникальным для сущностей данного типа, даже при шардировании базы данных. Атрибут является флагом; значение true включает автоинкремент.

    Важно

    • Поле с автоинкрементом обязательно должно иметь тип long;

    • Атрибут auto_increment несовместим с атрибутами default и default_function.

    Пример:

    {
      "name": "Contract",
      "type": "record",
      "logicalType": "Aggregate",
      "fields": [
          {"name": "id", "type": "long", "auto_increment": true},
          ...
      ],
      ...
    

1.1.5. Работа с датой и временем

Внутри TDG для представления даты/времени используется строковый формат ISO 8601. Этот формат позволяет делать поля даты/времени индексируемыми, и при этом имеющими правильный порядок сравнения.

Все даты, поступающие в приложение, должны быть приведены к UTC.

Допустимые форматы записи:

Например: 2018-03-24T10:20:48Z.

Чтобы объявить поле типа Date, Time или DateTime, используйте механизм логических типов (logicalType) Avro Schema. Базовый же тип для этих полей — всегда строковый. Пример объявления поля даты/времени:

{"name": "timestamp", "type": {"type": "string", "logicalType": "DateTime"}}

1.2. Безопасная среда исполнения

Пользовательский код в TDG исполняется отдельно от собственного кода TDG — в безопасной изолированной среде, называемой песочницей (или sandbox). При этом используется JIT-компилятор LuaJIT.

Для доступа к данным, хранящимся в TDG, используйте функции программного интерфейса репозитория. Все остальные функции и возможности, которые можно использовать при написании пользовательского кода обработки в песочнице, описаны в данном разделе.

Все функции можно разделить на следующие категории:

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

Важно

Подключать новые функции к безопасной среде исполнения категорически запрещено для сертифицированной версии TDG. Перед подключением новых функций в обычной версии TDG рекомендуется самостоятельно проверять их на уязвимости.

1.2.1. Стандартные модули и функции

Общедоступные Lua-модули и функции:

Модули Tarantool:

А также отдельные функции из модулей Tarantool:

Также доступны нестандартные функции собственной разработки, описание которых приведено далее.

1.2.2. Функции доступа к данным

Основные функции для доступа к данным в TDG входят в программный интерфейс репозитория. Кроме них, также доступны:

1.2.3. Функции управления обработкой

1.2.4. Функции преобразования данных

1.2.5. Функции логирования

1.2.6. Функции работы с датами и временем

1.2.7. Функции работы с последовательностями

Примечание

По умолчанию файберам или экземплярам выделяются диапазоны по 10 номеров. Пример использования: если на двух разных экземплярах вызвать 1 раз пайплайн, который заполняет поле объекта уникальным номером с помощью метода next, то номера у объектов будут 1 и 11 соответственно. Если вызвать еще по 9 раз пайплайны, то номера объектов будут 2-10 и 12-20 на соответствующих экземплярах. Дальше, если запустить пайплайн еще раз на первом экземпляре, то будет получен номер 21. Если мы продолжим вызывать пайплайн на одном из экземпляров, то номера будут идти по порядку (22, 23, …).

1.2.8. Подключение новых функций

Важно

Подключать новые функции к безопасной среде исполнения категорически запрещено для сертифицированной версии TDG. Перед подключением новых функций в обычной версии TDG рекомендуется самостоятельно проверять их на уязвимости.

Для подключения к безопасной среде исполнения (песочнице) новых функций необходимо выполнить следующие действия:

1.2.8.1. Создание модуля с подключаемыми функциями

Новые подключаемые функции необходимо разместить в специальном файле модуля. Данный файл должен иметь специальный формат, продемонстрированный в примере далее.

local exported_function = nil

local check_custom_function = os.getenv('CUSTOM_FUNCTION')
if check_custom_function ~= nil and check_custom_function ~= "" then
    local function custom_function()
        local magic_constant = 42
        return magic_constant
    end
    exported_function = custom_function
end

return {
    name = 'new_awesome_function',
    exports = exported_function
}

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

  • реализация произвольной логики проверок перед подключением новой функции;

  • задание логики функции непосредственно в файле модуля;

  • задание произвольного имени для вызова функции внутри песочницы (new_awesome_function).

Из файла должен возвращаться результат в виде имени и кода новой функции.

Имя новой функции, подключаемой к безопасной среде исполнения, указывается в виде строки name.

Код новой функции приводится в поле exports в одном из следующих форматов:

  • Ссылка на функцию, описанную в этом же файле (как в примере выше);

  • Ссылка на подключенный при помощи директивы require() модуль Tarantool.

Примечание

Код модуля с подключаемыми функциями выполняется за пределами песочницы. Поэтому в коде модуля нельзя воспользоваться функциями программного интерфейса репозитория и функциями, доступными из песочницы (описаны в данной главе выше).

1.2.8.2. Размещение файла модуля в файловой структуре

Возможны два варианта размещения файла модуля с подключаемыми функциями. Оба варианта равноценны с функциональной точки зрения.

Для того, чтобы новая функция была доступна в песочнице, необходимо разместить файл модуля подключаемой функции в специальной директории. Возможно, эту директорию потребуется создать, если она не существовала ранее. Также нужно проследить, чтобы у пользователей были необходимые права для чтения данной директории.

Файл размещается по адресу ../extensions/sandbox, где .. — это директория, в которой размещена директория с файлами TDG, обозначенная на следующей схеме как tdg.

.
├── tdg
├── extensions
    └── sandbox
        └── custom_function.lua    <-- файл модуля с подключаемыми функциями

Альтернативно, файл модуля можно поместить в архив .zip, посредством которого загружается конфигурация TDG. В архиве файл модуля необходимо разместить по такому же пути — ../extensions/sandbox.

1.2.8.3. Применение конфигурации

После создания файла модуля с новой функцией для безопасной среды исполнения и размещения данного файла в корректной директории, новая функция еще не будет доступна. Считывание файлов из данной директории выполняется на этапе применения конфигурации экземпляра.

Поэтому для добавления функции понадобится вызвать процесс применения конфигурации. Это можно сделать разными способами, например:

Примечание

При применении к кластеру TDG новой конфигурации она проходит валидацию.

Попытка применения той же самой конфигурации, что уже используется, закончится неудачей.

При этом, если конфигурация является валидной (корректной), то в ответ на запрос не будет выведено ошибок. Сообщение о том, что конфигурация совпадает с имеющейся и не будет применена, будет доступно только в системном журнале (на вкладке logger данное сообщение будет отсутствовать).

1.3. Программный интерфейс репозитория

Пользовательский код в TDG исполняется в изолированной среде — так называемой «песочнице» (sandbox). При этом для доступа к данным должны использоваться функции программного интерфейса репозитория (repository API).

Все запросы к данным в TDG от внешних информационных систем, включая GraphQL-запросы (а также запросы, выполняемые при помощи вкладки GraphQL), также реализованы на основе функций программного интерфейса репозитория.

Основные функции программного интерфейса репозитория включают в себя выборки разной сложности, изменение и обработку данных, а также добавление отложенных работ:

Синтаксис функций:

repository.find(type_name, filter, options, context)

repository.get(type_name, index_name, value, options, context)

repository.put(type_name, object, options, context)

repository.update(type_name, filter, updaters, options, context)

repository.delete(type_name, filter, options, context)

repository.call_on_storage(type_name, index_name, value, func_name, func_args, options, context)

repository.push_job(name, arguments, options, context)

repository.map_reduce(type_name, filter, version, map_fn, combine_fn, reduce_fn, opts)

Функции get, find, update, delete и map-reduce поддерживают порядковую нумерацию страниц (пагинацию) с помощью параметров first и after.

Чтобы фильтровать объекты, запросы используют условия-предикаты (filter) — булевы выражения, синтаксис которых описан ниже.

1.3.1. Синтаксис предикатов

В запросах предикаты (filter) записываются в виде:

{{left, comparator, right}, ...}

где:

Если в предикате несколько условий, по умолчанию они объединяются логической операцией and (конъюнкцией).

Примеры предикатов:

{{"$id", ">", 10}}
{{"$id", ">", 10}, {"$id", "<", 100}}
{{"$name", "==", "foo"}, {"$birth_year", "==", 1990}}
{{"$name", "==", "foo"}, {"$reg_date", "==", {1990, 04, 23}}}

1.3.2. Общее хранилище

Для передачи объектов между функциями и экземплярами TDG используйте общее хранилище (shared storage). При помощи следующей команды подключите существующее или создайте новое (если хранилище с таким именем ещё не существует) общее хранилище:

local shared_storage_object = shared_storage.new('some_namespace')

Переменная shared_storage_object в данном примере содержит указатель на созданное общее хранилище.

Примечание

При создании общего хранилища создаётся спейс, который хранится на одном из наборов реплик с ролью storage. Однако персистентность данных в общем хранилище не гарантируется — данные из него могут быть потеряны, например, при перезапуске кластера.

Данные в общее хранилище помещаются в формате key, value, например, следующей командой:

shared_storage_object:set('abc', 123)

где 'abc' — это ключ (key), а 123 — значение (value).

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

shared_storage_object:get('abc')

1.3.3. Исторические данные

Запросы позволяют получить или обработать объекты, которые предшествуют или равны определённой версии. За это отвечает параметр version в options.

Примечание

Пример: Допустим, существуют версии 1, 3 и 5 объекта, а мы запросили версию 4. В таком случае, мы получим версию либо равную запрошенной, либо ближайшую предшествующую, в данном случае версию 3.

При получении данных параметр version определяет версию получаемого объекта. Если параметр version не задан, то будет получена последняя версия объекта.

При обновлении данных параметр version определяет изменяемую версию объекта. Если задано значение параметра version, то запрос получит указанную версию объекта (или ближайшую предшествующую, см. пример выше), выполнит обновление и сохранит результат с той же версией. Если параметр version не задан, то запрос получит последнюю версию объекта, обновит её и сохранит с новой версией, значение которой будет взято по умолчанию (большое целое монотонно возрастающее число).

При вставке (добавлении или замене) объекта параметр version определяет версию объекта, который будет добавлен или заменён. Если параметр version не задан, то используется значение по умолчанию (см. выше).

При удалении данных параметр version определяет удаляемую версию объекта. Если параметр version не задан, то будет удалена последняя версия объекта.

Для запросов на выборку или удаление объектов (find или delete), при установленном флаге all_versions (значение true) обработка выполняется для всех версий объекта. Если задан параметр version, то обрабатываются все версии меньше или равные заданной.

1.3.4. Оптимистичные блокировки

В случае конкурентной модификации объекта, когда изменения в один объект могут вноситься параллельно из разных обработчиков, что может вызывать конфликты, необходимо использовать механизм оптимистичных блокировок, основанный на версиях объектов. Для этого в options запроса задайте значение параметра only_if_version, и запрос выполнится только в случае, если данная версия объекта является последней и совпадает с заданной в запросе.

Пример:

repository.put("users", {id = "100500", name = "Kirito777"}, {version = 6, only_if_version = 5})

Этот запрос попытается выполнить поиск по первичному ключу (в данном случае — id). Если запись с таким значением первичного ключа будет найдена, то она будет обновлена только в том случае, если версия объекта в системе на момент исполнения совпадёт со значением, переданным в параметре only_if_version (в данном примере это 5).

После успешного исполнения запроса последняя версия объекта станет равна 6. Если запись с переданным значением первичного ключа отсутствует, то новая запись добавлена не будет, так как версия несуществующей записи не может быть равна 5.

При вставке новых объектов можно использовать параметр if_not_exists, который также задается в options запроса. Параметр имеет тип boolean (значения true или false). Может использоваться только с функцией repository.put().

Если задано значение true, система проверит, существует ли уже такой объект, и только при условии его отсутствия новый объект будет добавлен в хранилище. Если параметр не задан, это равносильно значению false.

Пример:

repository.put("users", {id = "100500", name = "Kirito777"}, if_not_exists = true)

Примечание

Параметры only_if_version и if_not_exists взаимоисключающие и не могут использоваться вместе в одном запросе. В этом случае система выдаст ошибку запроса.

1.3.5. Функции программного интерфейса репозитория

1.3.5.1. Выборка по полям объектов одного типа (find)

Синтаксис

repository.find(type_name, filter, options, context)

где:

  • type_name — тип объекта;

  • filter — список условий-предикатов для выбора (фильтрации) объектов указанного типа;

  • options — параметры для управления запросом:

    • first — количество элементов;

    • after — курсор пагинации на первый элемент;

    • version — версия объекта;

    • all_versions — указатель для поиска по всем версиям объекта, если задано значение true;

    • mode — определяет целевой экземпляр для выполнения запроса. Возможные значения: read и write. Если задано write, целью будет мастер;

    • prefer_replica — определяет целевой экземпляр для выполнения запроса. Возможные значения: true и false. Если задано true, то предпочитаемая цель — одна из реплик. Если доступной реплики нет, то целью будет мастер. Опция полезна для ресурсозатратных функций, чтобы избежать замедления работы мастера;

    • balance — управление балансировкой нагрузки. Возможные значения: true и false. Если задано true, добавится балансировка нагрузки — запросы на чтение распределяются по всем узлам набора реплик по кругу. Если при этом параметр prefer_replica определен как true, предпочтение отдается репликам;

  • context — контекст выполнения запроса:

    • tenant — тенант.

Пример

repository.find(
  "Client",
  {{"$id", "==", 42}}
)

1.3.5.2. Выборка по индексу (get)

Синтаксис

repository.get(type_name, index_name, value, options, context)

где:

  • type_name — тип объекта;

  • index_name — имя индекса;

  • value — значение ключа поиска;

  • options — параметры для управления запросом:

    • first — количество элементов;

    • after — курсор пагинации на первый элемент;

    • version — версия объекта;

    • all_versions — указатель для поиска по всем версиям объекта, если задано значение true;

    • mode — определяет целевой экземпляр для выполнения запроса. Возможные значения: read и write. Если задано write, целью будет мастер;

    • prefer_replica — определяет целевой экземпляр для выполнения запроса. Возможные значения: true и false. Если задано true, то предпочитаемая цель — одна из реплик. Если доступной реплики нет, то целью будет мастер. Опция полезна для ресурсозатратных функций, чтобы избежать замедления работы мастера;

    • balance — управление балансировкой нагрузки. Возможные значения: true и false. Если задано true, добавится балансировка нагрузки — запросы на чтение распределяются по всем узлам набора реплик по кругу. Если при этом параметр prefer_replica определен как true, предпочтение отдается репликам;

  • context — контекст выполнения запроса:

    • tenant — тенант.

Пример

repository.get("Client", "id", 42)

1.3.5.3. Запрос на добавление данных (put)

Запрос put позволяет вставить новые данные или заменить существующие. Он поддерживает версионирование и оптимистичные блокировки.

Если отсутствует параметр version, то используется значение по умолчанию (большое целое монотонно возрастающее число).

При заданном параметре version запрос выполняет добавление или замену объекта с заданной версией (обычно используется целое число).

При указанном параметре only_if_version запрос добавляет или заменяет объект только в том случае, если последняя версия объекта совпадает с указанной.

Синтаксис

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

repository.put(type_name, object, options, context)

где:

  • type_name — тип объекта;

  • object — объект для вставки;

  • options — параметры для управления запросом:

    • version — версия объекта;

    • only_if_version — проверка имеющейся версии перед вставкой;

  • context — контекст выполнения запроса:

    • tenant — тенант.

Пример

repository.put("users", {id = "100500", name = "Kirito777"})

Данный запрос из примера добавит новый объект с первичным ключом id, равным 100500, если таковой ещё не существует. При этом значение параметра version будет равным значению по умолчанию (большое целое монотонно возрастающее число). Если объект с таким первичным ключом уже есть, то будет добавлена новая версия объекта со значением параметра version, равным значению по умолчанию.

1.3.5.4. Запрос на обновление данных (update)

Запрос на обновление данных (update) поддерживает версионирование и выполняется в две стадии:

  • исполнение запроса на каждом хранилище, которое может содержать объекты по условию, передаваемому аргументом filter;

  • сбор результатов на роутере.

Синтаксис

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

repository.update(type_name, filter, updaters, options, context)

где:

  • type_name — тип объекта;

  • filter — список условий-предикатов для выбора (фильтрации) объектов указанного типа;

  • updaters — список обновлений для объекта, состоящий из списка мутаторов {{mutator, path, new_value}, ...}, где:

    • mutator — имя мутатора, например:

      • set — устанавливает значение;

      • add — увеличивает значение на указанное число;

      • sub — уменьшает значение на указанное число;

    • path — строковый путь до поля объекта с точкой-разделителем (.).

      Путь до объекта(ов) массива должен включать индекс массива или символ * для захвата всех подобъектов;

    • new_value` — новое значение;

  • options — параметры для управления запросом:

    • first — количество элементов для обновления;

    • after — курсор пагинации на первый элемент;

    • version — версия объекта;

    • only_if_version — проверка имеющейся версии перед вставкой;

    • dont_skip_deleted — использовать в поиске удаленные версии объектов;

  • context — контекст выполнения запроса:

    • tenant — тенант.

Примеры

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

  • Чтобы обновить имя клиента с идентификатором 42, используйте следующий запрос:

    repository.update(
     "Client",
     {{"$id", "==", 42}},
     {{"set", "first_name", "John"},
      {"set", "last_name", "Doe"}})
    
  • Если у того же клиента истек срок действия первого паспорта и необходимо обновить соответствующее поле expired_flag, используйте следующий запрос:

    repository.update(
     "Client",
     {{"$id", "==", 42}},
     {{"set", "passports.1.expired_flag", "true"}}
    

    где .1. — индекс массива, содержащего экземпляры сущности Passport агрегата Client, т.е. первый паспорт клиента.

1.3.5.5. Запрос на удаление объектов (delete)

Чтобы прозрачно и удобно исключить объект из потенциальных результатов запросов, используйте запрос на удаление (delete). Он помещает объект или его версию в «удаленное состояние» (добавляя флаг delete:true), что исключает его из выборки.

Запрос на удаление поддерживает версионирование и оптимистичные блокировки.

Синтаксис

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

repository.delete(type_name, filter, options, context)

где:

  • type_name — имя типа объекта для удаления;

  • filter — список условий-предикатов для выбора (фильтрации) объектов указанного типа;

  • options — параметры для управления запросом:

    • first — количество элементов для удаления;

    • after — курсор пагинации на первый элемент;

    • version — версия объекта для копирования в удаленное состояние;

    • only_if_version — проверка имеющейся версии перед вставкой;

    • all-versions — этот флаг для функции удаления (delete) нельзя использовать без флага permanent_delete;

    • permanent_delete — при установленном флаге (значение True) происходит физическое удаление информации об объекте из TDG. Используется вместе с флагом all-versions;

  • context — контекст выполнения запроса:

    • tenant — тенант.

Пример

Чтобы удалить клиентов с именем «QWERTY» для модели из примера, используйте следующий запрос:

repository.delete(
 "Client",
 {{"$first_name", "==", "QWERTY"}})

В результате такого запроса все объекты, удовлетворяющие условию (first name равное QWERTY), будут дополнены новой версией (значение версии по умолчанию) с флагом delete:true.

1.3.5.6. Вызов функции на экземпляре с ролью storage (call_on_storage)

Синтаксис

repository.call_on_storage(type_name, index_name, value, func_name, func_args, options, context)

где:

  • type_name — тип объекта;

  • index_name — имя индекса;

  • value — значение ключа поиска;

  • func_name — имя вызываемой функции;

  • func_args — аргументы, которые передаются в вызываемую функцию;

  • options — параметры для управления запросом:

    • timeout — время ожидания выполнения запроса, секунды. Значение не должно быть больше, чем значение параметра конфигурации vshard_timeout;

    • mode — определяет целевой экземпляр для выполнения запроса. Возможные значения: read и write. Если задано write, целью будет мастер;

    • prefer_replica — определяет целевой экземпляр для выполнения запроса. Возможные значения: true и false. Если задано true, то предпочитаемая цель — одна из реплик. Если доступной реплики нет, то целью будет мастер. Опция полезна для ресурсозатратных функций, чтобы избежать замедления работы мастера;

    • balance — управление балансировкой нагрузки. Возможные значения: true и false. Если задано true, добавится балансировка нагрузки — запросы на чтение распределяются по всем узлам набора реплик по кругу. Если при этом параметр prefer_replica определен как true, предпочтение отдается репликам;

  • context — контекст выполнения запроса:

    • tenant — тенант.

1.3.5.7. Асинхронный запуск задач/функций (push_job)

Синтаксис

repository.push_job(name, arguments, options, context)

где:

  • name — имя функции/пайплайна, определенное в файле конфигурации;

  • arguments — аргументы функции;

  • options — параметры для управления запросом (не используется);

  • context — контекст выполнения запроса (не используется).

1.4. Запрос на сложную обработку кластером

Если требуется выполнить обработку всех данных в кластере, то её необходимо выполнять на всех экземплярах типа storage. Для этого можно использовать функцию map_reduce.

Сложная кластерная обработка по модели MapReduce в TDG состоит из трех этапов:

1.4.1. Синтаксис запроса

Функция map_reduce(type_name, filter, version, map_fn, combine_fn, reduce_fn, opts) имеет следующие аргументы:

1.4.2. Этап Map

Сначала на каждом экземпляре c ролью storage будет вызвана функция map_fn, столько раз, сколько на этом экземпляре будет найдено подходящих объектов, соответствующих типу type_name и условиям filter.

Функция map_fn применяется к каждому найденному кортежу.

local map_res, err = map_fn(tuple, opts.map_args)

Эта функция может вернуть любые данные или nil.

Если функция вернет данные, то на следующем этапе эти данные будут использованы для запуска combine_fn. combine_fn будет вызвана столько раз, сколько раз вызовы map вернут данные.

1.4.3. Этап Combine

Эта стадия опциональна и нужна для того, чтобы по возможности уменьшить количество данных, полученных на стадии Map, перед их передачей по сети и дальнейшей обработкой.

Результат каждого вызова map_fn передаётся в combine_fn. Каждый вызов combine_fn осуществляется с передачей исходного состояния, равного результату предыдущего вызова combine_fn. Для первого вызова исходное состояние равно opts.combine_initial_state, либо равно пустой таблице, если этот параметр не задан.

local combine_res = opts.combine_initial_state or {}
local combine_res, err = combine_fn(combine_res, map_res, opts.combine_args)

Функция combine_fn также выполняется на роли storage.

Результат выполнения combine_fn аккумулируется в переменной combine_res и передается на ту роль, откуда был вызван map_reduce — в функцию reduce_fn.

1.4.4. Этап Reduce

Данный этап предназначен для завершения обработки данных со всего кластера.

Данные передаются по сети на экземпляр, откуда была вызвана функция map_reduce. Там будет вызвана функция reduce_fn. Эта функция будет вызвана столько раз, сколько экземпляров типа storage в кластере найдет подходящие объекты и, соответственно, вернет результат в combine_res.

local reduce_res, err = reduce_fn(combine_res, opts.reduce_initial_state, opts.reduce_args)

Результат reduce_fn возвращается как результат всего map_reduce.

1.5. Представление модели

При эксплуатации TDG объекты могут поступить в систему постфактум, а запросы к системе могут быть сделаны по функциональному срезу для определенной бизнес-даты.

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

Чтобы поддерживать историчность и эволюцию модели, TDG представляет ее в едином формате — Lua-структуре, состоящей из примитивных типов. Ее легко преобразовать в JSON и обратно для передачи по сети.

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

1.5.1. Внутренний формат конфигурации

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

{
    "functions": {
        "function_name": "function_code"
        ...
    },
    "pipelines": {
        "pipeline_name": ["function1_name", "function2_name", ...],
        ...
    },
    "classifiers": {
        "classifier_name": "pipeline_name/function_name",
        ...
    },
    "routing": {
        "routing_key": "pipeline_name/function_name",
        ...
    },
    "storage": {
        "routing_key": "type_name"
    },
    "schema": <avro_schema>
}

где:

Также в формате присутствует поле schema, формат которого описан в разделе о доменной модели. В этом поле хранится структурное (а не строковое) представление доменной модели.

1.5.2. Внешний (экспортный) формат

Экспортный формат используется для загрузки начальной модели при первичном старте системы, а также для загрузки конфигурации в тестах.

Экспортный формат соответствует внутреннему, за исключением следующих полей:

Корневой объект сохраняется в файле config.yml, код функций — рядом, в соответствующих файлах с расширением .lua, а схема — в файле schema.avsc.

1.5.3. Экспортный формат бандла моделей

Экспортный формат бандла (комплекта) может использоваться для удобной передачи разработчикам модели, загруженной в систему. Бандл — папка, содержащая в себе набор моделей, каждая из которых находится в своей подпапке. Подпапки названы по бизнес-времени действия модели (а не по фактическому времени добавления).

Например:

bundle/
├── 2018-01-03T18:56:00Z
|   ├── config.yml
|   ├── schema.avsc
|   ├── function_1.lua
|   └── function_2.lua
└── 2018-03-05T00:41:00Z
    ├── config.yml
    ├── schema.avsc
    └── function_3.lua

Такой экспортный формат содержит только конфигурацию модели, но не содержит конфигурацию топологии системы или связи с внешними системами.

1.6. Разработка тестов

Тестирование приложений для системы TDG преследует две основные цели:

Юнит-тесты обычно синтетические и предназначены для исчерпывающего покрытия критических частей кода и последующей автоматической проверки на регрессии. Самая большая польза от юнит-тестов — выявление ситуаций, в которых модуль может получить разнообразный неверный «ввод» от пользователя. В таких случаях юнит-тесты помогают убедиться, что модуль реагирует на неверный ввод корректно. Если система приняла неверные по форме/содержанию данные или, наоборот, не приняла верные данные (посчитав их неверными), то юнит-тесты — идеальное средство проверки подобных сценариев.

Интеграционные тесты предназначены для проверки функциональности сложных элементов и для проверки на соответствие требованиям заказчика. Если поступает новое требование в формате пользовательской истории, то оно обязательно должно быть проверено интеграционным тестом, в котором должна быть сделана ссылка на требование.

Прежде чем разрабатывать собственные тесты, ознакомьтесь с существующими и запустите их.

1.6.1. Запуск тестов

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

  1. Установите все зависимости при помощи скрипта:

    ./deps.sh
    

    Он установит в папку .rocks все модули, нужные для запуска.

  2. Запустите юнит-тесты:

    tarantool unit.lua
    

    Команда выполнит по очереди все юнит-тесты из папки test/unit.

Чтобы запустить существующие интеграционные тесты:

  1. Установите python3, pip и несколько python-библиотек. Весь список зависимостей приведен в файле requirements.txt в корне проекта. Чтобы установить их все глобально, используйте pip. Например:

    sudo pip3 install -r requirements.txt
    

    Примечание

    Как альтернативу можно настроить pipenv и сделать для прогона тестов отдельную среду.

  2. Запустите интеграционные тесты:

    pytest
    

1.6.2. Разработка юнит-тестов

Юнит-тесты сгруппированы по подсистемам в подпапках test/unit. Чтобы тест был включен в общий прогон, имя файла должно начинаться с test_ и иметь расширение .lua, например, test_ddl.lua. Команда tarantool unit.lua найдет в упомянутой папке файлы с такими именами и автоматически исполнит их.

Юнит-тесты используют модуль Tarantool tap. Чтобы написать новый тест, используйте следующий код:

#!/usr/bin/env tarantool

local tap = require('tap')
local test = tap.test("validation")
test:plan(5) --- замените цифру на количество тестов в модуле

--- здесь будут тесты

 os.exit(test:check() and 0 or 1)

Чтобы написать сами тесты, достаточно вызывать у объекта test функции проверки:

test:isnil()
test:isstring()
test:isnumber()
test:istable()
test:isboolean()
test:isudata()
test:iscdata()

Если в эти функции будут переданы данные, не соответствующие ожидаемым, тест будет прерван с ошибкой и поясняющим сообщением.

Примечание

Чтобы быстро понять, как писать юнит-тесты, лучше всего посмотреть в реализацию существующих.

Если в тестах требуется использовать box-функции, используйте следующий код:

local tarantool = require('test.unit.tarantool').new()

tarantool:start()

--- здесь будут тесты

local success = test:check()

tarantool:stop()

os.exit(success and 0 or 1)

1.6.3. Разработка интеграционных тестов

Интеграционные тесты основаны на pytest и «заточены» под тестирование логики приложения с возможным подключением логики кластера.

Для запуска каждого файла с тестами:

  1. Сначала поднимается «с нуля» TDG или кластер из узлов с разными ролями.

  2. Затем ко всем возможным узлам применяется соответствующая конфигурация.

  3. Наконец, по очереди запускаются тест-кейсы.

Интеграционные тесты находятся в подпапках test/integration. В отличие от юнит-тестов, они сгруппированы не по подсистеме, а по логической «близости» тестов друг к другу. Основной критерий группировки — тесты в одной подпапке имеют одну и ту же стартовую конфигурацию.

Чтобы создать новую группу тестов:

  1. Добавьте папку в test/integration и в ней сделайте подпапки config и data.

  2. В config поместите все конфигурационные файлы для TDG и connector. При исполнении этой группы тестов, такие файлы будут автоматически загружены в качестве начальной конфигурации.

  3. Дополнительно к папке config можно создать рядом папку data и положить туда тестовые данные, например, большие XML или JSON-объекты. Это поможет не прописывать данные в коде теста в явном виде.

  4. Создайте файл с именем, начинающимся с test_ и расширением .py. Такие файлы автоматически включаются в прогон.

  5. В файле используйте следующий код:

    #!/usr/bin/env python3
    
    import pytest
    import os
    
    def test_something(server, datadir):
        # тут можно писать логику теста
        assert something == something_else
    
    # тут можно добавить еще тестов
    

Здесь функция-тест test_something имеет параметры server и datadir. Эти параметры называются «фикстуры», и они должны быть у каждой функции-теста. Фикстуры — это способ удобно использовать в тестах библиотечную функциональность. О них можно прочитать в документации по pytest.

При указании в параметрах datadir, можно получить полный путь к папке, в которой лежат тестовые данные текущей группы тестов.

Когда pytest видит в параметрах тестовой функции server:

  1. Он автоматически стартует TDG.

  2. Применяет к нему конфигурацию.

  3. Передает объект-обертку («враппер»), позволяющую удобно делать запросы (HTTP, SOAP, GraphQL и другие) к TDG.

1.6.3.1. API объекта-обертки

Объект-обертка сервера («враппер») поддерживает запросы через HTTP, SOAP и GraphQL:

  • server.post(path, data, json) — посылает post-запрос по пути path. Можно указать либо строку data для текстовых запросов, либо json для JSON-запросов;

  • server.soap(data) — послает SOAP-запрос, где data — текст запроса;

  • server.graphql(query) — послает GraphQL-запрос, где query — текст запроса. В ответ функция либо бросает исключение при ошибке, либо возвращает объект с результатом. graphql для TDG разделён на схемы. Для доступа к данным schema = 'default' или не указывается. Для доступа к функциям администрирования schema = 'admin'. Например, запрос данных:

    server.graphql("""
      query {
        User(country:"USA") {
          fullname
        }
      }
    """)
    

    Пример вызова администрирования TDG, изменение модели:

     obj = server.post('/graphql', json={
        "query": "mutation set_model($model:String!) { model(model: $model) }",
        "variables": {
            "model": json.dumps(model)
        },
        "schema": "admin"
    })
    
  • server.cluster_graphql(query) — посылает GraphQL-запрос для управления кластером. Например,

    obj = server.cluster_graphql("""
       {
           servers {
               uri
               replicaset { roles }
           }
       }
    """)
    

2. Руководство по эксплуатации

Данное руководство описывает работу с системой Tarantool Data Grid (TDG). с точки зрения администратора.

Информация в руководстве сгруппирована по основным задачам, которые выполняет администратор:

Задачи по администрированию могут выполняться с помощью различных средств (что также указано в соответствующих разделах руководства):

Содержание

2.1. Установка TDG

В этом разделе рассмотрена процедура установки TDG версии 1.5.0 или выше.

Программный комплекс TDG поддерживает установку на операционные системы Red Hat Enterprise Linux и CentOS версий 7.5 и выше.

Примечание

TDG может быть запущен на других дистрибутивах Linux, основанных на systemd, но не тестируется на них и может не соответствовать заявленной функциональности.

TDG разработан на основе фреймворка Tarantool Cartridge, в котором предусмотрена упаковка создаваемых приложений в дистрибутивы разных форматов, и, соответственно, различные процедуры установки из этих дистрибутивов.

В данном руководстве приводится один из вариантов установки TDG — из дистрибутива в формате архива tar.gz. Установка выполняется при помощи скрипта tdgctl.py с локальной машины на удаленные серверы.

Рассмотрим далее:

2.1.1. Подготовка к установке

2.1.1.1. Дистрибутив установки

Для установки вам понадобится дистрибутив TDG в формате архива tar.gz.

Запросить доступ к дистрибутивам TDG вы можете, обратившись через форму обратной связи на сайте Tarantool в разделе Tarantool Data Grid или по адресу электронной почты sales@tarantool.io.

Для упрощения процедур тестового развертывания в составе дистрибутива находится директория /deploy, содержащая:

  • скрипт для развертывания и управления кластером tdgctl.py;

  • примеры конфигураций кластера;

  • файл README.md с краткими инструкциями по установке;

  • файл Vagrantfile для автоматизации создания тестового окружения для развертывания кластера;

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

2.1.1.2. Предварительная настройка сервера

Основные требования к серверу, на котором будет производиться установка TDG (если установка выполняется распределенно на несколько серверов, требования ниже относятся к каждому из них):

  • Пользователь операционной системы сервера, от имени которого будет происходить установка, должен иметь привилегии суперпользователя. Также в файле /etc/sudoers на сервере нужно отключить для этого пользователя запрос пароля:

    <server_user_name> ALL=(ALL:ALL) NOPASSWD: ALL
    
  • На стороне сервера должен быть включен SSH-сервер, который слушает запросы клиентских соединений на стандартном порте 22;

  • На сервер должен быть загружен публичный SSH-ключ пользователя локальной машины, из-под которого будет запускаться на локальной машине скрипт tdgctl.py;

  • На локальной машине, откуда будет запускаться tdgctl.py, для работы скрипта требуется наличие Python 3 и библиотек fabric и requests. Проверить наличие библиотек можно командой:

    pip3 freeze
    

    Если библиотеки отсутствуют, установите их:

    pip3 install fabric requests
    

2.1.1.3. Подготовка конфигурации кластера

Для установки TDG на серверы также потребуется подготовить файл конфигурации кластера в формате JSON.

Рассмотрим структуру и параметры файла на примере:

{
    "general":
    {
        "cluster_cookie": "ilikerandompasswords"
    },
    "servers":
    [
        {
            "address": "172.19.0.2",
            "username": "vagrant",
            "instances":
            [
                {
                    "name": "core_1",
                    "binary_port": 3000,
                    "http_port": 8080,
                    "memory_mb": 128,
                    "env": {"CUSTOM_ENV": "some_value"}
                },
                {
                    "name": "runner",
                    "binary_port": 3001,
                    "http_port": 8081,
                    "memory_mb": 128
                },
                {
                    "name": "storage_1",
                    "binary_port": 3002,
                    "http_port": 8082,
                    "memory_mb": 1024
                },
                {
                    "name": "storage_2",
                    "binary_port": 3003,
                    "http_port": 8083,
                    "memory_mb": 1024
                }
            ]
        },
        {
            "address": "172.19.0.3",
            "username": "vagrant",
            "instances":
            [
                {
                    "name": "core_2",
                    "binary_port": 3004,
                    "http_port": 8084,
                    "memory_mb": 128
                },
                {
                    "name": "storage_1_replica",
                    "binary_port": 3005,
                    "http_port": 8085,
                    "memory_mb": 1024
                },
                {
                    "name": "storage_2_replica",
                    "binary_port": 3006,
                    "http_port": 8086,
                    "memory_mb": 1024
                }
            ]
        }
    ]
}

Параметры конфигурации:

general — параметры, относящиеся ко всем экземплярам (инстансам, instances):

servers — список (массив) серверов, на которые будет происходить установка. Для каждого сервера задается:

  • username — имя пользователя ОС, из-под которого будет происходить установка;

  • address — адрес сервера;

  • instances — список (массив) устанавливаемых экземпляров. Для каждого экземпляра задается:

    • name — имя экземпляра. При установке на сервера Linux это будет имя юнита systemd;

    • binary_port — порт, который должен быть открыт на сервере для взаимодействия экземпляров по бинарному протоколу Tarantool. Требует протоколы TCP и UDP;

    • http_port — порт, который должен быть открыт на сервере для доступа к экземпляру по HTTP. Требует протокола TCP;

    • memory_mb — ограничение потребления памяти Tarantool внутри экземпляра, мегабайты;

    • env — (опционально) переменные окружения, которые будут доступны для данного экземпляра и могут быть использованы в пользовательском коде.

2.1.2. Установка

Для установки системы используется скрипт tdgctl.py. Скрипт находится в дистрибутиве установки в директории /deploy.

При запуске скрипта нужно указать команду deploy и передать аргументами путь к файлу с конфигурацией кластера и файлу дистрибутива установки:

./tdgctl.py -c deploy.json deploy tdg-<version>.tar.gz

где

Подробнее о скрипте tdgctl.py и формате его команд см. здесь.

Cкрипт подключается к серверам, указанным в конфигурации, загружает на них дистрибутив, распаковывает исполняемые файлы TDG, создает systemd-юниты вида <instance_name>.service для каждого экземпляра, указанного в конфигурации кластера, и запускает созданные сервисы. Запуск сервисов производится от имени системного пользователя nobody.

Успешность установки можно определить по логу работы скрипта в консоли. Пример лога успешной установки (в соответствии с конфигурацией кластера из примера выше):

$ ./tdgctl.py -c deploy.json deploy tdg-1.6.5-10-g9fc081e.tar.gz

Deploying package...
Uploading package...
[####################] 100%
[                    ] 0% Created symlink from /etc/systemd/system/core_1 to /etc/systemd/system/core_1.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/core_1.service to /etc/systemd/system/core_1.service.
[##                  ] 14% Created symlink from /etc/systemd/system/runner to /etc/systemd/system/runner.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/runner.service to /etc/systemd/system/runner.service.
[#####               ] 28% Created symlink from /etc/systemd/system/storage_1 to /etc/systemd/system/storage_1.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/storage_1.service to /etc/systemd/system/storage_1.service.
[########            ] 42% Created symlink from /etc/systemd/system/storage_2 to /etc/systemd/system/storage_2.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/storage_2.service to /etc/systemd/system/storage_2.service.
[###########         ] 57% Created symlink from /etc/systemd/system/core_2 to /etc/systemd/system/core_2.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/core_2.service to /etc/systemd/system/core_2.service.
[##############      ] 71% Created symlink from /etc/systemd/system/storage_1_replica to /etc/systemd/system/storage_1_replica.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/storage_1_replica.service to /etc/systemd/system/storage_1_replica.service.
[#################   ] 85% Created symlink from /etc/systemd/system/storage_2_replica to /etc/systemd/system/storage_2_replica.service.
Created symlink from /etc/systemd/system/multi-user.target.wants/storage_2_replica.service to /etc/systemd/system/storage_2_replica.service.
[####################] 100%


7 instances created
172.19.0.2   core_1
172.19.0.2   runner
172.19.0.2   storage_1
172.19.0.2   storage_2
172.19.0.3   core_2
172.19.0.3   storage_1_replica
172.19.0.3   storage_2_replica
0 instances updated
0 instances kept

Done!

Далее необходимо подключиться к web-интерфейсу системы, убедиться, что все экземпляры запущены, и перейти к следующему этапу — настройке кластера и запуску системы в работу.

2.1.2.1. Директории по умолчанию

В процессе установки TDG на сервере создаются по умолчанию следующие директории:

  • /var/lib/tarantool/<instance_name> — рабочая директория ({workdir}) каждого из экземпляров, в которой хранятся его данные и конфигурация:

    • файлы снимков данных .snap и WAL-файлы .xlog;

    • поддиректории /config и /config.backup, в которых хранятся файлы конфигурации экземпляра и их резервные копии соответственно;

    • файл .tarantool.cookie, содержащий токен кластера;

  • /usr/share/tarantool/<instance_name> — директория, в которой хранятся исполняемые файлы TDG. Количество таких директорий соответствует количеству развернутых экземпляров.

<instance_name> — имя экземпляра, определенное в файле конфигурации кластера.

2.2. Web-интерфейс

Web-интерфейс TDG предоставляет возможности для настройки и администрирования системы.

2.2.1. Авторизация

Для подключения к web-интерфейсу надо зайти в браузере на любой сервер по доступному на нем http-порту http://<address>:<http_port> (указаны в файле конфигурации кластера). В рассматриваемом в конфигурации примере это может быть http://172.19.0.2:8080.

При первом подключении к web-интерфейсу после развертывания системы разрешен неавторизованный анонимный доступ. После включения режима обязательной аутентификации при подключении к web-интерфейсу пользователь будет попадать на страницу авторизации (к этому моменту должны быть созданы профили пользователей).

../../_images/ui_login.png

В форме авторизации необходимо ввести идентификатор пользователя (Login) и пароль (Password) и нажать Login. Идентификатор пользователя автоматически генерируется при создании профиля пользователя (параметр LOGIN).

При успешной авторизации пользователь попадает на основную страницу web-интерфейса. Имя пользователя, авторизованного в системе, отображается в web-интерфейсе в правом верхнем углу. Также там отображается меню системных уведомлений.

При ошибке авторизации система выдает сообщение об ошибке «Authentication failed»:

../../_images/ui_login2.png

2.2.2. Общее описание web-интерфейса

В web-интерфейсе можно выделить следующие основные области:

  1. Панель вкладок — отображает список вкладок для навигации по функциональным разделам web-интерфейса.

  2. Рабочая область вкладок — отображает содержание активной вкладки.

../../_images/ui_main.png

2.2.2.1. Панель вкладок

В зависимости от роли пользователя набор доступных вкладок будет разный. Пользователи с ролями «admin» и «supervisor» видят все вкладки. Пользователю с ролью «user» доступен ограниченный набор.

Кнопка Collapse menu внизу панели переключает ее отображение в компактный режим и обратно.

Примечание

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

Ниже перечислены все вкладки с кратким описанием их назначения и ссылками на подробное описание в соответствующих разделах документа (подробное описание вкладки Cluster и меню Settings дано далее в этой главе).

Как упоминалось выше, для пользователя с ролью «user» доступ к определенным функциям системы ограничен, поэтому от него скрыты следующие вкладки:

  • Cluster

  • Configuration files

  • Model

  • Audit Log

  • Settings

2.2.2.2. Вкладка Cluster

Вкладка Cluster отображает текущий статус кластера экземпляров TDG и дает возможность его администрировать. В интерфейсе можно выделить несколько групп элементов для управления кластером.

../../_images/ui_cluster.png

[1] Replica sets

  • основная статистика по наборам реплик (replica sets): общее количество наборов реплик в кластере (total) | наборы реплик в статусе «unhealthy» | общее количество экземпляров (servers);

  • фильтр узлов кластера по различным критериям: URI, UUID, роль набора реплик, имя (alias) узла.

[2] Виджет набора реплик, который содержит следующую информацию и функциональные элементы:

  • имя и роли набора реплик;

  • текущий статус:

    • «healthy» (набор реплик функционирует нормально);

    • «unhealthy» (набор реплик недоступен или функционирует неправильно);

  • для набора реплик с ролью «storage» — значения параметров «Vshard group» и «Replica set weight»;

  • виждеты экземпляров, входящих в данный набор реплик (см. далее [3]);

  • кнопка Edit — открывает диалоговое окно, в котором можно редактировать параметры набора реплик.

../../_images/ui_edit_replicaset.png

[3] Виджет экземпляра:

  • имя (alias) экземпляра;

  • URI экземпляра для доступа по бинарному порту (задается в конфигурации кластера — параметр advertise_uri);

  • статус:

    • «healthy» (экземпляр функционирует нормально);

    • «unhealthy» (экземпляр недоступен или функционирует неправильно);

  • индикатор, является ли экземпляр лидером (leader) в наборе реплик;

  • индикатор используемой памяти (Memory usage): фактически используемая память / лимит памяти, заданный для данного экземпляра;

  • если экземпляр входит в набор реплик с ролью «storage» — индикатор количества виртуальных сегментов (Buckets) на данном экземпляре;

  • кнопка […] — меню со следующими функциями:

    • Server details — открывает дополнительную страницу с информацией о параметрах экземпляра;

    • Disable server — временно отключает экземпляр. Позже его можно снова подключить к кластеру;

    • Expel server — исключает экземпляр из кластера. См. подробнее.

[4] Кнопки для работы со следующими функциями:

Для каждого экземпляра можно просмотреть детальную информацию о его параметрах в режиме read-only. Для этого на вкладке Cluster для нужного экземпляра нажмите … > Server details:

../../_images/ui_sdetails01.png

Отображается всплывающее окно, содержащее подробную информацией о параметрах экземпляра:

../../_images/ui_sdetails02.png

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

  • General — общая информация об экземпляре;

  • Cartridge — информация о версии фреймворка Tarantool Cartridge;

  • Replication — параметры репликации;

  • Storage — параметры базы данных;

  • Network — параметры, относящиеся к работе с сетью;

  • Membership — параметры модуля membership;

  • Vshard-Router — параметры встроенной роли vshard-router;

  • Vshard-Storage — параметры встроенной роли vshard-storage;

  • Issues — информация об ошибках, возникающих в работе экземпляра.

Также см. подробнее:

2.2.2.3. Меню Settings

Меню Settings содержит вкладки, предназначенные для управления настройками системы. Доступ к настройкам имеют пользователи с ролями «admin» (чтение и изменение) и «supervisor» (только чтение).

2.2.2.4. Системные уведомления

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

../../_images/ui_notify01.png

Список всех уведомлений, выданных системой до настоящего времени, можно просмотреть, нажав значок уведомлений в правом верхнем углу страницы. Если в списке есть уведомления, не просмотренные пользователем, значок отмечен синей точкой.

../../_images/ui_notify02.png

При нажатии на значок появляется выпадающий список уведомлений. При необходимости список можно очистить, нажав Clear в самом низу списка.

../../_images/ui_notify03.png

2.3. Настройка кластера и запуск системы

После успешной установки приложения на серверы необходимо настроить кластер, что включает в себя следующие действия:

2.3.1. Создание набора реплик и задание ролей

Операции по настройке кластера можно выполнить через web-интерфейс администратора. Для подключения к web-интерфейсу надо зайти в браузере на любой сервер по доступному на нем http-порту http://<address>:<http_port> (указаны в файле конфигурации кластера). В рассматриваемом примере это может быть http://172.19.0.2:8080 (соответствует экземпляру с именем «core_1»).

На вкладке Cluster мы имеем набор несконфигурированных экземпляров (инстансов, instances), на что указывает их текущий статус «Unconfigured».

../../_images/clusterconf01.png

В некоторых подсетях может не работать автоматический поиск доступных серверов (autodiscovery). Тогда экземпляры этих серверов могут отсутствовать в таблице Unconfigured servers. Для ручной проверки доступности и добавления новых экземпляров в кластер можно использовать функцию Probe server (кнопка над таблицей с экземплярами), которая проверяет, доступен ли экземпляр по указанному адресу. Если экземпляр доступен, он появится в таблице.

../../_images/probeserver.png

Далее необходимо сконфигурировать топологию кластера, создав так называемые наборы реплик (replica sets, репликасеты) и задав их роли.

Выберите в таблице несконфигурированный экземпляр и нажмите кнопку Configure в правой части строки этого экземпляра. Откроется диалог настройки репликасета Configure server.

В диалоге необходимо выбрать нужные для данного репликасета роли (параметр Roles). Этот параметр обязательный, поэтому должна быть выбрана как минимум одна роль. Если репликасет выполняет в кластере более одной роли, то нужно отметить все необходимые роли. Подробнее о ролях репликасетов и рекомендациях по их назначению см. раздел «Роли».

../../_images/clusterconf02-2.png

Остальные параметры репликасета являются опциональными. Тем не менее рекомендуется задать имя репликасета (Replica set name), чтобы в дальнейшем было легче им управлять. У параметров Replica set weight и Vhsard group можно оставить значения, заданные по умолчанию. После определения нужных параметров нажмите кнопку Create replica set.

Cозданный репликасет с включенным в него экземпляром отображается в таблице Replica sets. Оставшиеся несконфигурированные экземпляры по-прежнему отображаются в таблице Unconfigured servers.

../../_images/clusterconf03.png

Продолжим настройку кластера — в нашем примере создадим 4 дополнительных репликасета, каждый из которых содержит по одному экземпляру:

../../_images/clusterconf04.png

На примере репликасетов с ролью storage (их в текущей топологии кластера — два) рассмотрим также операцию по добавлению дополнительных экземпляров в существующий репликасет.

У одного из оставшихся несконфигурированных экземпляров — с именем «storage_1_replica» — нажмите Configure и в диалоге настройки репликасета перейдите на вкладку Join Replica Set. В списке Choose replica set выберите репликасет с именем «storage_1» и нажмите Join replica set.

../../_images/clusterconf05.png

Экземпляр «storage_1_replica» будет включен в состав репликасета «STORAGE_1».

../../_images/clusterconf06.png

Выполните аналогичную операцию для последнего несконфигурированного экземпляра «storage_2_replica», включив его в репликасет «STORAGE_2».

На этом настройка топологии кластера завершена.

2.3.2. Запуск кластера

После настройки топологии кластера необходимо запустить в рабочее состояние репликасеты с ролью storage, выполнив инициализацию модуля Tarantool vshard. Для этого на вкладке Cluster нажмите кнопку Bootstrap vshard:

../../_images/vshard_bootstrap.png

Будут созданы виртуальные сегменты для хранения данных (virtual buckets) и распределены по хранилищам с учетом количества экземпляров с ролью storage.

../../_images/vshard_bootstrap02.png

2.3.3. Загрузка конфигурации системы

Последний этап запуска системы в работу — загрузка и применение ее конфигурации.

В web-интерфейсе перейдите на вкладку Configuration files. В секции Upload configuration загрузите архив в формате .zip, который должен содержать основной файл конфигурации системы config.yml и другие необходимые файлы (описание модели данных, Lua-код функций и др.). Если загрузка и применение конфигурации прошли успешно, система выдаст уведомление об этом.

../../_images/config_upload.png

После этого система готова к работе.

В дальнейшем актуальную конфигурацию всегда можно скачать на этой же вкладке, нажав на кнопку Current configuration в верхнем правом углу.

2.3.4. Автоматическая синхронизация настроек в кластере

Для нормального функционирования кластера все экземпляры должны иметь одинаковые настройки. С этой целью каждый экземпляр в своей рабочей директории /var/lib/tarantool/<instance_name> хранит копию конфигурации — в поддиректории /config в виде набора yml-файлов. Также в рабочей директории хранятся резервная копия конфигурации (в поддиректории /config.backup) и токен кластера .tarantool.cookie. Кластер синхронизирует эти файлы настроек у всех экземпляров.

После первоначальной загрузки файла конфигурации config.yml конфигурация автоматически обогащается информацией о топологии кластера с указанием всех серверов, репликасетов, экземпляров и их ролей. Также добавляется информация о созданных спейсах для хранения объектов согласно модели данных. Именно в таком виде конфигурация хранится в рабочей директории каждого экземпляра и синхронизируется между ними.

При дальнейшей настройке системы — добавлении пользователей и токенов приложений, настройке прав доступа и др. — информация об этом добавляется в соответствующие файлы конфигурации и синхронизируется в кластере. Аналогичная синхронизация выполняется при любых изменениях текущих настроек.

2.4. Администрирование кластера

В данной главе описываются следующие операции по администрированию кластера:

2.4.1. Изменение топологии кластера (добавление экземпляров)

Рассмотрим добавление нового экземпляра (инстанса, instance) в кластер на примере топологии, которую мы использовали при описании установки системы.

Допустим, нам нужно добавить еще один экземпляр с кластерной ролью storage. Как и в случае первоначальной устновки, сначала необходимо подготовить файл конфигурации разворачиваемого экземпляра в формате JSON. Значения параметров конфигурации см. в описании примера.

Важно

Убедитесь, что значение параметра cluster_cookie такое же, как и в конфигурации уже развернутого кластера. В противном случае вы не сможете включить вновь развернутый экземпляр в кластер, поскольку принадлежность к кластеру как раз определяется посредством этого параметра (см. подробнее).

{
    "general":
    {
        "cluster_cookie": "ilikerandompasswords"
    },
    "servers":
    [
        {
            "address": "172.19.0.3",
            "username": "vagrant",
            "instances":
            [
                {
                    "name": "storage_3",
                    "binary_port": 3003,
                    "http_port": 8083,
                    "memory_mb": 1024
                }
            ]
        }
    ]
}

Далее разверните экземпляр с помощью скрипта tdgctl.py аналогично тому, как это выполнялось при установке системы.

./tdgctl.py -c deploy_add.json deploy -f tdg-<version>.tar.gz

где

После успешного выполнения команды новый экземпляр должен появиться в web-интерфейсе на вкладке Cluster в таблице Unconfigured servers.

../../_images/clusterconf07.png

Если новый экземпляр не появился в web-интерфейсе, используйте функцию Probe server для проверки его доступности (см. подробнее).

Далее необходимо настроить конфигурацию нового экземпляра: включить его в набор реплик — новый или уже существующий — и определить кластерную роль и другие параметры. Подробнее см. в разделе «Создание набора реплик и задание ролей».

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

../../_images/clusterconf08.png

Необходимо отметить, что новый набор реплик с ролью storage имеет вес (параметр Replica set weight), равный «0». Это определяется при инициализации модуля vshard, которая происходит во время первоначального развертывания кластера.

В данном случае — после добавления экземпляра в новый набор реплик — нужно увеличить значение параметра Replica set weight для того, чтобы система произвела балансировку данных, перенеся их часть на новый набор реплик с ролью storage.

Для этого нажмите кнопку Edit у нужного набора реплик. В диалоговом окне Edit Replica Set, увеличьте значение параметра Replica set weight и нажмите Save, чтобы начать балансировку данных.

../../_images/weight_1.png

Если мы добавляем новый экземпляр в уже существующий набор реплик с ролью storage, действия, описанные выше, производить не нужно — балансировка данных будет выполнена автоматически.

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

  1. Кластер валидирует обновление конфигурации, проверяя доступность нового экземпляра с помощью модуля Tarantool membership. Все узлы в кластере должны быть рабочими, чтобы валидация была пройдена.

  2. Новый экземпляр ожидает, пока другой экземпляр в кластере не получит обновление конфигурации и не обнаружит его. На этом шаге у нового экземпляра еще нет своего UUID.

  3. Как только экземпляр понимает, что кластер знает о нем, экземпляр вызывает функцию box.cfg() и начинает работу.

2.4.2. Балансировка данных

Балансировка данных (решардинг) запускается регулярно, а также после добавления в кластер нового набора реплик с ненулевым весом (параметр Replica set weight).

Мониторинг процесса балансировки можно вести, отслеживая количество активных виртуальных сегментов (virtual buckets) на экземплярах с ролью storage. Первоначально в новом наборе реплик нет активных сегментов. Через некоторое время фоновый процесс балансировки начинает переносить сегменты из других наборов в новый. Балансировка продолжается до тех пор, пока данные не будут распределены равномерно по всем наборам реплик.

Чтобы отслеживать текущее количество сегментов, подключитесь к нужному экземпляру с ролью storage через консоль и выполните команду

vshard.storage.info().bucket

В web-интерфейсе администратора это можно сделать на вкладке Console. Эта вкладка доступна только в режиме разработки (начиная с версии 1.6.3).

../../_images/vshard_buckets.png

2.4.3. Исключение экземпляра из кластера

Система позволяет исключить какой-либо экземпляр из кластера. После того как экземпляр будет исключен, остальные экземпляры будут информированы об этом и не будут считать его членом кластера. Снова вернуть исключенный экземпляр в кластер будет нельзя.

Для исключения экземпляра из кластера:

  1. В web-интерфейсе на вкладке Cluster для нужного экземпляра нажмите […] > Expel server.

../../_images/instance_expel.png
  1. В окне подтверждения нажмите OK.

Экземпляр больше не будет отображаться на вкладке Cluster.

2.4.4. Включение автоматического восстановления после отказа (Failover)

Если в кластере задана конфигурация «мастер-реплика» и включено автоматическое восстановление после отказа (failover), то при отказе мастера в каком-либо наборе реплик кластер автоматически выбирает следующую реплику из списка приоритетов и назначает ей роль активного мастера (read/write). Когда вышедший из строя мастер возвращается к работе, его роль восстанавливается, а назначенный ранее активный мастер снова становится репликой (read-only).

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

  1. В web-интерфейсе на вкладке Cluster нажмите кнопку Edit у нужного набора реплик.

  2. В диалоговом окне с помощью перетаскивания мышью (drag-and-drop) отсортируйте экземпляры в списке в нужном порядке приоритета и нажмите Save.

../../_images/instance_priority.png

По умолчанию восстановление после отказа отключено, на что указывает статус на кнопке Failover: disabled. Нажмите эту кнопку для включения данной функции.

В диалоговом окне Failover control выберите нужный тип автоматического восстановления.

../../_images/failover_control.png

Для опций Eventual и Stateful указано значение по умолчанию 20 секунд для параметра Failover timeout — время, через которое запустится восстановление после отказа, если мастер вышел из строя.

Для опции Stateful также понадобится указать следующие параметры:

После настройки нужных параметров нажмите кнопку Save. Статус функции восстановления изменится на Failover: eventual или Failover: stateful в зависимости от выбранного типа функции восстановления.

../../_images/failover_enabled.png

2.4.5. Изменение мастера в наборе реплик

Текущий мастер в наборе реплик отображается символом короны. На вкладке Cluster цвет короны символизирует статус данной реплики — зеленый для исправно работающей реплики и красный для неработающей реплики.

../../_images/crown1.png

В диалоге Edit replica set цвет короны всегда остается красным.

../../_images/crown2.png

В режимах Failover: eventual и Failover: disabled, чтобы вручную изменить мастера в наборе реплик, необходимо выполнить следующие действия:

  1. В web-интерфейсе на вкладке Cluster нажмите кнопку Edit у нужного набора реплик.

  2. В диалоговом окне в разделе Failover priority при помощи перетаскивания мышью (drag-and-drop) переместите на первую строку ту реплику, которую хотите сделать мастером, и нажмите Save.

../../_images/master_change.png

В режиме Failover: stateful выбор мастера осуществляется во внешней системе.

2.4.6. Отключение набора реплик

Под отключением набора реплик с ролью storage (например, для технического обслуживания) подразумевается перемещение всех его виртуальных сегментов в другие наборы реплик.

Чтобы отключить набор реплик:

  1. В web-интерфейсе на вкладке Cluster нажмите кнопку Edit у нужного набора реплик.

  2. В диалоговом окне установите значение параметра Replica set weight равным «0» и нажмите Save.

    ../../_images/weight_0.png
  3. Подождите, пока процесс балансировки не завершит перенос всех виртуальных сегментов. Текущее количество сегментов в данном наборе реплик можно отслеживать как это описано в разделе о балансировке данных.

2.5. Роли

Функции экземпляров TDG (инстансов, instances) в кластере распределяются на основе ролей. Кластерные роли — это Lua-модули, которые реализуют специфическую для экземпляра логику.

Существуют 2 вида ролей: встроенные и настраиваемые.

Встроенные роли vshard-router и vshard-storage, а также логика их работы уже определены в Tarantool Cartridge, на базе которого построен TDG, и не требуют дополнительной конфигурации.

Встроенная роль failover-coordinator и логика её работы также определены в Tarantool Cartridge.

Следующие встроенные роли выполняют сугубо технические задачи и потому не отображаются в интерфейсе пользователя:

По усмотрению администратора экземплярам назначаются настраиваемые роли, которые можно дополнительно сконфигурировать.

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

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

Настраиваемая роль

Автоматически назначаемые роли

connector

vshard-router, tracing

input_processor

vshard-router, tracing

storage

vshard-router, vshard-storage, tracing

logger

vshard-router

notifier

vshard-router, tracing

output_processor

vshard-router, tracing

scheduler

vshard-router, tracing

task_runner

vshard-router, tracing

2.5.1. Рекомендации по назначению ролей на экземплярах

Хотя в TDG нет понятия «обязательная роль», имеет смысл говорить о минимально необходимом наборе ролей — connector, input_processor и storage. Этот минимальный набор обеспечивает основные функции системы — получение объекта, его обработку и хранение в TDG. Остальные роли назначаются по необходимости, в зависимости от решаемых бизнес-задач.

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

Роль

Stateless / Stateful

Singleton

connector

stateless

нет

input_processor

stateless

нет

storage

stateful

нет

logger

stateful

да

notifier

stateful

да

output_processor

stateless

нет

scheduler

stateful

да

task_runner

stateless

нет

account_manager

stateful

да

sequence_generator

stateful

да

failover-coordinator

stateless

нет

Все роли являются реплицируемыми (репликасет (набор реплик) с ролью может содержать более одной реплики).

На одном экземпляре можно назначить одну или несколько ролей.

Учитывая вышесказанное, можно дать следующие рекомендации по организации кластера и назначению ролей на экземплярах кластера:

  1. Роли connector, input_processor, task_runner и output_processor задействованы в обработке объектов. Их нужно горизонтально масштабировать пропорционально входящей нагрузке и утилизации CPU на серверах.

  2. Если вы назначаете на экземпляр роль connector или input_processor, обычно рекомендуется назначить на этот же экземпляр и вторую роль из данной пары. Исключение может быть в случае, когда первоначальная обработка объекта на роли connector является трудозатратной операцией и имеет смысл масштабировать эту роль отдельно.

  3. Роль storage (хранит состояние, не singleton): создание репликасета с нодами в разных дата-центрах. Количество репликасетов (горизонтальное масштабирование) — пропорционально объему данных, хранимых в RAM.

    Важно

    Если экземпляру назначена роль storage, то после этого исключить (expel) из кластера этот экземпляр будет нельзя.

  4. Роли logger, notifier, scheduler (хранят состояние, singleton): обычно достаточно репликасета с 2 репликами, разнесенными по разным дата-центрам.

  5. Роль output_processor не хранит состояние напрямую. Функционально роль реплицирует объекты во внешние системы, но для хранения объектов, предназначенных для репликации, а также объектов, чья репликация завершилась с ошибкой, используется роль storage. Поэтому логика горизонтального масштабирования роли output_processor аналогична логике для ролей, используемых для обработки объектов (см. п.1 выше).

2.6. Основной процесс обработки запроса

Роль connector принимает запрос (объект) из системы-источника. Исходный формат входящего объекта — JSON или XML, в зависимости от системы-источника. Если экземпляров с ролью connector несколько, выбор экземпляра и балансировка нагрузки выполняется сервисом nginx.

На роли connector происходит первоначальная обработка (parsing) входящего объекта: объект преобразуется в Lua-объект (Lua-таблицу) и направляется на роль input_processor. Также для каждого запроса генерируется его UUID, по которому в дальнейшем можно проследить весь путь объекта.

Дальнейший маршрут объекта определяется в соответствии с ключом маршрутизации (routing_key), который присваивается объекту на разных этапах его обработки. Логика маршрутизации по ключу и порядок обработки объекта задается в файле конфигурации системы config.yml.

На роли input_processor объект проходит через конвейеры обработки (pipelines, пайплайны), которые определены в конфигурации config.yml.

  1. Прежде всего выполняется классификация объекта. Если классификация успешна, объекту присваивается ключ маршрутизации, определяющий дальнейшие пайплайны для обработки.

  2. Если задано в конфигурации, объект проходит обработку в других пайплайнах в соответствие с ключом маршрутизации.

  3. Объект валидируется в соответствии с моделью данных.

Примечание

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

Если на любом из этапов — 1, 2, 3 — происходит ошибка, объект отправляется в ремонтную очередь. Информация об объектах в ремонтной очереди с описанием ошибок доступна администратору через web-интерфейс. Если определена роль notifier и настроена конфигурация mail server и subscribers, подписчикам будет отправлено уведомление об ошибке.

Если классификация, обработка и валидация объекта прошли успешно, объекту присваивается соответствующий routing_key, и объект сохраняется на экземпляре с ролью storage. Тип сохраняемого объекта также определяется настройками в config.yml в соответствии с ключом маршрутизации объекта.

Дальнейшие возможные действия с сохраненными объектами:

2.7. Настройки безопасности

Администрирование функций безопасности включает в себя следующее:

Также важная тема, относящаяся к безопасности, — режимы функционирования TDG.

2.7.1. Ролевая модель доступа

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

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

Роль

Доступ к функциям

Доступ к данным

admin

Полный доступ ко всем функциям.

read/write для всех агрегатов

supervisor

Полный доступ в режиме «только для чтения» — имеет доступ ко всем разделам системы, но не может менять ее настройки.

read для всех агрегатов

user

Ограниченный доступ. Запрещен доступ к разделам, связанным с администрированием системы (скрыты вкладки Cluster, Configuration files, Model, Audit Log, Settings).

Отсутствует

На основе этих ролей администратором могут быть созданы пользовательские роли с произвольным набором прав как для доступа к функциям системы, так и для доступа к данным.

Текущий список ролей пользователей можно увидеть на вкладке Settings > Roles:

../../_images/user_roles01.png

Для работы ролевой модели доступа необходимо назначить одному из наборов реплик в кластере роль account_manager. Это делается на этапе настройки кластера.

2.7.1.1. Создание роли пользователя

Администратор имеет возможность создания новых ролей доступа, в том числе на базе уже существующих (ролей по умолчанию или ранее созданных пользовательских ролей). Для новой роли может быть задан произвольный набор прав, и также к ней может быть привязан профиль доступа к данным.

Для создания новой роли пользователя:

  1. На вкладке Settings > Roles нажмите Add new role. Откроется диалог создания роли.

  2. В диалоге создания задайте следующие параметры:

    • Name — название роли;

    • Description (optional) — (опционально) произвольное описание роли;

    • Inherit from role — (опционально) выбор существующей роли, на базе которой будет создаваться новая.

  3. В таблице отметьте флаг Allowed для тех действий, которые будут доступны для пользователя данной роли (перечислены в списке в колонке Action). Профили доступа к данным, если они уже созданы в системе, отображаются в этом же списке. Назначить профиль доступа к данным можно и позднее, отредактировав набор действий для этой роли.

  4. Сохраните новую роль, нажав Save.

    ../../_images/user_roles02.png

2.7.2. Управление пользователями

Текущий список пользователей TDG и инструменты для управления ими находятся на вкладке Settings > Users:

../../_images/user_list.png

Управление пользователями включает в себя следующие операции:

2.7.2.1. Создание профиля пользователя

Для создания профиля пользователя TDG:

  1. В web-интерфейсе перейдите на вкладку Settings > Users и нажмите Create user. Откроется диалог создания пользователя.

    ../../_images/user_create01.png
  2. В диалоге укажите следующие параметры:

    • Name — имя пользователя;

    • Email — электронная почта пользователя;

    • Password — пароль для авторизации в системе (должен соответствовать политике паролей). Также пароль можно сгенерировать автоматически:

      • либо кнопкой Generate;

      • либо оставить поле пустым — в этом случае система автоматически сгенерирует пароль и отправит пользователю на указанный Email (для этого необходимо иметь настроенный SMTP-сервер).

    • Expires in — (опционально) срок действия пароля;

    Примечание

    Проверка истечения срока действия паролей выполняется примерно раз в 30 минут. Учетные записи с истекшим сроком действия паролем блокируются.

    • Role — роль пользователя согласно ролевой модели доступа.

  3. Нажмите Submit.

При создании профиля автоматически генерируется уникальный идентификатор пользователя, который отображается в колонке LOGIN в таблице User list и используется в дальнейшем для авторизации в web-интерфейсе.

Профили пользователей, включая их пароли, хранятся в файле конфигурации системы config.yml, который синхронизируется между всеми экземплярами, входящими в кластер. В целях безопасности пароли пользователей хранятся в виде хэша с добавлением криптографической соли.

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

../../_images/user_create02.png

Примечание

Помимо создания профилей пользователей в web-интерфейсе, их можно импортировать в систему посредством JSON-файла.

2.7.2.2. Редактирование и удаление профиля пользователя

Для редактирования профиля пользователя:

  1. В web-интерфейсе перейдите на вкладку Settings > Users.

  2. В таблице User list в колонке ACTIONS для нужного пользователя нажмите Edit.

  3. В диалоге редактирования профиля пользователя измените необходимые параметры и нажмите Submit.

Для удаления профиля пользователя из системы в колонке ACTIONS нажмите More для нужного пользователя и выберите в выпадающем меню Delete. В диалоговом окне подтвердите удаление, нажав OK.

2.7.2.3. Изменение статуса пользователя

При создании профиля пользователя он автоматически активируется в системе, на что указывает статус «active» в колонке STATUS таблицы User list. Администратор может изменить статус пользователя вручную — заблокировать пользователя в системе:

  1. В колонке ACTIONS нажмите More для нужного пользователя и выберите в выпадающем меню Block user:

    ../../_images/user_block01.png
  2. В диалоговом окне укажите, если необходимо, причину изменения статуса (параметр Reason) и нажмите Block. Если ранее статус пользователя уже менялся, причина последнего изменения статуса будет указана в параметре Previous Reason.

    ../../_images/user_block02.png

Статус пользователя будет изменен на «blocked» и отображен в колонке STATUS.

В дальнейшем администратор может заново активировать профиль пользователя по аналогичной процедуре (More > Unblock user).

2.7.2.4. Сброс пароля пользователя

Администратор может сбросить пароль любого из пользователей: в колонке ACTIONS нажмите More для нужного пользователя и выберите в выпадающем меню Reset password. В диалоговом окне подтвердите сброс пароля, нажав OK. После этого на электронный адрес пользователя, указанный в его профиле, будет выслан временный пароль для авторизации в системе.

Для корректной работы отправки нового пароля на электронный адрес должен быть настроен SMTP-сервер. Для этого необходимо:

  1. Развернуть и запустить SMTP-сервер.

  2. В файле конфигурации TDG config.yml прописать следующие настройки и загрузить измененную конфигурацию в систему:

    connector:
      output:
        - name: to_smtp
          type: smtp
          url: <URI SMTP-сервера>
          from: <адрес отправителя>
          timeout: <значение тайм-аута, секунды>
    
    account_manager:
      only_one_time_passwords: true
      output:
        name: to_smtp
    

2.7.2.5. Экспорт/импорт профилей пользователей

2.7.2.5.1. Экспорт

Профили пользователей можно экспортировать из системы в формате JSON. Для этого на вкладке Settings > Users нажмите Export:

../../_images/user_export01.png

В результате система сформирует и экспортирует файл с именем users-<N>.json (где <N> — порядковый номер), который содержит массив с профилями всех текущих пользователей. Профиль каждого пользователя имеет следующий формат (пример):

[
   {
     "expires_in":2592000,
     "login":"pc9199",
     "email":"petrov@mailserver.com",
     "created_at":1586236779870364400,
     "state_reason":"petrov@mailserver.com state is changed to active: recover from disabled",
     "failed_login_attempts":1,
     "uid":"23563aa8-facc-4970-89f3-cfc267609c3b",
     "role":"admin",
     "state":"active",
     "username":"Петров",
     "last_login":1586236825716746000,
     "last_password_update_time":null
   },
   {
   ...
   }
]

2.7.2.5.2. Импорт

Также возможна обратная операция — импорт профилей пользователей в систему.

Для импорта вначале необходимо подготовить файл с профилями пользователей в формате JSON. Это может быть ранее экспортированный файл с профилями (см. выше), или же администратор может подготовить файл с этими данными самостоятельно. В описанном представлении данных пользователя в формате JSON обязательными являются все поля кроме:

  • state_reason;

  • last_login;

  • last_password_update_time;

  • password.

Отдельно нужно сказать про поле password и логику генерации пароля пользователя при импорте профиля. Существует 2 варианта создания пароля:

  1. Указать пароль в явном виде в поле password — в этом случае флаг Generate passwords в диалоге импорта отмечать не нужно (см. ниже процедуру импорта), и пароль для пользователя будет взять из поля password как есть. При этом пароль должен соответствовать текущей политике паролей, определенной в системе.

  2. Сгенерировать пароль автоматически — в этом случае в поле password необходимо передать пустое значение (null) или просто не указывать это поле в JSON, а в диалоге импорта нужно отметить флаг Generate passwords. Пароль будет сгенерирован автоматически в соответствии с текущей политикой паролей.

Важно

Для всех импортируемых пользователей в JSON должен быть выбран один и тот же вариант генерации пароля — либо вариант 1, либо вариант 2.

После успешного импорта профиля данные пользователя, включая пароль, будут отображены в web-интерфейсе. Также можно настроить отправку данных на электронную почту пользователя. Для этого необходимо иметь настроенный SMTP-сервер и в диалоге импорта отметить флаг Send passwords via user’s email.

Важно

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

Пример профиля пользователя в формате JSON для импорта в систему:

[
   {
     "expires_in":2592000,
     "login":"rk7222",
     "email":"ivanov@mailserver.com",
     "created_at":1586236779870364400,
     "state_reason":null,
     "failed_login_attempts":0,
     "uid":"a0067457-faf2-4441-b213-7c823422bab6",
     "role":"admin",
     "state":"active",
     "username":"Иванов",
     "last_login":null,
     "last_password_update_time":null,
     "password":null
   }
]

Для импорта профилей пользователей:

  1. На вкладке Settings > Users нажмите Import. Откроется диалоговое окно.

    ../../_images/user_import01.png
  2. В диалоговом окне выберите JSON-файл с профилями пользователей (Choose File), отметьте, если необходимо, опции, связанные с генерацией паролей (Generate passwords и Send passwords via user’s email), и нажмите Apply.

В случае успешного импорта новые профили пользователей будут добавлены в таблицу User list. Данные профилей, включая пароли, будут показаны в web-интерфейсе в сообщении о результатах операции импорта.

../../_images/user_import02.png

Важно

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

Также данные импортированного пользователя, включая пароль, можно сохранить в формате .csv — кнопка Download passwords в сообщении с результатами импорта.

2.7.2.6. Управление политикой паролей

Политика создания паролей для авторизации пользователей в системе регулируется на вкладке Settings > Password Policy. Данная политика применима в равной степени как к паролям, которые пользователи задают вручную, так и к автоматически сгенерированным паролям. Изменять политику паролей может только администратор.

../../_images/passpolicy.png

В политике определяются:

  • Категории символов, которые должны быть обязательно включены в пароль:

    • Include Lowercase Characters— латинские буквы в нижнем регистре. По умолчанию включено;

    • Include Uppercase Characters — латинские буквы в верхнем регистре. По умолчанию включено;

    • Include Digits — цифры от 0 до 9 включительно. По умолчанию включено;

    • Include Symbols — дополнительные символы (!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~);

  • Password length — минимальная допустимая длина пароля. Значение по умолчанию: 8. Максимальная длина пароля: 1000 символов.

Для изменения политики паролей необходимо поменять значения нужных параметров и нажать ОК.

2.7.3. Токен приложений

Приложениям внешних систем для доступа к данным и функциям TDG необходим авторизованный доступ, который организуется через токены приложений.

Общий процесс выглядит следующим образом: в web-интерфейсе администратор генерирует токен, назначает для него права доступа к объектам TDG и передает токен разработчикам внешней системы.

Сгенерировать токен можно в web-интерфейсе: вкладка Settings > Tokens, кнопка Create token. В диалоге создания необходимо указать следующие параметры и нажать Submit:

В дальнейшем сам сгенерированный токен и его имя являются нередактируемыми. Отредактировать можно только срок действия токена и его роль.

../../_images/token01.png

После генерации токен в явном виде будет доступен только в сообщении в web-интерфейсе:

../../_images/token02.png

Важно

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

Другие возможные операции по управлению токенами — изменение статуса, удаление, экспорт, импорт — аналогичны таким же операциям для пользовательских профилей.

2.7.4. Права доступа к данным

TDG дает возможность установить для каждой роли права на действия с данными (объекты с логическим типом «Aggregate», далее — агрегат), которые обрабатываются и хранятся в системе:

Устанавливать права нужно после того, как в систему загружена модель данных, в которой описаны агрегаты и связанные с ними объекты. Модель данных загружается при первоначальной конфигурации системы.

Права доступа к данным задаются в web-интерфейсе через создание профиля доступа (data action), который потом назначается для каких-либо из пользовательских ролей.

Для создания профиля доступа:

  1. Перейдите на вкладку Settings > Data actions.

  2. Нажмите Add new Data Action. Откроется диалог создания профиля.

    ../../_images/data_action01.png
  3. В поле Name введите имя профиля доступа.

  4. Для каждого из агрегатов отметьте галочками нужные права, Read и/или Write.

  5. Сохраните профиль, нажав Save.

Созданный профиль доступа отображается на вкладке Settings > Data actions. Профиль является редактируемым, т.е. в дальнейшем можно изменять права Read/Write для нужных агрегатов.

После создания профиль становится доступен для назначения какой-либо роли.

Примечание

Назначить профиль доступа можно только для роли, созданной в системе администратором. Для ролей по умолчанию («admin», «supervisor», «user») эта операция недоступна, т.к. эти роли нередактируемые и являются своего рода шаблонами с предзаданным набором прав.

Чтобы назначить профиль доступа для существующей роли:

  1. Перейдите на вкладку Settings > Roles и в колонке Action для нужной роли нажмите Edit.

  2. В диалоге редактирования отметьте флаг Allowed для нужного профиля доступа.

    ../../_images/data_action02.png
  3. Сохраните настройки роли, нажав Save.

Аналогично профиль доступа можно назначить и при создании новой роли.

2.7.5. Режим обязательной аутентификации

Важно

Сразу после развертывания системы у пользователей и внешних приложений есть возможность неавторизованного анонимного доступа ко всем функциям и данным, что некорректно с точки зрения безопасности. Поэтому одним из первых действий администратора должно быть отключение возможности анонимного доступа и настройка обязательной аутентификации.

Для этого необходимо:

  1. Создать профиль пользователя с ролью «admin».

  2. Авторизоваться в системе под этим пользователем.

  3. Включить режим обязательной аутентификации (отключить анонимный доступ).

Режим обязательной аутентификации включается/отключается на вкладке Cluster переключателем Auth.

../../_images/user_auth03.png

Важно

При включении режима обязательной аутентификации любой запрос к TDG, а также доступ к веб-интерфейсу потребуют идентификации и аутентификации.

После идентификации и аутентификации пользователя в веб-интерфейсе будут скрыты недоступные для роли текущего пользователя вкладки.

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

  1. Передача логина и пароля пользователя.

  2. Передача параметра lsid из файла-cookie (в основном используется веб-интерфейсом после первого ввода логина и пароля для последующих аутентификаций).

  3. Передача токена приложения.

2.7.6. Авторизация внешних пользователей и систем через LDAP

Система TDG поддерживает технологию единого входа (Single Sign-On). Таким образом, авторизованный доступ к данным и функциям TDG возможен не только через токены и пользователей, но и через LDAP.

Чтобы настроить авторизацию внешних пользователей и систем через LDAP, пропишите необходимые параметры в файле конфигурации config.yml. Добавить секцию LDAP в файл конфигурации можно на любом этапе работы с системой TDG.

В самом начале настройки LDAP стоит обратить внимание на параметры domain и organizational_units. Они используются при аутентификации для поиска пользователя в соответсвующем домене и организационном юните(-ах).

Логином в систему является строка вида имя пользователя@domain, где:

Например: johndoe@example.com.

Однако, если опция use_active_directory выставлена в True, то логином в систему будет являться атрибут userPrincipalName у пользователя LDAP.

Примечание

Для локального тестирования LDAP авторизации предлагается использовать сервер GLAuth. Гарантируется работа с версией GLAuth 2.0.0.

2.7.7. Режимы функционирования TDG

TDG может функционировать в двух режимах:

Режим эксплуатации является основным для штатной эксплуатации TDG.

Режим разработки предоставляет дополнительный функционал (см. список ниже), который используется при разработке пользовательского кода и отладке работы системы. Однако при штатной эксплуатации этот функционал может снижать производительность системы и создавать ситуации, потенциально небезопасные с точки зрения сохранности данных и уязвимости системы. Поэтому в версии TDG, сертифицированной по требованиям доверия ФСТЭК России, использование режима разработки запрещено.

Дистрибутивы установки для этих двух режимов разные. По умолчанию выдается дистрибутив для работы в режиме эксплуатации.

В режиме разработки доступны следующие дополнительные функции (по сравнению с режимом эксплуатации):

Дистрибутив установки содержит скрипты enable_dev_mode.sh и enable_prod_mode.sh для включения соответствующего режима функционирования. Скрипты находятся в корневой директории дистрибутива.

Развернутый экземпляр можно переключить в другой режим работы. Для этого необходимо:

  1. На сервере, где развернут экземпляр, перейти в директорию, где хранятся исполняемые файлы для этого экземпляра /usr/share/tarantool/<instance_name>

  2. Запустить нужный скрипт (enable_dev_mode.sh или enable_prod_mode.sh).

  3. Перезапустить экземпляр:

    systemctl restart <instance_name>
    

2.8. Ремонтная очередь

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

Можно выделить следующие основные причины возникновения ошибок, когда объекты остаются в ремонтной очереди:

Работать с объектами в ремонтной очереди можно через web-интерфейс на вкладке Repair.

../../_images/repair01.png

В таблице отображается текущий список объектов в ремонтной очереди. Двойной клик на объект в таблице открывает отдельное окно Object info со следующей информацией об объекте:

../../_images/repair02.png

Для поиска нужного объекта есть возможность фильтрации по любому сочетанию символов в любой колонке таблицы — поле Filter; по дате и времени — поле Start Time ~ End Time.

Доступные действия над объектами в ремонтной очереди:

Когда объект попадает в ремонтную очередь, он имеет статус «New». При повторной обработке статус объекта меняется на «In Progress». Если обработка прошла успешна, объект удаляется из ремонтной очереди. Если при повторной обработке опять возникла ошибка, система выдаст сообщение об ошибке, и объект останется в ремонтной очереди со статусом «Reworked».

Аналогично действиям над отдельными объектами, можно выполнить действия над всеми объектами в ремонтной очереди:

2.8.1. Уведомления

В системе есть возможность информировать пользователей о попадании объекта в ремонтную очередь. Для этого должна быть определена роль notifier, а также заданы настройки почтового сервера и подписчиков, которым будут отправляться уведомления.

Роль notifier задается на одном из экземпляров при настройке ролей в кластере. Настройки почтового сервера и подписчиков задаются через web-интерфейс на вкладках Settings > Mail server и Settings > Subscribers соответственно.

2.8.1.1. Settings > Mail server

Настройки:

  • Url — сервер SMTP, используемый для отправки уведомлений;

  • From — отправитель, который будет показан в почтовом клиенте;

  • User name — имя пользователя сервера SMTP;

  • Password — пароль пользователя сервера SMTP;

  • Timeout (sec) — тайм-аут запроса к серверу SMTP, в секундах.

2.8.1.2. Settings > Subscribers

Необходимо создать подписчиков (кнопка Create subscriber), которые будут получать уведомления, указав их имя и Email. Возможные действия с подписчиками аналогичны действиям с пользователями. Можно

  • создать новых подписчиков;

  • редактировать данные текущих подписчиков: изменить имя и Email;

  • удалить подписчиков.

2.9. Управление бизнес-объектами

2.9.1. Вкладка Expiration

В системе есть возможность сконфигурировать время жизни бизнес-объекта (агрегата). В конце жизни объект физически удаляется из системы.

Эти возможности системы полезны при работы с типами объектов, которые нет необходимости хранить дольше определенного времени, например, суточные котировки и т.п.

Время жизни объекта можно задать через web-интерфейс на вкладке Settings > Expiration. Объекты на этой вкладке описаны в модели данных и становятся доступны после загрузки модели в систему.

../../_images/expiration.png

В секции Time limit задаются:

В секции Version limit задаётся:

Ограничения времени жизни объекта и ограничение количества версий могут работать как по отдельности, так и одновременно.

Помимо пользовательского интерфейса эти параметры могут быть заданы в файле конфигурации config.yml в секции «expiration».

2.9.2. Вкладка Unlinked spaces

При удалении агрегатов из модели данных в базе данных остаются спейсы, в которых хранятся объекты удаленных типов. На вкладке Settings > Unlinked spaces находится список всех спейсов, которые больше не привязаны к типам данных модели:

../../_images/unlinked01.png

Действия, которые возможны с этими спейсами:

Для выполнения этих операций нажмите соответствующую кнопку в колонке ACTIONS для нужного спейса.

Также эти операции можно применить сразу к нескольким спейсам: нужно выбрать необходимые спейсы, после чего станут доступны кнопки Truncate selected и Drop selected:

../../_images/unlinked02.png

2.10. Логирование

Просмотр лога (журнала) событий, связанных с бизнес-процессами, доступен через web-интерфейс на вкладке Logger.

Для этого в системе должна быть определена роль logger и настроена его конфигурация.

../../_images/logger01.png

Каждая запись в таблице лога предоставляет следующую информацию о событии:

Для удобства поиска записей в логе можно использовать фильтры. Фильтры существуют для каждой из колонок таблицы. Возможно использовать несколько фильтров совместно.

При заходе на страницу в таблице лога отображаются не более 100 записей. Если нужно увеличить количество записей, выводимых на экран, нажмите кнопку Show more внизу под таблицей.

Также возможно выгрузить все текущие записи лога в виде файла в формате .txt. Для этого нажмите кнопку Save внизу под таблицей.

Полный лог всех событий пишется средствами операционной системы и доступен при помощи системной утилиты journalctl:

journalctl -u <instance_name>

Также полные логи для всех экземпляров кластера можно получить при помощи скрипта expirationd tdgctl.py:

./tdgctl.py logs

См. подробнее про формат данной команды.

2.11. Журнал аудита

Журнал аудита содержит в себе записи о событиях безопасности в TDG. Подробный список событий безопасности, записи о которых попадают в журнал аудита, приведен далее.

Просмотр журнала аудита доступен через web-интерфейс на вкладке Audit Log.

Для обеспечения надежного сохранения записей журнала аудита предусмотрено несколько механизмов повышения надежности сохранения информации о событиях безопасности:

При этом журнал аудита ведется независимо от настроек авторизации. Отключить ведение журнала аудита можно, сняв галочку «Audit log is enabled» на вкладке Audit log.

../../_images/audit01.png

Каждая запись в таблице предоставляет следующую информацию о событии:

Для удобства поиска записей в журнале можно использовать фильтры. Фильтры существуют для каждой из колонок таблицы. Возможно использование фильтров по нескольким колонкам совместно.

По умолчанию используется единственный фильтр — по полю Severity, установленный на уровень Info. Для фильтрации по другому уровню важности выберите подходящий уровень из выпадающего списка, задайте фильтры по другим полям, если необходимо, и нажмите кнопку Apply для применения выбранных фильтров. Для возвращения к фильтру по умолчанию — нажмите кнопку Reset.

При входе на страницу Audit log в таблице отображаются не более 100 записей. Если нужно увеличить количество записей, выводимых на экран, нажмите кнопку Show more внизу, под таблицей.

Также возможно выгрузить все отображаемые в данный момент в таблице записи журнала аудита в виде текстового файла в формате .txt. Для этого нажмите кнопку Save внизу, под таблицей.

../../_images/audit02.png

2.11.1. Состав событий безопасности

В журнал аудита TDG записываются следующие события.

2.11.1.1. VERBOSE

Следующие события имеют уровень важности Verbose и не отображаются при фильтрации по любому другому уровню.

  • Сообщение о предоставлении доступа по имени токена: Access granted by token

  • Сообщение об отклонении доступа внешним модулем авторизации: Access denied by external auth: %REASON%

  • Сообщение о предоставлении доступа внешним модулем авторизации: Access granted by external token

  • Сообщение о предоставлении доступа токену: Access granted by token

2.11.1.2. INFO

Следующие события имеют уровень важности Info и отображаются при фильтрации по уровням Info и Verbose.

  • Сообщение о создании токена: Token %UID% created

  • Сообщение об изменении статуса токена: %TOKEN_NAME% state is changed to %STATE%

  • Сообщение об обновлении токена: Token %UID% updatedn%UPDATE_LIST%

  • Сообщение об удалении токена: Token %UID% removed

  • Сообщение о создании пользователя: User %UID% created

  • Сообщение об изменении статуса пользователя: %USER_EMAIL% state is changed to %STATE%

  • Сообщение об обновлении пользователя: User %UID% deleted

  • Сообщение об удалении пользователя: User %UID% updatedn%UPDATE_LIST%

  • Сообщение о применении новой конфигурации к генератору/валидатору паролей: New configuration for password generator has been applied

  • Сообщение об успешном вводе пароля пользователя: Correct password for user %UID%

  • Сообщение о попытке применения нового конфига: Try to upload a config

  • Сообщение об успешном применении нового конфига: Config applied

  • Сообщение о скачивании конфига: Config downloaded

  • Сообщение об успешном применении новой модели: Model applied

  • Сообщение об использовании функции eval (запрос и результат): Result of eval %CODE% is %RESULT%

  • Сообщение о предоставлении доступа по cookies пользователя: Access granted to user

  • Сообщение о предоставлении анонимного доступа: Access granted to anonymous user

  • Сообщение об изменении hard-limit’а: hard-limits changed. Old value: %OLD%, new value: %NEW%

  • Сообщение об изменении vshard-timeout’а: vshard-timeout changed. Old value: %OLD%, new value: %NEW%

  • Сообщение об изменении force-yield-limit’а: force-yield-limit changed. Old value: %OLD%, new value: %NEW%

  • Сообщение об изменении graphql-query-cache-size’а: graphql-query-cache-size changed. Old value: %OLD%, new value: %NEW%

  • Сообщение об изменении настроек времени жизни объектов: Expiration settings changed. Old values: %OLD%, new values: %NEW%

2.11.1.3. WARNING

Следующие события имеют уровень важности WARNING и отображаются при фильтрации по всем уровням, кроме ALARM.

  • Сообщение о вводе неправильного пароля пользователя: Incorrect password for user %UID%

  • Сообщение о попытке использования неизвестного имени токена: Access denied. Unknown token %TOKEN_NAME%

  • Сообщение о неизвестной ошибке при использовании имени токена: Access denied. Some error has occurred with token %TOKEN_NAME%

  • Сообщение об ошибке при использовании внешнего модуля авторизации: Error while performing external authentication: %ERROR%

  • Сообщение о попытке использования неизвестного токена: Attempt to authorize with token, but token %TOKEN% is unknown

  • Сообщение о неизвестной ошибке при использовании токена: Attempt to authorize with token %TOKEN%, but some error has occurred

  • Сообщение о попытке использования заблокированного токена: Attempt to authorize with token, token %TOKEN% blocked

  • Сообщение о попытке использования cookies неизвестного пользователя: Attempt to authorize with cookies, but user %LOGIN% is unknown

  • Сообщение о неизвестной ошибке при использовании cookies пользователя: Attempt to authorize with cookies for login %LOGIN%, but some error has occurred

  • Сообщение о попытке использования cookies заблокированного пользователя: Attempt to authorize with cookies, but user %LOGIN% blocked

  • Сообщение об отклонении доступа: Access denied

2.11.1.4. ALARM

Следующие события имеют уровень важности ALARM и отображаются при фильтрации по любому из уровней.

  • Сообщение об очистке audit логов: Audit log spaces was truncated

2.12. Репликация объектов

Механизм репликации объектов позволяет отправлять объекты во внешние системы в нужном формате.

Для работы репликации в системе должна быть определена роль output_processor и настроена конфигурация роли.

После успешной обработки на роли input_processor объект направляется в хранилище (роль storage) с определенным ключом маршрутизации. Если в конфигурации системы для данного ключа предусмотрена репликация, объект также отправляется в очередь репликации. Далее объект проходит так называемый preprocessing — обрабатывается в пайплайне, указанном в конфигурации для роли output_processor, и отправляется во внешнюю систему при помощи роли connector, где уже определен endpoint внешней системы.

Также возможно настроить репликацию определенных типов объектов, попавших в ремонтную очередь. Это тоже настраивается в конфигурации системы.

Если во время репликации объекта произошла ошибка, объект попадает в специальную ремонтную очередь репликации. Ее функционал идентичен ремонтной очереди, но различие в том, что ремонтная очередь репликации содержит объекты, которые не удалось реплицировать, а не объекты, которые не удалось сохранить. Администрировать объекты в ремонтной очереди репликации можно через web-интерфейс на вкладке Output_Processor.

../../_images/output_processor01.png

Информация об объектах в этой ремонтной очереди, а также операции над ними (фильтрация, Try again, Delete и т.д.) аналогичны информации и операциям в основной ремонтной очереди. Отличаются только статусы объектов в этих двух очередях. В ремонтную очередь репликации объекты попадают в результате двух типов ошибок:

При повторной операции (Try again) над объектом его статус меняется на «In Progress». Если повторная операция успешна, объект переходит на следующий этап обработки или удаляется из ремонтной очереди (в зависимости от предыдущего статуса). Если повторная операция завершилась ошибкой, статус объекта меняется на «Rereplicated (Preprocessing error)» или «Rereplicated (Sending error)» (в зависимости от предыдущего статуса) и объект остается в ремонтной очереди репликации.

2.13. Задачи и отложенные работы

2.13.1. Задачи (tasks)

Задачи суть те же пайплайны с набором функций, которые могут быть применены к сохраненным объектам или для любых других действий в системе (например, создание отчетов, инвалидация кэшированных данных и др.) и запущены в любое время, в т.ч. по расписанию.

Для выполнения задач в системе должны быть определены роли task_runner и scheduler и настроена их конфигурация.

Отслеживать текущее состояние задач и управлять их выполнением можно через web-интерфейс на вкладке Tasks.

../../_images/tasks01.png

Имя, вид и расписание выполнения задач определяются в конфигурации системы.

Информацию о конкретном экземпляре задачи можно получить в отдельном pop-up окне, которое выводится по клику на UUID задачи в колонке ID.

../../_images/tasks02.png

2.13.2. Отложенные работы (jobs)

Отложенные работы (jobs) по сути аналогичны задачам (являются пайплайнами обработки объектов). Но в отличие от задач, которые задаются и настраиваются в конфигурации системы, отложенные работы задаются и вызываются в клиентском программном коде: функция push_job программного интерфейса репозитория. Например:

local params = ...

local obj = params.obj

if obj.id ~= '26DA4133-0F97-44E8-83E6-95BA7646FC02' then
    repository.push_job('bad_job')
else
    for i = 1, obj.repeats do
        repository.push_job('sum', {obj.id, obj.initial, i})
    end
end

return params

Web-интерфейс позволяет вести мониторинг отложенных работ, которые завершились с ошибкой, — вкладка Failed Jobs. Элементы web-интенфейса и набор операций, доступные на этой вкладке, аналогичны элементам и операциям ремонтной очереди на вкладке Repair (см. подробнее).

В конфигурации системы также можно задать:

2.14. Тестирование и отладка

Web-интерфейс администратора предоставляет ряд инструментов для тестирования и отладки работоспособности системы. Они доступны на вкладках Model, Test, Graphql, Console и Code (последние две вкладки доступны только в режиме разработки).

2.14.1. Вкладка Model

Дает возможность загрузить в систему модель данных или проверить и отредактировать уже существующую.

../../_images/tab_model.png

Если в систему уже была загружена конфигурация вместе с моделью данных, в окне Request будет показана текущая модель.

Если необходимо, можно внести правки в модель и снова загрузить ее в систему, нажав Submit. При успешной обработке и загрузке, в качестве ответа от системы в окне Response будет отображена загруженная модель. В случае ошибки в окне Response будет выведено сообщение об ошибке.

2.14.2. Вкладка Test

На этой вкладке можно протестировать обработку системой входящего запроса.

Если система уже готова к работе (настроен кластер, определены роли экземпляров, загружена конфигурация системы и модель данных), в окно Request можно вставить текст запроса и отправить его, нажав Submit.

Запросы можно отправлять в формате JSON или SOAP XML, выбрав нужный формат переключателем в окне Request.

../../_images/tab_test.png

В окне Response выводится ответ от соответствующего модуля системы, отвечающего за прием и первоначальную обработку (parsing) запроса. В случае ошибки синтаксиса запроса, выводится сообщение об ошибке. Если запрос корректен, выдается ответ «ОК».

Ответ «ОК» означает, что запрос успешно обработан на роли connector и отправлен дальше на обработку на роль input_processor. Был ли запрос успешно обработан далее и сохранен в системе — нужно проверить дополнительно. Прежде всего нужно проверить ремонтную очередь: в случае ошибок обработки объект окажется там и не будет сохранен в систем. В этом случае можно проанализировать ошибки и внести коррективы в сам запрос и/или его обработчики. Если ремонтная очередь пустая, значит объект успешно обработан и сохранен. Проверить это можно, используя другие средства отладки, в частности отправив GraphQL-запрос.

2.14.2.1. Пример

Ниже приведен пример описания модели данных и входящего запроса (объекта) для этой модели. Подробнее о модели данных для приложения TDG см. раздел «Разработка доменной модели».

Модель:

[
    {
        "name": "Address",
        "type": "record",
        "logicalType": "ValueObject",
        "doc": "Адрес",
        "fields": [
            {"name": "city", "type": "string"},
            {"name": "street", "type": "string"},
            {"name": "building", "type": "string"},
            {"name": "apartment", "type": "int"}
        ]
    },

    {"type": "record",
     "name": "Person",
     "logicalType": "Aggregate",
     "doc":"Человек",
     "fields": [
         {"name": "passport_id", "type": "string"},
         {"name": "first_name", "type": "string"},
         {"name": "last_name", "type": "string"},
         {"name": "address", "type": "Address"},
         {"name": "birthday", "type": {"type": "string", "logicalType": "Date"}},
         {"name": "age", "type":["null", "int"]}
     ],

     "indexes": ["passport_id"]

    }
]

Объект в формате JSON для отправки входящего тестового запроса:

{
  "Person": {
      "passport_id": "7519 123456",
      "first_name": "Petr",
      "last_name": "Petrov",
      "birthday": "1980-01-01Z",
      "address": {
        "city": "Moscow",
        "street": "Tverskaya",
        "building": "23a",
        "apartment": 10
      }
  }
}

2.14.3. Вкладка Graphql

На этой вкладке доступна встроенная утилита GraphiQL, с помощью которой можно писать, валидировать и отправлять в систему запросы (query) и мутации (mutation) на языке запросов GraphQL.

../../_images/tab_graphql.png

Для работы с данными нужно использовать схему default (переключатель Select the desired scheme вверху страницы). Эта схема задана по умолчанию и используется для доступа к объектам.

Подробнее про запросы GraphQL см. в главе «Запросы к данным».

2.14.3.1. Пример

Рассмотрим GraphQL запросы и мутации для примера модели данных и тестового объекта, которые обсуждались ранее в разделе «Тестирование и отладка > Test». В предыдущем примере мы остановились на том, что в систему загружена модель данных и отправлен входящий запрос в формате JSON, в результате которого объект был корректно обработан и сохранен на роли storage.

  1. Запрос на получение объекта:

query {
  Person {
    passport_id
    first_name
    last_name
    birthday
    address {
      city
      street
      building
      apartment
    }
  }
}
  1. Мутация на вставку/изменение объекта и получение вставленного объекта:

mutation {
  Person(insert:{passport_id:"7519 123456"
                 first_name:"Petr"
                 last_name:"Petrov"
                 birthday:"1980-01-01Z"
                 address:{
                  city:"Moscow"
                  street:"Tverskaya"
                  building:"23a"
                  apartment:10
                 }
                }
  )
  {
    passport_id
    first_name
    last_name
    birthday
    address {
      city
      street
      building
      apartment
    }
  }
}
  1. Мутация на удаление объекта и получение удаленного объекта:

mutation {
  Person(passport_id:"7519 123456" delete:true){
    passport_id
    first_name
    last_name
    birthday
    address {
      city
      street
      building
      apartment
    }
  }
}

2.14.4. Вкладка Console

Примечание

Вкладка Console доступна только в режиме разработки.

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

../../_images/tab_console2.png

2.14.5. Вкладка Code

Примечание

Вкладка Code доступна только в режиме разработки.

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

../../_images/tab_code.png

2.15. Метрики

Для мониторинга работы TDG предоставляются метрики в формате Prometheus. Для каждого из экземпляров кластера значения метрик доступны по адресу: http://<IP_адрес_экземпляра>/metrics. В системе-сборщике метрик необходимо подать на вход адреса для сбора метрик со всех экземпляров кластера.

Все доступные метрики можно разделить на несколько категорий:

Используются следующие типы метрик Prometheus:

Подробнее про типы метрик см. в официальной документации Prometheus.

2.15.1. Метрики TDG

2.15.1.1. Метрики запросов GraphQL

Для мониторинга и оценки запросов GraphQL предоставляются следующие метрики:

  • tdg_graphql_query_time{alias,schema,entity,operation_name} — время обработки запроса на получение данных (query), миллисекунды. Тип метрики: histogram;

  • tdg_graphql_mutation_time{alias,schema,entity,operation_name} — время обработки запроса на изменения данных (mutation), миллисекунды. Тип метрики: histogram;

  • tdg_graphql_query_fail{alias,schema,entity,operation_name} — количество запросов на получение данных (query) c ошибками. Тип метрики: counter;

  • tdg_graphql_mutation_fail{alias,schema,entity,operation_name} — количество запросов на изменение данных (mutation) c ошибками. Тип метрики: counter.

Бакеты (bucket) гистограмм распределены в диапазоне от 0 до 1000 миллисекунд с интервалом в 100 миллисекунд (см. пример ниже).

Каждая из метрик имеет следующие тэги:

  • alias — имя экземпляра, на котором собираются метрики. Имя экземпляра было задано при развертывании кластера;

  • schema — имя схемы (default или admin), в которую поступил запрос GraphQL;

  • entity — сущность, над которой производится операция;

  • operation_name — имя запроса GraphQL (может отсутствовать, если имя запроса не было задано). Рекомендуется указывать имена для всех запросов, чтобы можно было однозначно идентифицировать, к какому запросу относится информация в метрике.

Вызов сервиса аналогичен запросу (query) для сущности. В данном случае в тэг entity будет записано имя сервиса.

Каждый запрос может состоять из нескольких операций, которые, в свою очередь, могут состоять из получения/модификации нескольких сущностей. В этом случае по каждой сущности будет выдана отдельная метрика со своим набором тэгов.

Пример:

# HELP tdg_graphql_query_time Graphql query execution time
# TYPE tdg_graphql_query_time histogram
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="100"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="200"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="300"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="400"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="500"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="600"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="700"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="800"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="900"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="1000"} 25
tdg_graphql_query_time_bucket{alias="core_1",schema="default",entity="City",operation_name="GetCity",le="+Inf"} 25
tdg_graphql_query_time_sum{alias="core_1",schema="default",entity="City",operation_name="GetCity"} 55
tdg_graphql_query_time_count{alias="core_1",schema="default",entity="City",operation_name="GetCity"} 25

# HELP tdg_graphql_mutation_time Graphql mutation execution time
# TYPE tdg_graphql_mutation_time histogram
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="100"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="200"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="300"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="400"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="500"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="600"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="700"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="800"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="900"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="1000"} 16
tdg_graphql_mutation_time_bucket{alias="core_1",schema="default",entity="City",operation_name="InsCity",le="+Inf"} 16
tdg_graphql_mutation_time_sum{alias="core_1",schema="default",entity="City",operation_name="InsCity"} 34
tdg_graphql_mutation_time_count{alias="core_1",schema="default",entity="City",operation_name="InsCity"} 16

# HELP tdg_graphql_query_fail Graphql query fail count
# TYPE tdg_graphql_query_fail counter
tdg_graphql_query_fail{alias="core_1",schema="default",entity="City",operation_name="GetCity"} 2

# HELP tdg_graphql_mutation_fail Graphql mutation fail count
# TYPE tdg_graphql_mutation_fail counter
tdg_graphql_mutation_fail{alias="core_1",schema="default",entity="City",operation_name="InsCity"} 4

Чтобы получить информацию о среднем количестве запросов GraphQL в секунду из Prometheus, воспользуйтесь запросом

rate(tdg_graphql_query_time_count[2m])

Период, по которому вычисляется rate() (в примере — 2m), должен быть как минимум в два раза больше периода сбора метрик. Если вы добавляете панель на стандартный Grafana Tarantool dashboard, воспользуйтесь переменной $rate_time_range.

Среднее время выполнения запроса GraphQL можно получить с помощью

rate(tdg_graphql_query_time_sum[2m])/rate(tdg_graphql_query_time_count[2m])

95-й перцентиль времени выполнения запроса GraphQL можно получить с помощью

histogram_quantile(0.95, sum(rate(tdg_graphql_query_time_bucket[2m])) by (le))

2.15.1.2. Метрики системного администрирования

tdg_cluster_clock_delta{alias,uuid} — разница во времени между локальными часами (часы экземпляра, на котором собираются метрики) и часами другого экземпляра в кластере, секунды. Положительное значение указывает на то, что часы другого экземпляра опережают локальные. Отрицательное значение — на обратную ситуацию. Тип метрики: gauge.

Тэги метрики:

  • uuid — UUID экземпляра, разницу во времени с которым определяет метрика;

  • alias — имя экземпляра, на котором собираются метрики.

В конфигурации системы при помощи параметра clock_delta_threshold_sec можно задать максимально допустимую рассинхронизацию по времени. При превышении этого порога в журнал будет выведено сообщение об ошибке. Подробнее см. в описании параметра

Если несколько экземпляров расположены на одном физическом сервере, разница во времени между ними, как правило, будет очень небольшой, т.к. каждый из этих экземпляров «смотрит» на одни и те же часы — часы физической машины. Разницу во времени в этом случае можно считать сетевой погрешностью. Однако если экземпляры расположены на нескольких физических серверах, метрика может диагностировать ситуацию, когда между экземплярами этих серверов временная разница значительная, что может указывать или на рассинхронизацию часов разных физических серверов, или на сетевые проблемы.

Пример ниже иллюстрирует подобную ситуацию: в кластере развернуты 7 экземпляров (см. топологию кластера); мы собираем метрики на экземпляре с именем «core_1», у которого большая временная дельта одного порядка с тремя экземплярами, развернутыми на другой физической машине.

Пример:

# HELP tdg_cluster_clock_delta The time difference in cluster
# TYPE tdg_cluster_clock_delta gauge
tdg_cluster_clock_delta{uuid="1ab7778c-26f6-4424-b8cd-1daf1d93fc70",alias="core_1"} -0.0001205
tdg_cluster_clock_delta{uuid="76fb5acd-65fd-43f0-8d57-6622aafdc5aa",alias="core_1"} 3.5e-05
tdg_cluster_clock_delta{uuid="a87d0c8c-aced-4c5c-9880-a23cd4edbc01",alias="core_1"} -12.851604
tdg_cluster_clock_delta{uuid="401415dd-4d4d-4c29-9342-fb3efbee5d12",alias="core_1"} 4.75e-05
tdg_cluster_clock_delta{uuid="2e4bb162-d2e7-43f5-9ca9-530c60b2712d",alias="core_1"} 0.00029
tdg_cluster_clock_delta{uuid="b82e8c4f-b522-414c-9e51-a850db7302b1",alias="core_1"} -12.8515295
tdg_cluster_clock_delta{uuid="7acc17ad-aa8a-4954-b13f-3938964c9f41",alias="core_1"} -12.850967

2.15.1.3. Метрики для задач и отложенных работ

В системе TDG доступны метрики для задач (tasks) и отложенных работ (jobs). Метрики актуальны только для экземпляров с ролью task_runner, так как именно на этих экземплярах запускаются задачи и отложенные работы.

Метрики задач имеют следующие тэги:

  • alias — обозначает имя экземпляра, на котором собираются метрики. Имя экземпляра было задано при развертывании кластера;

  • name — имя задачи;

  • kind — вид задачи:

    • single_shot — единоразовая задача;

    • continuous — непрерывно выполняемая задача;

    • periodical — задача, выполняемая по расписанию.

Метрики отложенных работ и системных задач имеют только тэги alias и name.

В TDG версий 1.6.x и 1.7.x есть только одна системная задача (system task) — это задача по архивации (читать подробнее про секцию archivation в файле конфигурации).

  • tdg_tasks_started — показывает, сколько всего запущено задач. Тип метрики: counter.

    По аналогии: tdg_jobs_started — число запущенных отложенных работ, tdg_system_tasks_started — число запущенных системных задач.

    Пример:

    # HELP tdg_system_tasks_started Total system tasks started
    # TYPE tdg_system_tasks_started counter
    tdg_tasks_started{alias="runner_1",name="districts_stat.calc_statistics.call",kind="periodical"} 2
    
    # HELP tdg_jobs_started Total jobs started
    # TYPE tdg_jobs_started counter
    tdg_jobs_started{name="succeed",alias="runner_1"} 1
    
    # HELP tdg_system_tasks_started Total system tasks started
    # TYPE tdg_system_tasks_started counter
    tdg_system_tasks_started{name="tasks.system.archivation.start",alias="runner_1"} 718
    
  • tdg_tasks_failed — показывает, сколько задач завершились с ошибкой. Тип метрики: counter.

    По аналогии: tdg_jobs_failed — число отложенных работ, которые завершились с ошибкой.

    Пример:

    # HELP tdg_tasks_failed Total tasks failed
    # TYPE tdg_tasks_failed counter
    tdg_tasks_succeeded{alias="runner_1",name="districts_stat.calc_statistics.call",kind="periodical"} 1
    
    # HELP tdg_jobs_failed Total jobs failed
    # TYPE tdg_jobs_failed counter
    tdg_jobs_failed{name="fail",alias="runner_1"} 2
    
  • tdg_tasks_succeeded — показывает, сколько задач было успешно выполнено. Тип метрики: counter.

    По аналогии: tdg_jobs_succeeded — число успешно выполненных отложенных работ, tdg_system_tasks_succeeded — число успешно выполненных системных задач.

    Пример:

    # HELP tdg_tasks_succeeded Total tasks succeeded
    # TYPE tdg_tasks_succeeded counter
    tdg_tasks_succeeded{alias="runner_1",name="districts_stat.calc_statistics.call",kind="periodical"} 2
    
    # HELP tdg_jobs_succeeded Total jobs succeeded
    # TYPE tdg_jobs_succeeded counter
    tdg_jobs_succeeded{name="succeed",alias="runner_1"} 1
    
    # HELP tdg_system_tasks_succeeded Total system tasks succeeded
    # TYPE tdg_system_tasks_succeeded counter
    tdg_system_tasks_succeeded{name="tasks.system.archivation.start",alias="runner_1"} 718
    
  • tdg_tasks_stopped — показывает, сколько задач было приостановлено. Тип метрики: counter.

    Пример:

    # HELP tdg_tasks_stopped Total tasks stopped
    # TYPE tdg_tasks_stopped counter
    tdg_tasks_stopped{alias="runner_1",name="districts_stat.calc_statistics.call",kind="periodical"} 2
    
  • tdg_tasks_running — показывает, сколько задач запущено в данный момент. Тип метрики: gauge.

    По аналогии: tdg_jobs_running — число отложенных работ, запущенных в данных момент, tdg_system_tasks_running — число системных задач, запущенных в данный момент.

    Пример:

    # HELP tdg_tasks_running Currently running tasks
    # TYPE tdg_tasks_running gauge
    tdg_tasks_running{alias="runner_1",name="districts_stat.calc_statistics.call",kind="periodical"} 0
    
    # HELP tdg_jobs_running Currently running jobs
    # TYPE tdg_jobs_running gauge
    tdg_jobs_running{name="succeed",alias="runner_1"} 0
    
    # HELP tdg_system_tasks_running Currently running system tasks
    # TYPE tdg_system_tasks_running gauge
    tdg_system_tasks_running{name="tasks.system.archivation.start",alias="tnt_net_external_1_runner_1_1"} 0
    
  • tdg_tasks_execution_time — показывает статистику по времени исполнения задачи. Тип метрики: histogram.

    По аналогии: tdg_jobs_execution_time — статистика по времени исполнения отложенной работы, tdg_system_tasks_execution_time — статистика по времени исполнения системной задачи.

    Бакеты (bucket) гистограмм распределены в диапазоне от 0 до 5 секунд: 0.0001, 0.00025, 0.0005, 0.001, 0.0025, 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5.

    Пример:

    # HELP tdg_tasks_execution_time Tasks execution time statistics
    # TYPE tdg_tasks_execution_time histogram
    tdg_tasks_execution_time_count{alias="runner_1",name="calc_districts_stat",kind="periodical"} 2
    tdg_tasks_execution_time_sum{alias="runner_1",name="calc_districts_stat",kind="periodical"} 0.014632841999969
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.0001",kind="periodical"} 0
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.00025",kind="periodical"} 0
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.0005",kind="periodical"} 0
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.001",kind="periodical"} 0
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.0025",kind="periodical"} 1
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.005",kind="periodical"} 1
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.01",kind="periodical"} 1
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.025",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.05",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.1",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.25",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="0.5",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="1",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="2.5",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="5",kind="periodical"} 2
    tdg_tasks_execution_time_bucket{alias="runner_1",name="calc_districts_stat",le="+Inf",kind="periodical"} 2
    
    # HELP tdg_jobs_execution_time Jobs execution time statistics
    # TYPE tdg_jobs_execution_time histogram
    tdg_jobs_execution_time_count{name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_sum{name="succeed",alias="runner_1"} 1.0725110769272e-05
    tdg_jobs_execution_time_bucket{le="0.0001",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.00025",name="succeed",alias="runner_1"}1
    tdg_jobs_execution_time_bucket{le="0.0005",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.001",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.0025",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.005",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.01",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.025",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.05",name="succeed",alias="runner_1"}
    tdg_jobs_execution_time_bucket{le="0.1",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.25",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="0.5",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="1",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="2.5",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="5",name="succeed",alias="runner_1"} 1
    tdg_jobs_execution_time_bucket{le="+Inf",name="succeed",alias="runner_1"} 1
    
    # HELP tdg_system_tasks_execution_time System tasks execution time statistics
    # TYPE tdg_system_tasks_execution_time histogram
    tdg_system_tasks_execution_time_count{name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_sum{name="tasks.system.archivation.start",alias="runner_1"} 0.052489631809294
    tdg_system_tasks_execution_time_bucket{le="0.0001",name="tasks.system.archivation.start",alias="runner_1"} 631
    tdg_system_tasks_execution_time_bucket{le="0.00025",name="tasks.system.archivation.start",alias="runner_1"} 715
    tdg_system_tasks_execution_time_bucket{le="0.0005",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.001",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.0025",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.005",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.01",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.025",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.05",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.1",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.25",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="0.5",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="1",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="2.5",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="5",name="tasks.system.archivation.start",alias="runner_1"} 718
    tdg_system_tasks_execution_time_bucket{le="+Inf",name="tasks.system.archivation.start",alias="runner_1"} 718
    

2.15.2. Метрики Tarantool

В системе TDG доступны метрики для мониторинга работы экземпляров Tarantool.

2.15.2.1. Общая статистика

Общая информация о различных параметрах экземпляров Tarantool. Метрики имеют тип gauge.

  • tnt_cfg_current_time — cистемное время экземпляра в формате unix timestamp;

  • tnt_info_uptime — время с момента запуска экземпляра, секунды;

  • tnt_read_only — обозначает, находится ли экземпляр в режиме «только чтение». 1 если верно, 0 если неверно;

  • tnt_info_lsn — LSN (log sequence number, регистрационный номер в журнале) данного экземпляра;

  • tnt_info_vclock — значение LSN из пары «id: lsn» в векторных часах, где id — идентификатор экземпляра в наборе реплик, а lsn — регистрационный номер в журнале.

2.15.2.2. Общая статистика использования памяти

Метрики имеют тип gauge.

  • tnt_info_memory_cache — объем памяти, используемый для кэширования данных, байты. Актуально для движка базы данных vinyl;

  • tnt_info_memory_data — объем памяти, используемый для хранения данных (кортежей), байты;

  • tnt_info_memory_index — объем памяти, используемый для индексирования данных, байты;

  • tnt_info_memory_lua — объем памяти, используемый средой выполнения Lua-кода, байты;

  • tnt_info_memory_net — объем памяти, используемый для буферов сетевого ввода/вывода, байты;

  • tnt_info_memory_tx — объем памяти, используемый активными транзакциями, байты.

2.15.2.3. Статистика использования памяти для распределения slab

Метрики имеют тип gauge.

  • tnt_slab_quota_size — максимальный объем памяти, который механизм распределения slab может использовать как для кортежей, так и для индексов, байты. Как настроено в параметре memtx_memory — по умолчанию 2^28 байт = 268 435 456 байт;

  • tnt_slab_arena_size — общий объем памяти, используемый для кортежей и индексов, включая выделенные, но в данный момент свободные slab’ы, байты;

  • tnt_slab_items_size — общий объем памяти, используемый только для кортежей, включая выделенные, но в данный момент свободные slab’ы, байты. Не используется для индексов;

  • tnt_slab_quota_used — объем памяти, уже выделенный для распределения slab, байты;

  • tnt_slab_arena_used — эффективный объем памяти, используемый для кортежей и индексов, не включая выделенные, но в данный момент свободные slab’ы, байты;

  • tnt_slab_items_used — эффективный объем памяти, используемый только для кортежей, не включая выделенные, но в данный момент свободные slab’ы, байты. Не используется для индексов;

  • tnt_slab_quota_used_ratio — соотношение quota_used / quota_size;

  • tnt_slab_arena_used_ratio — соотношение arena_used / arena_size;

  • tnt_slab_items_used_ratio — соотношение items_used / slab_count * slab_size. Это slab’ы, которые используются только для кортежей, не для индексов.

2.15.2.4. Статистика использования памяти в конкретных спейсах

У каждой из этих метрик есть тэги alias (экземпляр, на котором собираются метрики), name (имя спейса) и engine (движок базы данных, используемый для этого спейса). Метрики имеют тип gauge.

  • tnt_space_len{alias,name,engine} — количество кортежей в спейсе;

  • tnt_space_bsize{alias,name,engine} — количество байтов в спейсе (количество байтов во всех кортежах, включая ключи индекса);

  • tnt_space_index_bsize{alias,name,engine} — количество байтов, занятых под индексы;

  • tnt_space_total_bsize{alias,name,engine} — суммарное количество байтов space_bsize + space_index_bsize.

2.15.2.5. Статистика сетевой активности

Метрики имеют тип gauge. У некоторых метрик ниже встречается значение RPS — это среднее количество запросов в секунду, за последние 5 секунд.

  • tnt_net_sent_total — исходящий трафик, байты;

  • tnt_net_sent_rps — исходящий трафик, RPS;

  • tnt_net_received_total — входящий трафик, байты;

  • tnt_net_received_rps — входящий трафик, RPS;

  • tnt_net_connections_total — общее количество входящих сетевых соединений с момента запуска экземпляра;

  • tnt_net_connections_current — текущее количество входящих сетевых соединений;

  • tnt_net_connections_rps — среднее количество входящих сетевых соединений, RPS;

  • tnt_net_requests_total — общее количество входящих сетевых запросов с момента запуска экземпляра;

  • tnt_net_requests_current — текущее количество входящих сетевых запросов в обработке. Может быть ограничено параметром конфигурации базы данных net_msg_max;

  • tnt_net_requests_rps — среднее количество входящих сетевых запросов, RPS.

2.15.2.6. Информация о файберах

Метрики имеют тип gauge.

  • tnt_fiber_count — общее количество файберов;

  • tnt_fiber_csw — количество переключений контекста для всех файберов;

  • tnt_fiber_memalloc — общий объем памяти, выделенный под файберы, байты;

  • tnt_fiber_memused — реальный объем памяти, используемый файберами, байты.

2.15.2.7. Статистика входящих запросов (по типу запросов)

Тип метрик — gauge. Метрики имеют следующие тэги:

  • alias — обозначает имя экземпляра, на котором собираются метрики. Имя экземпляра было задано при развертывании кластера;

  • operation — тип входящего запроса, приходящего по бинарному протоколу:

    • auth — запросы на аутентификацию;

    • call — запросы на выполнение хранимой процедуры;

    • delete — запросы на удаление;

    • error — запросы, завершившиеся с ошибкой;

    • eval — запросы на выполнение Lua-кода;

    • execute — выполнение SQL-запросов;

    • insert — запросы на вставку;

    • prepare — запросы SQL prepare;

    • replace — запросы на замену;

    • select — запросы на поиск;

    • update — запросы на обновление;

    • upsert — запрос на обновление или вставку.

Метрики:

  • tnt_stats_op_total{alias,operation} — общее количество запросов данного типа с момента запуска экземпляра;

  • tnt_stats_op_rps{alias,operation} — среднее количество запросов данного типа в секунду, за последние 5 секунд.

2.15.2.8. Статистика использования памяти для среды выполнения Lua-кода

Метрики имеют тип gauge.

  • tnt_runtime_lua — объем динамической памяти сборщика мусора в Lua, байты;

  • tnt_runtime_used — объем памяти, используемый Lua в данный момент, байты.

2.15.2.9. Статистика CPU

Метрики имеют тип gauge.

  • tnt_cpu_count — общее количество процессоров, сконфигурированных операционной системой;

  • tnt_cpu_total — процессорное время хоста;

  • tnt_cpu_thread{thread_pid,kind,thread_name,alias,file_name} — процессорное время потока Tarantool. У этой метрики всегда есть следующие тэги:

    • thread_pid — PID (process ID), идентификатор потока;

    • kind — вид, может быть user или system;

    • thread_name — имя потока, может быть tarantool, wal, iproto или coio;

    • alias — экземпляр, на котором собираются метрики;

    • file_name — имя файла точки входа, например, init.lua.

  • tnt_cpu_user_time — количество использованного пользовательского времени процессора, секунды;

  • tnt_cpu_system_time — количество использованного системного времени процессора, секунды.

2.15.2.10. Метрики работы экземпляров Tarantool в кластере

Метрики имеют тип gauge.

  • tnt_cartridge_issues{alias,level} — количество ошибок в работе экземпляра. У метрики всегда есть тэги alias (экземпляр, на котором собираются метрики) и level, где level — это уровень критичности ошибки:

    • critical относится к критическим ошибкам в работе экземпляра, например, когда используется более 90% памяти;

    • warning относится к другим ошибкам в работе кластера, например, ошибки репликации на экземпляре.

  • tnt_clock_delta{alias,delta} — дрейф часов в кластере. У метрики всегда есть тэги alias (экземпляр, на котором собираются метрики) и delta, который имеет следующие возможные значения:

    • max — разница с самыми быстрыми часами (всегда положительная);

    • min — разница с самыми медленными часами (всегда отрицательная).

2.15.2.11. Метрики LuaJIT

Метрики LuaJIT дают представление о работе сборщика мусора Lua. Эти метрики доступны в Tarantool 2.6 и более поздних версиях.

  • Общие метрики JIT

    • lj_jit_snap_restore — общее количество восстановлений стека по снимку. Тип метрики: counter;

    • lj_jit_trace_num — количество JIT-трассировок. Тип метрики: gauge;

    • lj_jit_trace_abort — общее количество прерванных трассировок. Тип метрики: counter;

    • lj_jit_mcode_size — общий объем выделенного машинного кода, байты. Тип метрики: gauge.

  • JIT-строки:

    • lj_strhash_hit — количество интернируемых строк. Тип метрики: counter;

    • lj_strhash_miss — общее количество выделенных строк. Тип метрики: counter.

  • Шаги сборщика мусора:

    • lj_gc_steps_atomic — количество шагов инкрементного сборщика мусора (фаза atomic). Тип метрики: counter;

    • lj_gc_steps_sweepstring — количество шагов инкрементного сборщика мусора (фаза sweep для строк). Тип метрики: counter;

    • lj_gc_steps_finalize — количество шагов инкрементального сборщика мусора (фаза finalize). Тип метрики: counter.

    • lj_gc_steps_sweep — количество шагов инкрементального сборщика мусора (фаза sweep). Тип метрики: counter;

    • lj_gc_steps_propagate — количество шагов инкрементального сборщика мусора (фаза propagate). Тип метрики: counter;

    • lj_gc_steps_pause — количество шагов инкрементального сборщика мусора (фаза pause). Тип метрики: counter.

  • Аллокация:

    • lj_gc_strnum — количество размещенных объектов-строк. Тип метрики: gauge;

    • lj_gc_tabnum — количество размещенных объектов-таблиц. Тип метрики: gauge;

    • lj_gc_cdatanum — количество размещенных объектов cdata. Тип метрики: gauge;

    • lj_gc_udatanum — количество размещенных объектов udata. Тип метрики: gauge;

    • lj_gc_freed — объем освобожденной памяти, байты. Тип метрики: counter;

    • lj_gc_total — текущий объем выделенной Lua-памяти, байты. Тип метрики: gauge;

    • lj_gc_allocated — объем выделенной памяти, байты. Тип метрики: counter.

2.15.2.12. Vinyl

Следующие метрики предоставляют статистику работы движка vinyl. Метрики имеют тип gauge.

  • Disk — дисковые метрики используются для мониторинга общего объема данных на диске:

    • tnt_vinyl_disk_data_size — количество данных в байтах, хранимое в файлах .run, расположенных в директории vinyl_dir;

    • tnt_vinyl_disk_index_size — количество данных в байтах, хранимое в файлах .index, расположенных в директории vinyl_dir.

  • Regulator — регулятор движка vinyl решает, когда начинать действия по дисковому IO. Он группирует действия в пакеты, чтобы они были более последовательными и эффективными.

    • tnt_vinyl_regulator_dump_bandwidth — расчетная средняя скорость дампа, байты в секунду;

    • tnt_vinyl_regulator_write_rate — фактическая средняя скорость выполнения операций записи, байты в секунду;

    • tnt_vinyl_regulator_rate_limit — ограничение скорости записи, байты в секунду;

    • tnt_vinyl_regulator_dump_watermark — максимальный объем памяти в байтах, используемый для in-memory хранения LSM-дерева движка vinyl.

  • Transactional activity — работа с транзакциями:

    • tnt_vinyl_tx_commit — счетчик коммитов (успешных завершений транзакций);

    • tnt_vinyl_tx_rollback — счетчик откатов (неудачных завершений транзакций);

    • tnt_vinyl_tx_conflict — счетчик конфликтов, которые привели к откату транзакций;

    • tnt_vinyl_tx_read_views — текущее количество транзакций, которые перешли в состояние read-only, чтобы временно избежать конфликта.

  • Memory — следующие метрики показывают области памяти состояния, используемые движком vinyl для кэша и буферов записи:

    • tnt_vinyl_memory_tuple_cache — объем памяти в байтах, используемый в настоящее время для хранения кортежей (данных);

    • tnt_vinyl_memory_level0 — область памяти «Уровень 0» (L0), байты;

    • tnt_vinyl_memory_page_index — объем памяти в байтах, используемый в настоящее время для хранения индексов;

    • tnt_vinyl_memory_bloom_filter — объем памяти в байтах, используемый фильтрами bloom.

  • Scheduler — планировщик движка vinyl, который вызывает регулятор и обновляет связанные с ним переменные. Это происходит раз в секунду.

    • tnt_vinyl_scheduler_tasks{status,alias} — количество задач планировщика на дамп / компактификацию. У метрики всегда есть тэги alias (экземпляр, на котором собираются метрики) и status, который имеет следующие возможные значения:

      • inprogress для задач, которые запущены в данный момент;

      • completed для успешно завершенных задач;

      • failed для задач, прерванных из-за ошибок.

    • tnt_vinyl_scheduler_dump_time — общее время в секундах, затраченное всеми рабочими потоками на выполнение дампов;

    • tnt_vinyl_scheduler_dump_count — счетчик выполненных дампов.

2.16. Конфигурация системы (config.yml)

config.yml — основной файл конфигурации системы, в котором задана логика и порядок обработки входящих запросов, а также настройки кластерных ролей и других функций системы.

Файл загружается в систему при первоначальной конфигурации после установки системы и настройки кластера.

Рассмотрим структуру файла и логику настроек на примере ниже. В примере в качестве справочной информации приведены все возможные секции и параметры.

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

---
types: {__file: model.avsc}

functions:
  focus_decode: {__file: focus_decode.lua}
  focus_routing: {__file: focus_routing.lua}
  validate_coupon_payment: {__file: validate_coupon_payment.lua}
  focus_classifier: {__file: focus_classifier.lua}
  notification: {__file: notification.lua}
  single_task: {__file: single_task.lua}
  long_task: {__file: long_task.lua}

pipelines:
  connect_input_handle:
    - focus_routing
  coupon_payment_handle:
    - focus_decode
    - validate_coupon_payment
  focus_classifiers:
    - focus_classifier
  notification_filter:
    - notification
  single_task:
    - single_task
  long_task:
    - long_task

connector:
  input:
    - name: soap
      type: soap
      wsdl: {__file: Connect.wsdl}
      success_response_body: {__file: success_response_body.xml}
      error_response_body: {__file: error_response_body.xml}
      handlers:
        - function: Connect
          pipeline: connect_input_handle

    - name: http
      type: http
      pipeline: connect_input_handle

    - name: kafka
      type: kafka
      brokers:
        - localhost:9092
      topics:
        - orders
        - items
      group_id: kafka
      token_name: kafka_token
      pipeline: connect_input_handle

  output:
    - name: to_input_processor
      type: input_processor

    - name: to_external_http_service
      type: http
      url: http://localhost:8021/test_json_endpoint
      format: json

    - name: to_external_soap_service
      type: soap
      url: http://localhost:8020/test_soap_endpoint

    - name: to_kafka
      type: kafka
      brokers:
        - localhost:9092
      topic: objects

    - name: to_smtp
      type: smtp
      url: localhost:2525
      from: tdg@localhost
      subject: TDG_Objects
      timeout: 5
      ssl_cert: ssl.crt
      ssl_key: ssl.pem

    - name: dummy
      type: dummy

  routing:
    - key: input_processor
      output: to_input_processor

    - key: external_http_service
      output: to_external_http_service

    - key: external_soap_service
      output: to_external_soap_service

    - key: dummy
      output: dummy

input_processor:
  classifiers:
    - name: focus
      pipeline: focus_classifiers

  routing:
    - key: focus_couponpayment
      pipeline: coupon_payment_handle

    - key: focus_initiation
      pipeline: focus_catchall_handle

    - key: focus_ratechange
      pipeline: focus_catchall_handle

  storage:
    - key: focus_couponpayment
      type: CouponPayment

output_processor:
  focus_couponpayment:
    pipeline: notification_filter
    output: to_external_http_service
  unclassified:
    pipeline: notification_filter
    output: to_external_http_service

repair_queue:
  on_object_added:
    __unclassified__:
        postprocess_with_routing_key: unclassified

logger:
  rotate_log: true
  max_msg_in_log: 500000
  max_log_size: 10485760
  delete_by_n_msg: 1000

audit_log:
  enabled: true
  severity: INFO
  remove_older_than_n_hours: 12

tasks:
  task_1:
    kind: single_shot
    pipeline: single_task
    keep: 5
  task_2:
    kind: continuous
    pipeline: long_task
    pause_sec: 10
  task_3:
    kind: periodical
    pipeline: long_task
    schedule: "0 */5 * * * *"

task_runner:
  running_count_threshold: 100

jobs:
  max_jobs_in_parallel: 100

account_manager:
  only_one_time_passwords: true
  output:
    name: to_smtp
    options:
      subject: "Registration"
  password_change_timeout_seconds: 10
  block_after_n_failed_attempts: 5
  ban_inactive_more_seconds: 86400
  password_policy:
    min_length: 8
    include:
      lower: true
      upper: true
      digits: true
      symbols: false

pepper: 2d60ec7f-e9f0-4018-b354-c54907b9423d

auth_external: {__file: auth.lua}

notifier:
  mail_server:
    url: 127.0.0.1:2525
    from: TDG_repair_queue
    username: user
    password: passpass
    timeout: 5
    skip_verify_host: true
  users:
    - id: 1
      name: Petrov
      addr: petrov@mailserver.com

services:
  get_price:
    doc: "Get the item price by ID"
    function: get_price_by_id
    return_type: ItemPrice
    args:
      item_id: string

expiration:
  - type: CouponPayment
    lifetime_hours: 12
    delay_sec: 1800
    keep_version_count: 5

archivation:
  - type: Quotation
    lifetime_days: 7
    schedule: "0 0 0 */1 * *"
    dir: "/var/data"
    file_size_threshold: 104857600

hard-limits:
  scanned: 2000
  returned: 100

force_yield_limits: 1000

graphql_query_chache_size: 1000

vshard-timeout: 2

maintenance:
  clock_delta_threshold_sec: 5

gc:
  forced: true
  period_sec: 2
  steps: 20

tracing:
  base_url: localhost:9411/api/v2/spans
  api_method: POST
  report_interval: 0
  spans_limit: 100

sequence_generator:
  starts_with: 1
  range_width: 100

test-soap-data: {__file: test_object.json}

libraries:
  cache:
    __file: cached.lua
  utils:
    __file: utils.lua

welcome-message: |
  Hello! Let's start working with Tarantool Data Grid.

tdg-version: "== 1.7.0"

2.16.1. Секции

В файле конфигурации могут быть настроены следующие секции:

2.16.1.1. types

Описание модели данных (типов объектов), которые будут сохраняться в системе. В качестве языка описания модели используется Avro Schema — см. подробнее раздел «Разработка доменной модели». Как правило, описание делается в отдельном файле с расширением .avsc, на который делается ссылка в этой секции. Например:

types: {__file: model.avsc}

2.16.1.2. functions

Описание функций, которые будут выполняться в конвейерах обработки объектов (секция pipelines). Для каждой функции указывается имя функции и исполняемая часть — Lua-код функции, который также обычно выносится в отдельный файл. Например:

functions:
  focus_routing: {__file: focus_routing.lua}

2.16.1.3. pipelines

Описание конвейеров обработки объектов (пайплайнов). Для каждого пайплайна указывается имя и входящие в него функции, заданные в секции functions. Например:

pipelines:
  connect_input_handle:
    - focus_routing

2.16.1.4. connector

Для кластерной роли connector настраиваются:

input

Параметры коннекторов для получения и первоначальной обработки (parsing) входящих запросов. Ряд параметров есть у всех типов коннекторов:

  • name — имя коннектора (произвольное);

  • type — тип коннектора. Поддерживаемые типы:

    • http — для запросов в формате JSON по HTTP;

    • soap — для запросов в формате XML (SOAP) по HTTP;

    • kafka — для интеграции с шиной данных Apache Kafka.

  • pipeline — конвейер обработки входящих объектов, определенный в секции pipelines.

Помимо этих параметров, у некоторых типов коннекторов есть параметры, специфические только для них.

type: soap

  • wsdl — схема WSDL, описывающая структуру входящего XML;

  • success_response_body — шаблон ответа в случае успешной обработки запроса;

  • error_response_body — шаблон ответа в случае ошибки;

  • handlers — обработчики входящего запроса.

Примечание

Шаблоны ответа опциональны (параметры success_response_body и error_response_body). Пользователь может задать шаблоны в нужном ему формате, соответствующем системе, в которую отправляется ответ; сам TDG ограничений на формат не накладывает. В шаблоне error_response_body возможно использовать один спецификатор форматирования %s, чтобы передать в тело ответа текст ошибки.

Например:

connector:
  input:
    - name: soap
      type: soap
      wsdl: {__file: Connect.wsdl}
      success_response_body: {__file: success_response_body.xml}
      error_response_body: {__file: error_response_body.xml}
      handlers:
        - function: Connect
          pipeline: connect_input_handle

type: kafka

  • brokers — адреса (URL) брокеров сообщений;

  • topics — топики (topics) в терминологии Kafka;

  • group_id — идентификатор группы подписчиков;

  • token_name — имя токена приложения. Необходимо вначале сгенерировать токен в системе (см. описание процедуры) и далее указать имя токена (name) в качестве значения параметра. Токен будет использоваться для авторизации при обработке входящих сообщений, которые коннектор забирает из шины данных Apache Kafka. Поскольку формат сообщений шины не дает возможности передать токен в самом сообщении, токен указывается в конфигурации коннектора;

  • options — служит для передачи опций в библиотеку librdkafka.

  • workers_count — задает количество читателей сообщений (workers), которые будут работать на коннекторе. Значение по умолчанию: 10. Параметр может быть полезен для случая, когда нужно гарантированно сохранить порядок чтения входящих сообщений. Если читателей сообщений несколько, то будет идти параллельная обработка нескольких сообщений сразу, и их порядок может быть нарушен. Чтобы гарантировать сохранение порядка, необходимо в кластере оставить один connector и один input_processor (подробнее про эти роли экземпляров TDG см. в главе Роли) и задать значение workers_count: 1.

Для типа Kafka в конфигурации можно задать более одного входящего коннектора. Например:

connector:
  input:
  - name: kafka-1
    type: kafka
    brokers:
      - localhost:9092
    topics:
      - orders-1
      - items-1
    group_id: kafka
    token_name: kafka_token
    pipeline: connect_input_handle
    workers_count: 1

  - name: kafka-2
    type: kafka
    brokers:
      - localhost:9092
    topics:
      - orders-2
      - items-2
    group_id: kafka
    token_name: kafka_token
    pipeline: connect_input_handle
    workers_count: 1

output

Параметры коннекторов для отправки исходящих запросов. Ряд параметров есть у всех типов коннекторов:

  • name — имя коннектора (произвольное).

  • type — тип коннектора. Поддерживаемые типы:

    • input_processor — для отправки объекта на роль input_processor;

    • http — для отправки объекта в формате JSON во внешнюю систему по HTTP;

    • soap — для отправки объекта в формате XML (SOAP) во внешнюю систему по HTTP;

    • kafka — для интеграции с шиной данных Apache Kafka;

    • smtp — для отправки запросов через SMTP-сервер;

    • dummy — для игнорирования объектов (пришедший объект никуда не отправляется).

  • headers– заголовки HTTP, которые при необходимости может установить пользователь при отправке данных во внешнюю систему.

Помимо этих параметров, у некоторых типов коннекторов есть параметры, специфические только для них.

type: http

  • url — URL внешней системы, куда отправляется объект;

  • format — формат, в котором отправляется объект. Для коннектора типа http формат — JSON.

  • options — опции параметра opts (из встроенного модуля Tarantool http).

Например:

connector:
    output:
        - name: to_external_http_service
          type: http
          url: http://localhost:8021
          format: json
          options:
            timeout: 5
            keepalive_idle: 60
            keepalive_interval: 60
            verify_host: true
            verify_peer: true
          headers:
            hello: world

type: soap

  • url — URL внешней системы, куда отправляется объект.

Например:

connector:
  output:
    - name: to_external_soap_service
      type: soap
      url: http://localhost:8020/test_soap_endpoint
      headers:
        config_header: header_for_soap

type: kafka

  • brokers — адреса (URL) брокеров сообщений;

  • topic — топик (topic) в терминологии Kafka;

  • format — формат, в котором оправляется сообщение в Kafka. Возможные значения: json и plain. Значение plain может применяться для случая, когда необходимо отправить в Kafka сообщение в формате XML. Значение по умолчанию: json.

  • options — служит для передачи опций в библиотеку librdkafka.

  • is_async — определяет режим работы TDG в качестве Kafka-продюсера:

    • true — подтверждение о доставке сообщения отправляется только после того, как сообщение было действительно доставлено в Kafka.

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

    Значение по умолчанию: true.

Например:

connector:
  output:
     - name: to_kafka
       type: kafka
       brokers:
         - localhost:9092
       topic: objects
       options:
         debug: "all"
         queue.buffering.max.ms: 1
       is_async: true

type: smtp

  • url — URL сервера SMTP;

  • from — имя отправителя, которое будет показываться в поле «From» при получении сообщения;

  • subject — тема отправляемого сообщения;

  • timeout — тайм-аут запроса к серверу SMTP, секунды;

  • ssl_cert — путь к SSL-сертификату;

  • ssl_key — путь к приватному ключу для SSL-сертификата.

Например:

connector:
  output:
    - name: to_smtp
      type: smtp
      url: localhost:2525
      from: tdg@localhost
      subject: TDG_Objects
      timeout: 5
      ssl_cert: ssl.crt
      ssl_key: ssl.pem

routing

Mаршрутизация объекта для отправки через определенный output, который определяется в зависимости от ключа маршрутизации key. Ключ маршрутизации объект получает в результате обработки в пайплайне, указанном в input. Если в input пайплайн не указан, объект обрабатывается пайплайном по умолчанию, которые превращает объект вида

{
  "obj_type": { "field_1": 1 }
}

в объект

{
  "field_1": 1
}

и задает значение ключа маршрутизации как routing_key = obj_type.

Пример конфигурации:

connector:
  routing:
    - key: input_processor
      output: to_input_processor

    - key: external_http_service
      output: to_external_http_service

    - key: external_soap_service
      output: to_external_soap_service

2.16.1.5. input_processor

Для кластерной роли input_processor настраиваются:

classifiers

Определение пользовательского пайплайна, выполняющего классификацию объектов. В результате классификации объекту присваивается нужный ключ маршрутизации, по которому определяются дальнейшие действия по его обработке. Если пайплайн не задан, объект никак не обрабатывается и направляется на обработку пайплайном, указанным в секции input_processor: routing.

routing

Маршрутизация объекта в определенный пайплайн обработки по ключу маршрутизации (параметр key).

storage

Настройки сохранения объекта в роли storage по ключу маршрутизации (параметр key). Параметр type определяет тип бизнес-объекта (агрегата).

Пример маршрута (порядка обработки) объекта

Рассмотрим порядок обработки объекта на примере конфигурации выше.

1. После попадания в систему на роль connector, объект будет обработан в соответствии с настройками конфигурации input в секции connector.

В нашем примере мы видим, что для всех возможных вариантов input (JSON via HHTP, XML via SOAP, Kafka) конвейер обработки указан один и тот же: pipeline: connect_input_handle.

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

pipelines:
  connect_input_handle:
    - focus_routing

3. В секции functions мы видим, что исполняемый код этой функции находится в файле focus_routing.lua.

functions:
  ...
  focus_routing: {__file: focus_routing.lua}

Листинг кода:

local first = ...

local ret = {obj = first, priority = 1, routing_key = 'input_processor'}

return ret

Необработанный объект должен быть помещен в поле obj. Объекту будет присвоен ключ маршрутизации «input_processor».

4. Дальнейший маршрут объекта определяется настройками routing в секции connector. Для объектов с ключом маршрутизации «input_processor» это будет output: to_input_processor:

connector:

  routing:
    - key: input_processor
      output: to_input_processor
  1. В секции connector находим данный output:

connector:

  output:
    - name: to_input_processor
      type: input_processor

Значение параметра type означает, что объект будет направлен на экземпляр с ролью input_processor.

6. При попадании на роль input_processor объект прежде всего будет обрабатываться в соответствии с настройками из секции ниже:

input_processor:
  classifiers:
    - name: focus
      pipeline: focus_classifiers

В указанном здесь пайплайне будет выполняться следующий код из focus_classifier.lua:

local param = ...

local type_table =
    {
        ["Initiation"] =  "focus_initiation",
        ["Coupon Payment"] =  "focus_couponpayment",
        ["Exercise"] =  "focus_exercise",
        ["Rate Change"] =  "focus_ratechange"
    }

local node = lom.get_by_path(param.obj, 'message.header.routedata.event_type')

if node == nil then
    return param.obj
end

local event_type = string.strip(node[1])

param.routing_key = type_table[event_type]

return param

где lom.get_by_path — функция, которая берет значение из объекта по указанному пути. При этом путь записывается с разделением при помощи точки.

Допустим, что после обработки на данном этапе наш объект получит ключ маршрутизации «focus_couponpayment».

7. Дальнейшая обработка объекта с таким ключом маршрутизации будет определяться следующими настройками в секции input_processor:

input_processor:

  routing:
    - key: focus_couponpayment
      pipeline: coupon_payment_handle

  storage:
    - key: focus_couponpayment
      type: CouponPayment

Это означает, что сначала объект будет обработан в еще одном пайплайне — coupon_payment_handle, а потом направлен на роль storage как объект типа «CouponPayment». Данный тип должен быть описан в модели данных, которая определена в секции

types: {__file: model.avsc}

После успешной валидации по модели данных, объект будет сохранен на роли storage.

8. Если для данного ключа маршрутизации указаны еще какие-либо настройки в других секциях config.yml, объекты с этим ключом будут обработаны далее (см. пример про секцию output_processor).

2.16.1.6. output_processor

Задается логика обработки объектов, которые будут реплицироваться во внешние системы. Выполняется после успешного сохранения объектов на экземплярах с ролью storage.

Для объектов с определенным ключом маршрутизации определяется:

  • pipeline — какой конвейер обработки будет применен к объекту.

  • output — с какими параметрами объект будет отправлен во внешнюю систему. Все доступные параметры можно посмотреть в секции output.

  • expiration_timeout — по истечении какого времени (в секундах) объект будет удален из очереди, если он не был обработан. Значения по умолчанию нет.

  • store_strategy — значения copy или reference определяют то, как хранятся объекты — кортеж или первичный ключ соответственно. При использовании копии (copy) сохраняется кортеж, и даже при его удалении из хранилища никакие данные не теряются. Хранение по первичному ключу (reference) тратит меньше ресурсов, но при этом менее надежно — если объект был вытеснен, то при отправке он будет пропущен.

  • is_async — асинхронный или синхронный режим работы. Значение по умолчанию — is_async: true. В синхронном режиме (is_async: false) доступны еще два дополнительных параметра:

    • sync_retry_timeout — параметр задает таймаут (в секундах), после которого повторяется отправка объекта, с доставкой которого возникла проблема (по умолчанию sync_retry_timeout: 60);

    • sync_failed_attempt_count_threshold — параметр задает количество повторных попыток доставки. Значения по умолчанию нет.

В рассматриваемом примере:

output_processor:
  focus_couponpayment:
    pipeline: notification_filter
    output: to_external_http_service

Данные настройки означают, что объекты, которые на более ранних этапах обработки получили ключ маршрутизации focus_couponpayment, будут вначале обработаны функциями из пайплайна notification_filter, а затем отосланы в соответствии с настройками указанного здесь output (смотрим эти настройки в секции connector):

connector:

    output:
    - name: to_external_http_service
      type: http
      url: http://localhost:8021/test_json_endpoint
      format: json
      headers:
        config_header: header_for_http

Аналогично определяется поведение роли output_processor в отношении объектов с другими ключами маршрутизации.

При работе с output_processor можно переключаться между асинхронным и синхронным режимами работы (параметр is_async). Значение параметра is_async: false переводит роль output_processor в синхронный режим.

В асинхронном режиме есть только одна очередь вывода, и в случае сбоя объект помещается в ремонтную очередь. В синхронном режиме для продолжения работы необходимо, чтобы все сообщения были доставлены. Если в параметрах для отправки исходящих запросов output хотя бы с одним из получателей возникла ошибка, то останавливается вся очередь вывода. Попытку доставки можно повторить по истечении заданного таймаута (параметр sync_retry_timeout), и только для тех output, на которых возникла проблема. Количество повторных попыток можно настроить с помощью параметра sync_failed_attempt_count_threshold.

Пример:

output_processor:
  Type1:                                          # ключ маршрутизации
    expiration_timeout: 1000                      # время, по истечении которого необработанный объект будет удален
    store_strategy: copy                          # объекты хранятся в виде кортежей
    is_async: false                               # выбор синхронного режима
    sync_retry_timeout: 5                         # параметр доступен, если is_async: false
    sync_failed_attempt_count_threshold: 1000     # параметр доступен, если is_async: false
    handlers:                                     # обработчики запросов
      - pipeline: output_processor
        outputs:                                  # список получателей, которым будет доставлен объект
          - http_output
          - http_output2
          - http_output3

2.16.1.7. repair_queue

repair_queue:
  on_object_added:
    __unclassified__:
        postprocess_with_routing_key: unclassified

В данном примере настроен случай, когда определенные объекты, попавшие в ремонтную очередь, также должны быть реплицированы во внешнюю систему. В данном случае ранее на этапе классификации объект не удалось классифицировать, и ему было присвоено специальное значение ключа «__unclassified__», которым определяются неклассифицированные объекты.

При попадании такого объекта в ремонтную очередь, согласно настройкам postprocess_with_routing_key: unclassified, объекту присваивается другой ключ маршрутизации «unclassified», и с этим ключом он направляется на роль output_processor. Дальнейшая обработка объекта будет выполняться в соответствии с настройками в секции output_processor:

output_processor:
  unclassified:
    pipeline: notification_filter
    output: to_external_http_service

2.16.1.8. logger

В этой секции определяются настройки для кластерной роли logger. Все параметры обязательные.

  • rotate_log — флаг (true/false), осуществлять ли ротацию лога. Значения по умолчанию нет.

  • max_msg_in_log — максимальное количество сообщений, сохраняемых в логе. Значения по умолчанию нет.

  • max_log_size — максимальный размер файла лога, в байтах. Значения по умолчанию нет.

  • delete_by_n_msg — количество одновременно удаляемых сообщений при ротации лога. При превышении значений параметров max_msg_in_log или max_msg_log_size наиболее старые n сообщений в логе удаляются за раз, что повышает производительность по сравнению с режимом, когда старые сообщения удаляются по одному. Значения по умолчанию нет.

2.16.1.9. audit_log

В секции задаются параметры для работы журнала аудита. Все параметры опциональные.

  • enabled — включена (true) или выключена (false) запись событий в журнал аудита. По умолчанию: true.

  • severity — уровень важности событий, которые будут записываться в журнал аудита. Возможные значения по возрастанию важности: VERBOSE, INFO, WARNING, ALARM. По умолчанию: INFO.

    При указании определенного уровня в журнал аудита будут записываться события этого уровня и выше. Например, если задано INFO, будут записываться события, соответствующие уровням INFO, WARNING и ALARM. Подробнее см. список событий, соответствующий каждому уровню.

  • remove_older_than_n_hours — максимальное время хранения записей в журнале аудита, часы. Записи старше указанного времени удаляются. Значения по умолчанию нет.

2.16.1.10. tasks

В этой секции настраивается конфигурация задач, выполняемых при помощи ролей scheduler и task_runner. Например:

tasks:
  task_1:
    kind: single_shot
    pipeline: single_task
    keep: 5
  task_2:
    kind: continuous
    pipeline: long_task
    pause_sec: 10
  task_3:
    kind: periodical
    pipeline: long_task
    schedule: "0 */5 * * * *"

Параметры конфигурации:

  • task_N — имя задачи;

  • kind — вид задачи: «single_shot», «continuous» или «periodical» (см. подробнее);

  • pipeline — пайплайн, определяющий, что именно делается в рамках задачи;

  • keep — количество завершенных экземпляров задачи, которые сохраняются в истории. По умолчанию: 10;

  • pause_sec — пауза в выполнении задачи вида «continuous», секунды;

  • schedule — расписание выполнения для задач вида «periodical». Задается в формате cron. Используется расширенный синтаксис, в котором минимальной величиной является секунда:

* * * * * *
| | | | | |
| | | | | ----- День недели (0-6) (Воскресенье = 0)
| | | | ------- Месяц (1-12)
| | | --------- День (1-31)
| | ----------- Час (0-23)
| ------------- Минута (0-59)
--------------- Секунда (0-59)

В примере выше значение параметра schedule: "0 */5 * * * *" означает, что задача будет запускаться периодически каждые 5 минут.

2.16.1.11. task_runner

running_count_threshold — порог количества выполняемых пайплайнов для задач (tasks) и отложенных работ (jobs). По умолчанию: 100.

Этот параметр не ограничивает количество запущенных пайплайнов: при превышении порога в журнале просто создается предупреждение «Too many running pipelines. Now running %d pipelines».

2.16.1.12. jobs

max_jobs_in_parallel — максимальное количество отложенных работ (jobs), которые могут выполняться одновременно. По умолчанию: 50.

Когда достигается указанное ограничение, отложенные работы сверх лимита устанавливаются в очередь и выполняются по мере возможности.

2.16.1.13. account_manager

Настройки кластерной роли account_manager, которая обеспечивает работу ролевой модели доступа и связанных с ней функций безопасности (см. подробнее).

  • only_one_time_passwords — флаг (true/false). По умолчанию: false. Если указано значение true, будет запрещена возможность вручную задать пароль пользователя при его создании или импорте. TDG будет автоматически генерировать одноразовый пароль и высылать его на адрес электронной почты пользователя. Для отсылки пароля также необходимо иметь работающий сервер SMTP, описание его конфигурации в секции connector (output: type: smtp) и указание на этот output в секции account_manager:

    account_manager:
      only_one_time_passwords: true
      output:
        name: to_smtp
        options:
          subject: "Registration"
    

    Опционально можно указать заголовок письма, в котором высылается одноразовый пароль (options: subject:).

    Если указано значение only_one_time_passwords: false, то автоматическая генерация пароля и отсылка его пользователю также будет выполняться в случае, когда поле Password при создании пользователя оставлено пустым.

  • password_change_timeout_seconds — минимальное время, которое должно пройти до следующей смены пароля, секунды. Значения по умолчанию нет.

    Примечание

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

  • block_after_n_failed_attempts — количество неудачных попыток входа в систему, после которых пользователь будет заблокирован (статус пользователя станет «blocked»). Значения по умолчанию нет.

  • ban_inactive_more_seconds — максимальное время, в течение которого пользователь может быть неактивен в системе, секунды. По истечении этого времени пользователь будет заблокирован. Максимально возможное значение параметра — 45 дней. Если значение превышает 45 дней или параметр не задан, будет взято значение по умолчанию, равное 45 дням.

  • password_policy — настройки политики паролей. Эти настройки также можно задать через web-интерфейс.

    • min_length — минимальная допустимая длина пароля. По умолчанию: 8.

    • include — флаги (true/false), определяющие, какие категории символов должны обязательно входить в пароль:

      • lower — латинские буквы в нижнем регистре. По умолчанию: true.

      • upper — латинские буквы в верхнем регистре. По умолчанию: true.

      • digits — цифры от 0 до 9 включительно. По умолчанию: true.

      • symbols — дополнительные символы !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~. По умолчанию: false.

2.16.1.14. pepper

Строка символов, которая в целях усиления безопасности добавляется к паролю перед его хэшированием. Если данный параметр не указан в конфигурации, добавляется строка по умолчанию, определенная в коде системы.

2.16.1.15. auth_external

В настройке задается Lua-код или путь к файлу с Lua-кодом, в котором пользователь имеет возможность самостоятельно задать логику для авторизации входящих запросов. Код должен вернуть таблицу с параметром auth, в котором лежит функция для проверки входящих запросов в формате HTTP. Функция возвращает либо nil, если доступ запрещен, либо в противном случае — объект, содержащий аутентификационную информацию.

Примечание

В версии Tarantool Data Grid, сертифицированной по требованиям доверия ФСТЭК России, использование параметра auth_external запрещено.

2.16.1.16. notifier

Настройки кластерной роли notifier.

  • mail_server — секция настроек сервера SMTP, который используется для отправки уведомлений при попадании объекта в ремонтную очередь. Данные параметры также можно задать через web-интерфейс.

    • url — URL сервера SMTP;

    • from — имя отправителя, которое будет показываться в поле «From» при получении уведомления;

    • username — имя пользователя сервера SMTP;

    • password — пароль пользователя сервера SMTP;

    • timeout — тайм-аут запроса к серверу SMTP, секунды.

    • skip_verify_host — флаг (true/false): пропустить проверку хоста по протоколу TLS.

  • users — секция, где задаются данные подписчиков (subscribers), которые будут получать уведомления. Подписчиков также можно создать через web-интерфейс.

    • id — идентификатор подписчика;

    • name — имя подписчика;

    • addr — e-mail подписчика.

2.16.1.17. ldap

В этой секции настраивается авторизация внешних пользователей и систем через LDAP.

ldap:
  - domain: 'glauth.com'
    organizational_units: ['superheros']
    hosts:
      - localhost:3893
    use_active_directory: true
    use_tls: false
    search_timeout: 2
    roles:
      - role: 'admin'
        domain_groups:
          - 'cn=superheros,ou=groups,dc=glauth,dc=com'
          - 'cn=users,ou=groups,dc=glauth,dc=com'
  • domain — доменное имя, которое используется в доменном логине пользователя (user@domain);

  • organizational_units — названия организационных подразделений или групп пользователей;

  • hosts — адрес для подключения к LDAP-серверу;

  • use_active_directory — параметр, определяющий, используется ли Active Directory (служба каталогов Microsoft). Если установлено значение true, используйте email для входа в систему и атрибут Active Directory userprincipalname=email в качестве фильтра, где <email> — это имя для входа пользователя в формате email-адреса;

  • use_tls — параметр, определяющий, используется ли TLS. Значение по умолчанию: false;

  • search_timeout — таймаут ожидания ответа от LDAP-сервера. Значение по умолчанию: 2 секунды;

  • roles — описание ролей, которые будут назначаться пользователю в зависимости от LDAP-групп, в которых он состоит:

    • role — роль, назначенная пользователю или внешнему приложению для авторизованного доступа и действий в системе (читать подробнее про роли);

    • domain_groups — LDAP-группы, которые соответствуют указанной выше роли. cn — общее имя (common name), ou — организационное подразделение или группа пользователей (organization unit name), dc — компонент домена (domain component).

2.16.1.18. services

В этой секции настраивается конфигурация сервисов. Например:

services:
  get_price:
    type: query
    doc: "Get the item price by ID"
    function: get_price_by_id
    return_type: ItemPrice
    args:
      item_id: string

Параметры:

  • Имя сервиса. В примере выше — get_price. Имя сервиса должно начинаться с латинской буквы и может содержать латинские буквы, цифры и символ подчеркивания (_);

  • type — тип запроса GraphQL для вызова сервиса: query или mutation. Если тип — query, параметр можно не указывать.

  • doc — произвольное описание сервиса;

  • function — ссылка на функцию, которая выполняет данный сервис. Функция должна быть описанна в конфигурации в секции functions;

  • return_type — тип данных, который возвращается в результате выполнения сервиса;

  • args — описание аргументов, передаваемых на вход при выполнении сервиса, в формате «имя_аргумента: тип_данных».

2.16.1.19. expiration

В секции задаются следующие параметры:

  • type — тип объекта, в отношении которого задаются ограничения;

  • lifetime_hours — время жизни объекта в часах. Объекты старше этой величины будут считаться устаревшими и подлежащими удалению. Значение по умолчанию: 24;

  • delay_sec — интервал в секундах, через который запускается очередная проверка устаревших объектов и их удаление. Значение по умолчанию: 36000;

  • keep_version_count — ограничение количества версий для объектов данного типа. По умолчанию: не ограничено.

Данные настройки также можно задать через web-интерфейс.

2.16.1.20. archivation

Определенные типы объектов могут поступать в систему в большом количестве, но при этом иметь короткое время активного использования, после чего потребность в обращении к ним возникает редко. Для этого случая реализован механизм архивации, когда такие объекты выгружаются из TDG и сохраняются отдельно на жестком диске.

Объекты сохраняются в текстовом виде в файлах формата .jsonl (формат имени — YYYY-MM-DDTHH:MM:SS.jsonl). Объекты записываются в файл построчно: один объект — одна строка вида {"TypeName": {... data ...}}, где TypeName — тип сохраняемого объекта.

Настройки архивации в конфигурации TDG:

  • type — тип объекта;

  • lifetime_days– время жизни объекта в TDG, дни. Объекты старше этой величины архивируется;

  • schedule — расписание запуска задачи на архивацию в формате cron;

  • dir — директория для хранения файлов с архивными данными;

  • file_size_threshold — максимальный размер файла с архивными данными, байты. По достижении этого размера запись архивируемых данных начинается в новый файл. По умолчанию: 104857600 (100 Мб).

2.16.1.21. hard_limits

Для контроля нагрузки на сервер задаются следующие ограничения на выполнение GraphQL-запросов:

  • scanned — запрос не должен проходить больше заданного количества кортежей в спейсах. По умолчанию: 2000.

  • returned — запрос не должен возвращать больше заданного количества кортежей. По умолчанию: 100.

При превышении одного из ограничений выполнение запроса прекращается и возвращается ошибка.

2.16.1.22. force_yield_limits

force_yield_limits — ограничение на количество сканирований записей в спейсе. При достижении порога выполняется yield. По умолчанию: 1000.

Актуально при выполнении map_reduce, чтобы избежать зависаний на экземплярах с ролью storage. Также учитывается при работе функций программного интерфейса репозитория.

2.16.1.23. graphql_query_chache_size

graphql_query_chache_size — размер кэша запросов GraphQL. Измеряется в количестве запросов, т.е. кэшируются N последних уникальных запросов в виде полного текста каждого запроса. По умолчанию: 3000.

2.16.1.24. vshard-timeout

vshard-timeout — время ожидания запроса, которое передается в функции vshard.callro()/callrw(), секунды. По умолчанию: 2.

2.16.1.25. maintenance

clock_delta_threshold_sec — порог рассинхронизации истинного времени (CLOCK_REALTIME) на серверах, секунды. По умолчанию: 5.

При превышении порога в логе создается запись об ошибке «Time deviation threshold exceeded! Max clock delta is %s». Проверка синхронизации важна для операций, использующих метки времени, таких как логирование и аудит.

2.16.1.26. gc

Роль garbage_collector принудительно запускает сборку мусора в Lua. Роль включается неявно на всех экземплярах.

Параметры:

  • forced — включение (true) или отключение (false) принудительной сборки мусора. По умолчанию: false;

  • period_sec — интервал, через который происходит запуск нового цикла сборки мусора, секунды;

  • steps — размер шага сборщика мусора.

2.16.1.27. tracing

Настройки коммуникации с трейсинг-системой (tracing system), куда передаются данные для анализа производительности выполнения кода.

  • base_url — эндпойнт программного интерфейса (API endpoint), куда отсылаются собранные для анализа спаны (spans);

  • api_method — тип HTTP-запроса для обращения к base_url. Для трейсинг-систем, поддерживающих протокол OpenZipkin, — POST;

  • report_interval — интервал, через который в трейсинг-систему отсылаются накопленные спаны, секунды;

  • spans_limit — размер буфера для накопления спанов перед отправкой в трейсинг-систему. Измеряется количеством спанов.

Например:

tracing:
  base_url: localhost:9411/api/v2/spans
  api_method: POST
  report_interval: 5
  spans_limit: 100

2.16.1.28. metrics

По умолчанию значения метрик в формате Prometheus доступны по адресу http://<IP_адрес_экземпляра>/metrics. Подробнее о сборе метрик можно почитать в главе «Метрики».

Также для мониторинга работы TDG можно настроить просмотр метрик по другим адресам ресурсов (endpoints) и в других форматах:

metrics:
  export:
    - path: '/path_for_json_metrics'
      format: 'json'
    - path: '/path_for_prometheus_metrics'
      format: 'prometheus'
    - path: '/health'
      format: 'health'
  • export — параметр, который определяет, что в этой секции файла конфигурации мы делаем экспорт метрик в нужную нам базу данных временных рядов (time series database);

  • path — путь, по которому будут доступны метрики. Например:

    • </path_for_json_metrics> — путь, по которому будут доступны метрики в формате JSON;

    • </path_for_prometheus_metrics> — путь, по которому будут доступны метрики в формате Prometheus;

    • </health> — путь, по которому будет доступна информация о текущем состоянии экземпляра.

  • format — формат, в котором будут доступны метрики:

    • JSON;

    • Prometheus;

    • health — проверка текущего состояния экземпляра. Если состояние экземпляра удовлетворительное, возвращает 200, если нет — возвращает 500.

Если у вас, например, несколько систем хранения метрик, вы можете добавить несколько адресов ресурсов одного формата по разным путям:

metrics:
  export:
    - path: '/path_for_json_metrics'
      format: 'json'
    - path: '/another_path_for_json_metrics'
      format: 'json'

Как только вы добавите секцию metrics в файл конфигурации, метрики по умолчанию в формате Prometheus по адресу http://<IP_адрес_экземпляра>/metrics перестанут быть доступными. Если вам нужно, чтобы метрики по-прежнему были доступны по этому адресу в том же формате, добавьте path: '/metrics' и format: 'prometheus' в секцию metrics.

2.16.1.29. sequence_generator

Настройки, используемые при генерации последовательностей уникальных чисел:

  • starts_with — число, с которого начинается последовательность. По умолчанию: 1.

  • range_width — диапазон последовательности. По умолчанию: 100.

См. подробнее про функцию работы с последовательностью.

2.16.1.30. test-soap-data

Параметр позволяет задать текст, который будет по умолчанию отображаться на закладке Test в web-интерфейсе. Может использоваться для удобства тестирования: в этой секции можно задать структуру тестового объекта в формате XML или JSON для имитации входящего запроса.

2.16.1.31. libraries

Настройка подключения пользовательских библиотек, которые могут использоваться в коде функций пайплайнов (см. секции functions и pipelines). Указывается имя библиотеки, которое будет использоваться в коде, и путь к файлу библиотеки, который загружается вместе с конфигурацией системы.

Пример конфигурации:

libraries:
  cache:
    __file: cached.lua
  utils:
    __file: utils.lua

Пример вызова:

Если в указанной в конфигурации библиотеке (например, utils.lua) определена функция

local function timediff(value)
    return (datetime.now() - value)
end

то в пользовательском коде функцию можно вызвать как utils.timediff(value).

2.16.1.32. welcome-message

Текст приветственного сообщения, которое будет появляться при входе в систему. Ограничения на количество символов в сообщении нет.

2.16.1.33. tdg-version

Проверка версии TDG на совместимость при применении конфигурации. Для параметра указывается условие проверки, и с ним сравнивается текущая версия TDG. Если условие не выполняется, применение конфигурации останавливается.

Пример:

tdg-version: "== 1.7.0" # [оператор][пробел][версия]

где:

  • оператор: ==, <=, <, >, >=;

  • версия: major.minor.patch (семантическое версионирование) или scm-<число>.

Важно

Чтобы избежать возможных ошибок при чтении, всегда заключайте выражение из оператора и версии в кавычки. Обязательного помещения в кавычки не требует только выражение с «==».

Синтаксис YAML позволяет указывать многостроковые значения с помощью операторов >, <, >=, >= в первой строке. Например, чтобы задать версию больше, чем некоторое значение, нужно поместить оператор > и версию в кавычки:

# ошибка, будет прочитано как "1.7.0"
# tdg-version: > 1.7.0

# правильно, будет прочитано как "больше чем 1.7.0"
tdg-version: "> 1.7.0"

2.17. Скрипт tdgctl.py

Скрипт tdgctl.py позволяет развернуть TDG и выполнить ряд операций по его администрированию. В дистрибутиве установки скрипт находится в директории /deploy.

Для использования скрипта необходимо подготовить файл конфигурации кластера в формате JSON.

2.17.1. Общий формат

tdgctl.py [-h] [-c <файл_конфигурации>] [-v] <команда> [<опции>]

Команды:

Опции, общие для всех команд (далее в описании конкретных команд не упоминаются):

-v, --verbose — вывод полного лога работы команды.

Примечание

Каждая из команд применяется только к тем экземплярам, которые указаны в файле конфигурации, передаваемом через опцию -c.

2.17.2. Команда deploy

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

Формат:

tdgctl.py deploy [-f] [-r] <файл_дистрибутива>

где

 "servers":
 [
     {
         "address": "172.19.0.2",
         "username": "admin",
         "instances":
         [
             {
                 "name": "core_1",
                 "binary_port": 3000,
                 "http_port": 8080,
                 "memory_mb": 128
                 "roles": ["connector", "input_processor"]
             },
             {
                 "name": "storage_1",
                 "binary_port": 3001,
                 "http_port": 8081,
                 "memory_mb": 1024
                 "roles": ["storage"]
             },

2.17.3. Команда upgrade

Используется для функционального обновления экземпляров.

Формат:

tdgctl.py upgrade [-f] <файл_дистрибутива>

где

2.17.4. Команда rm

Используется для удаления экземпляров кластера. При удалении экземпляра также удаляются все его данные.

Формат:

tdgctl.py rm [-y]

где

-y, --yes — опция удаления без запроса подтверждения.

2.17.5. Команда logs

Используется для выгрузки логов всех экземпляров кластера.

Формат:

tdgctl.py logs [-d N]

где

-d N, --days N — опция выгрузки логов не старше N дней.

Для каждого из экземпляров кластера формируется файл лога с именем <instance_name>.log. При старте команды создается директория вида logs.yyyy-mm-ddThh:mm:ssZ, куда складываются все файлы логов, сформированные при данном выполнении команды (yyyy-mm-ddThh:mm:ssZ — дата и время на момент запуска команды).

2.17.6. Команда backup

Используется для резервного копирования данных с экземпляров.

Формат:

tdgctl.py backup [-c]

где

-c, --clear — опция очистки директории для резервных данных перед началом резервного копирования.

Резервные данные сохраняются отдельно для каждого из экземпляров в директории /var/lib/tarantool/<instance_name>.checkpoint/.

В качестве резервных данных система сохраняет следующие файлы для каждого из экземпляров:

2.17.7. Команда restore

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

Формат:

tdgctl.py restore

2.17.8. Команда stop

Используется для остановки экземпляров.

Формат:

tdgctl.py stop [--backup]

где

--backup — опция для выполнения резервного копирования (box.snapshot()).

2.17.9. Команда start

Используется для старта экземпляров.

Формат:

tdgctl.py start

3. Запросы из внешних систем

В этой главе вы познакомитесь с различными видами запросов, обрабатываемых TDG.

Существуют следующие основные типы запросов:

Подробная информация по запросам для доступа к данным находится в разделе Запросы на получение данных.

Описание запросов, изменяющих настройки TDG, приведено в разделе Запросы на изменение настроек.

Содержание

3.1. Запросы к данным

Этот раздел посвящен различным способам обмена данными между TDG и внешними автоматизированными системами.

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

Отправляя соответствующий запрос в TDG, вы можете:

Важно

Получение данных из TDG сразу в ответе на запрос возможно только в GraphQL-запросах. Однако, при соответствующей конфигурации, все виды запросов способны вызывать заранее заложенную логику обработки, включая отправку данных через output_processor.

Далее в этой главе рассмотрено применение запросов для операций с данными в TDG. В целях наглядной иллюстрации будет использоваться следующий базовый пример (см. описание по ссылке https://github.com/tarantool/examples/blob/master/tdg/5/5_Quickstart_guide_TDG.md), который будет дорабатываться в случае необходимости. В примерах этой главы за основу взяты модель данных и конфигурация системы (архив можно забрать по ссылке https://github.com/tarantool/examples/releases/download/untagged-91dd480c7608ccbcd1c0/TDG_config_example_5.zip>) из пятого упражнения по работе с TDG (https://github.com/tarantool/examples/tree/master/tdg/5).

3.1.1. Описание базового примера

Рассматриваемый далее пример использует простую модель данных библиотеки. Имеются объекты следующих типов:

Все объекты в примере имеют логический тип Агрегат («Aggregate» — см. подробнее). При этом объекты Пользователь и Книга связаны с объектом Подписка (в объекте Подписка хранится информация о том, какие книги есть у каких пользователей).

../../../_images/prepare.svg

На языке доменной модели (используемом в TDG) описание этой структуры выглядит следующим образом:

[
    {
        "name": "User",
        "type": "record",
        "logicalType": "Aggregate",
        "doc": "читатель",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "username", "type": "string"}
        ],
        "indexes": ["id"],
        "relations": [
          { "name": "subscription", "to": "Subscription", "count": "many", "from_fields": "id", "to_fields": "user_id" }
        ]
    },
    {
        "name": "Book",
        "type": "record",
        "logicalType": "Aggregate",
        "doc": "книга",
        "fields": [
            {"name": "id", "type": "long"},
            {"name": "book_name", "type": "string"},
            {"name": "author", "type": "string"}
        ],
        "indexes": ["id"],
        "relations": [
          { "name": "subscription", "to": "Subscription", "count": "many", "from_fields": "id", "to_fields": "book_id" }
        ]
    },
    {
    "name": "Subscription",
    "type": "record",
    "logicalType": "Aggregate",
    "doc": "абонемент",
    "fields": [
        {"name": "id", "type": "long"},
        {"name": "user_id", "type": "long"},
        {"name": "book_id", "type": "long"}
    ],
    "indexes": [
      {"name":"pkey", "parts": ["id", "user_id"]},
      "user_id",
      "book_id"
    ],
    "affinity": "user_id",
    "relations": [
      { "name": "user", "to": "User", "count": "one", "from_fields": "user_id", "to_fields": "id" },
      { "name": "book", "to": "Book", "count": "one", "from_fields": "book_id", "to_fields": "id" }
    ]
    }
]

Примечание

Параметр affinity не используется в данном разделе по назначению и достался базовому примеру из пятого упражнения по работе с TDG (https://github.com/tarantool/examples/tree/master/tdg/5). Подробнее про параметр affinity читайте в документации.

3.1.1.1. Подготовка TDG

Для работы с примерами запросов вам потребуется рабочий кластер TDG с загруженной конфигурацией системы и моделью данных.

  1. Выполните установку и настройку кластера TDG в соответствии с инструкциями Установка и запуск и Настройка кластера.

  2. Скачайте архив, который содержит модель данных и конфигурацию системы, по следующей ссылке: https://github.com/tarantool/examples/releases/download/untagged-91dd480c7608ccbcd1c0/TDG_config_example_5.zip. Загрузите архив в TDG согласно инструкции.

В результате у вас должен получиться кластер TDG с полноценным набором ролей: connector, input_processor, storage, account_manager, logger и другие. При этом вышеуказанный архив с конфигурацией содержит рассмотренную ранее модель данных, включающую три агрегата User, Book и Subscription со связями между ними. Кроме модели данных в архиве содержится файл конфигурации системы и файлы с исходными кодами функций обработки данных.

3.1.2. Приём HTTP-запросов

HTTP используется в TDG для работы с графическим (web) интерфейсом и обработки запросов через HTTP API. В данном разделе будет рассмотрено использование HTTP API.

Запросы по протоколу HTTP необходимо направлять по адресу любого из экземпляров TDG с ролью connector на порт, указанный в параметре http_port для данного экземпляра при конфигурации кластера.

В конец адреса после символа / добавляется указание на тип обрабатываемых запросов:

В итоге адрес для отправки запроса в TDG должен приобрести вид полноценного URL адреса, например: http://172.19.0.2:8080/http.

3.1.2.1. Авторизация

Для обработки HTTP-запроса он должен пройти авторизацию, которая осуществляется по токену приложений. Подробнее про получение токена приложений — читайте тут. Токен приложения, сформированный в TDG, необходимо передать в HTTP-заголовке запроса по схеме Authorization: Bearer, где „Authorization“ — имя заголовка, а „Bearer“ — тип токена, например:

Authorization: Bearer ee7fbd80-a9ac-4dcf-8e43-7c98a969c34c

Важно

Токен должен быть сформирован в кластере TDG, к которому осуществляется доступ, иначе он не пройдет авторизацию. Кроме того, ему должны быть выданы соответствующие права для выполнения операций чтения и записи с объектами (агрегатами) модели данных.

3.1.2.2. Обработка запросов

Обработка поступающих запросов описывается в основном файле конфигурации системы. В разделе connector/input указываются каналы, по которым могут поступать входящие запросы (за исключением GraphQL-запросов, которые обрабатываются, даже если не указаны в файле конфигурации, при условии успешной авторизации по токену приложений). Дальнейшая обработка поступивших запросов выполняется в соответствии с конфигурацией, указанной в этом же файле.

3.1.2.3. Отправка запросов

Для отправки запроса в TDG по протоколу HTTP может быть использовано любое средство, включая даже сам TDG. Для простоты демонстрации далее мы используем интерпретатор Python версии 3 с библиотекой requests или программу curl в качестве альтернативного варианта.

Для отправки запроса, в примерах на языке Python вызовите интерпретатор языка Python версии 3 или выше, указав ему на файл скрипта с запросом:

python ./request.py

Примечание

Этот файл должен содержать код отправки HTTP-запроса в TDG. Подробнее в соответствующих разделах для JSON и XML.

В результате выполнения скрипта вы не увидите никаких сообщений об успешном или неуспешном выполнении запроса. Это связано с тем, что в скрипте не предусмотрено подобных проверок и вывода диагностических сообщений (например возвращенного ответа на запрос).

В результате успешного выполнения JSON и XML запросов возвращается только HTTP status code 200 (OK). Это означает только то, что запрос прошёл авторизацию и первичную валидацию.

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

В случае успешной авторизации, но неуспешной обработки запроса — данный запрос попадает в ремонтную очередь.

Получение результатов обработки данных в ответе на JSON или XML запрос невозможно (в отличии от GraphQL).

Проверить факт выполнения вышеуказанного запроса можно, убедившись в достижении результата. В нашем случае для этого убедитесь в том, что в TDG была добавлена запись типа User с id равным 1 и usernameAlex. Наиболее простой способ сделать это — выполнить GraphQL-запрос.

3.1.3. Запросы в формате GraphQL

Рассмотрим обработку запросов в формате GraphQL на основе базового примера. Для отправки запросов используется веб-интерфейс TDG и программа curl. Для приёма и обработки запросов вам понадобится кластер TDG, настроенный ранее.

Основной язык запросов TDG основан на GraphQL. GraphQL запросы можно выполнить с использованием веб-интерфейса на вкладке Graphql или отправив их по протоколу HTTP (с корректным заголовком для авторизации) на адрес вида http://172.19.0.2:8080/graphql, где

Запросы GraphQL делятся на следующие два типа:

Частным случаем запроса на получение данных является запрос на выполнение сервиса. В этом случае также используется тип query, но обращение идет не напрямую к хранящимся в системе данным, а к сервису, в котором можно задать произвольную логику для выборки объектов.

3.1.3.1. Адаптация конфигурации из базового примера

Для выполнения примеров в данном разделе используйте кластер TDG, установка и настройка которого проводились ранее.

Для повторения примеров из данного раздела вам потребуется внести определённые исправления в конфигурацию системы, загруженную ранее.

Прежде всего, внесите изменения в модель данных. Для этого отредактируйте файл model.avsc из архива с конфигурацией системы. Измените описание объекта с именем User так, чтобы оно стало следующим:

{
  "name": "User",
  "type": "record",
  "logicalType": "Aggregate",
  "doc": "читатель",
  "fields": [
    {
      "name": "id",
      "type": "long"
    },
    {
      "name": "username",
      "type": "string"
    },
    {
      "name": "phones",
      "type": {
        "type": "array",
        "items": "string"
      }
    }
  ],
  "indexes": [
    "id",
    "phones"
  ],
  "relations": [
    {
      "name": "subscription",
      "to": "Subscription",
      "count": "many",
      "from_fields": "id",
      "to_fields": "user_id"
    }
  ]
}

Также внесите изменение в описание объекта Book так, чтобы оно стало следующим:

{
  "name": "Book",
  "type": "record",
  "logicalType": "Aggregate",
  "doc": "книга",
  "fields": [
    {
      "name": "id",
      "type": "long"
    },
    {
      "name": "book_name",
      "type": "string"
    },
    {
      "name": "author",
      "type": "string"
    },
    {
      "name": "year",
      "type": "int"
    }
  ],
  "indexes": [
    "id",
    "year"
  ],
  "relations": [
    {
      "name": "subscription",
      "to": "Subscription",
      "count": "many",
      "from_fields": "id",
      "to_fields": "book_id"
    }
  ]
}

Затем повторно заархивируйте новую модель с остальными файлами конфигурации и повторите загрузку конфигурации системы согласно инструкции для обновления модели данных.

3.1.3.2. Запрос на получение данных

Все агрегаты (объекты логического типа «Aggregate» — см. подробнее раздел о модели данных) доступны для запроса по имени типа. Общий вид GraphQL-запроса на получение данных следующий:

query {
  aggregate_name {
    fields
  }
}

где

Для возвращаемого объекта можно указывать произвольный набор полей, который вы хотите получить, т.е. необязательно указывать все поля, описанные для данного агрегата в модели данных. Поля могут разделяться запятой, пробелом или переносом строки.

Примечание

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

3.1.3.2.1. Пример выполнения запроса через веб-интерфейс

Для выполнения GraphQL-запросов проще всего использовать встроенный веб-клиент на вкладке Graphql в веб-интерфейсе TDG. Для выполнения простого запроса на получение данных для нашего базового примера введите следующий запрос:

{
  User {
    id
    username
  }
}

Обратите внимание, что в фигурных скобках указан тип объекта (Агрегата) User. Далее в отдельных фигурных скобках указаны его поля id и username для их отображения в получаемом ответе.

3.1.3.2.2. Пример выполнения запроса через HTTP-запрос

Также вы можете выполнить запрос, отправив его в input_processor TDG по протоколу HTTP. Для выполнения запроса при помощи утилиты curl используйте следующую команду в консоли.

curl --request POST \
  --url http://172.19.0.2:8080/graphql \
  --header 'Authorization: Bearer ee7fbd80-a9ac-4dcf-8e43-7c98a969c34c' \
  --data '{"query":"{User{id,username}}"}'

Примечание

Используйте в качестве значения для параметра Authorization: Bearer токен приложений, сгенерированный заранее.

В качестве ответа возвращается объект JSON, содержащий массив со всеми записями типа User, при этом для каждой записи будут указаны поля id и username.

{
  "data": {
    "User": [
      {
        "id": 1,
        "username": "John Smith"
      },
      {
        "id": 2,
        "username": "Adam Sanders"
      }
    ]
  }
}

Если в качестве fields указать пустой список, то система также вернет пустой объект, т.к. GraphQL возвращает именно то, что было указано в запросе.

3.1.3.3. Выборка агрегатов

Отдельно взятый агрегат можно выбрать по индексу. Для этого индексированное поле нужно указать в качестве аргумента запроса. В примере ниже агрегат User выбирается по индексу id (см. описание модели). Проверка условия выполняется на полное совпадение.

{
  User(id: 1) {
    id
    username
  }
}

Примечание

Для запросов такого рода доступны только индексированные поля. Фильтровать по обычным (неиндексированным) полям таким способом не получится.

В одном запросе можно указывать несколько индексов. В таком случае запрос будет искать объекты, удовлетворяющие всем условиям одновременно (логическая операция конъюнкция или логическое И).

query {
  Subscription(user_id: 1, book_id: 3) {
    id
    user_id
    book_id
  }
}

Для запроса по составному (мультиколоночному) индексу используется массив значений. В нашем примере у агрегата типа Subscription есть составной индекс pkey, включающий в себя поля id и user_id. Пример запроса по этому индексу выглядит так:

{
  Subscription(pkey: [2, 1]) {
    id
    book_id
    user_id
  }
}

3.1.3.4. Мультиключевые индексы

Отдельно нужно отметить запросы по так называемому мультиключевому индексу (multikey index), т.е. индексу по полю, содержащему массив. Для иллюстрации возьмем за основу наш пример, в который test такое поле (phones) и соответствующий индекс к агрегату User. Поле phones будет содержать массив, в котором хранятся все телефонные номера читателя.

Примечание

Мультиключевой индекс не может быть первичным.

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

3.1.3.4.1. Пример запроса с мультиключевым индексом

Допустим, необходимо сделать выборку читателей (User), телефоны которых начинаются с определенного кода страны, например, «+7». У читателя с id = 1 таких телефонов два:

{
  "id": 1,
  "username": "John Smith",
  "phones": [
    "+74951234567",
    "+79997654321",
    "+19001234567"
  ]
}

Соответственно запрос по индексу phones для такого случая вернет агрегат типа User c id = 1 дважды

Выполните следующий запрос на вкладке Graphql веб-интерфейса TDG.

{
  User(phones_like: "+7%") {
    id
    username
    phones
  }
}

В результате вы получите следующий ответ.

{
  "data": {
    "User": [
      {
        "username": "John Smith",
        "phone": [
          "+74951234567",
          "+79997654321",
          "+19001234567"
        ],
        "id": 1
      },
      {
        "username": "John Smith",
        "phone": [
          "+74951234567",
          "+79997654321",
          "+19001234567"
        ],
        "id": 1
      }
    ]
  }
}

3.1.3.5. Выборка со сравнением

Выборки поддерживают операции сравнения в виде суффиксов в именах индексов.

Поддерживаются следующие операторы сравнения:

Формат запросов:

{
  aggregate_name(index_gt: value) {
    fields
  }
}

где

3.1.3.5.1. Примеры выборки со сравнением

Например, для получения всех книг, выпущенных после 2008 года, используйте следующий запрос.

{
  Book(year_gt: 2008) {
    book_name
    year
    author
  }
}

Данные суффиксы также поддерживаются для составных индексов и multikey индексов. Предположим, что есть индекс, содержащий в себе такие части, как year и month. Тогда для получения книг, выпущенных после июля 2008 года, выполните следующий запрос.

{
  Book(year_month_gt: [2008, 7]) {
    book_name
    year
    author
  }
}

Примечание

Используемая в нашем примере модель данных не предполагает поля month, но вы можете попробовать добавить его сами (по аналогии с этим разделом) и выполнить вышеуказанный запрос для закрепления практических навыков.

Операторы сравнения для индексов по строковым полям работают в соответствии с правилами сортировки (collation), принятыми в Tarantool.

Также для индексов по строковым полям поддерживается оператор _like — для поиска заданного шаблона в строке. В шаблоне можно использовать подстановочный знак (wildcard) %, который представляет любое количество любых символов. Для примера выполните следующий запрос.

{
  User(phones_like: "+7%") {
    id
    username
    phones
  }
}

3.1.3.6. Выборка агрегатов по связям

Для фильтрации связанных агрегатов используется тот же синтаксис, что и для выборки обычных агрегатов.

В используемом базовом примере агрегаты User и Subscription связаны отношением «один ко многим». Соответственно, в одном запросе можно получить одновременно и данные читателя, и информацию о его подписках (или об отдельно взятой подписке, как в примере ниже).

{
  User(id: 1) {
    id
    username
    phones
    subscription(pkey: [2, 1]) {
      id
      book_id
    }
  }
}

Данный вид запроса аналогичен SQL LEFT OUTER JOIN.

Как объясняется в разделе про отношения между объектами, отношения могут быть односторонними или полными (двусторонними). В нашем примере в модели данных заданы двусторонние отношения (например, поле relations определено и у User, и у Subscription), поэтому также возможен запрос «с другой стороны» — т.е. запрашивая данные по какому-то из абонементов/подписок, в этом же запросе можно получить и данные читателя. В качестве примера выполните следующий запрос.

{
  Subscription(pkey: [2, 1]) {
    id
    book_id
    user {
      id
      username
      phones
    }
  }
}

3.1.3.7. Пагинация

Для пагинации используется метод с непрозрачными курсорами, аналогичный описанному в документации по GraphQL (https://graphql.org/learn/pagination/#pagination-and-edges).

В общем виде запрос выглядит так:

{
  aggregate_name(first: 2, after: $cursor)
}

где:

В after как раз и передается «непрозрачный курсор». Непрозрачный курсор — это строка, о смысле которой пользователь не должен задумываться. Все, что нужно знать — это то, что, используя эту строку, сервер может продолжить выполнение запроса с нужного места.

Каждый агрегат имеет специальное синтетическое поле cursor, доступное через GraphQL. В дизайне пагинации TDG было решено перенести cursor на уровень агрегата, что позволяет не вводить промежуточных уровней запроса edges и node, как это предлагается делать в руководстве по GraphQL (https://graphql.org/learn/pagination/#pagination-and-edges).

3.1.3.7.1. Примеры использования пагинации

В качестве примера первого запроса с пагинацией выполните следующий запрос.

{
  User(first: 2) {
    id
    username
    cursor
  }
}

Полученный ответ будет напоминать следующий.

{
  "data": {
    "User": [
      {
        "cursor": "gaRzY2Fuk6ABzxYAPuJNoseB",
        "username": "John Smith",
        "id": 1
      },
      {
        "cursor": "gaRzY2Fuk6ACzxYAEQtuI8e5",
        "username": "Adam Sanders",
        "id": 2
      }
    ]
  }
}

Теперь, чтобы продолжить получение следующей порции данных, возьмите поле cursor из последнего полученного объекта (в данном случае — "gaRzY2Fuk6ACzxYAEQtuI8e5") и передайте его в аргумент after, выполнив следующий запрос.

{
  User(first: 2, after: "gaRzY2Fuk6ACzxYAEQtuI8e5") {
    id
    username
    cursor
  }
}

Для обратной пагинации необходимо использовать отрицательное число first. В этом случае система вернет предыдущие объекты относительно after. Обратная пагинация некольцевая: с помощью неё нет возможности получить последний объект множества выборки, смещаясь от первого.

Пагинация также доступна для запроса по связям. Например:

{
  User(id: 1) {
    id
    username
    phones
    subscription(first: 2) {
      id
      book_id
    }
  }
}

3.1.3.8. Версионирование и запрос исторических данных

Основные принципы версионирования данных в TDG указаны тут.

Для передачи и запроса версии используется служебное поле version. Важно отметить, что если в запросе не указывается версия, то возвращается последняя (наибольшая) версия.

Количество хранимых версий можно ограничить через конфигурацию системы. По умолчанию количество не ограничено.

3.1.3.8.1. Пример запроса с использованием исторических данных

Допустим в результате одного из запросов у записи типа User с id равным 1 был удалён один из номеров телефона (записана новая версия данных без этого номера).

Нужно получить предыдущую версию, где есть удаленный номер телефона.

В таком случае сделайте запрос на получение последней версии агрегата (не указывая, какую версию хотите получить), и добавьте в вывод значение поля version:

{
  User(id: 1) {
    id
    username
    phones
    version
  }
}

В ответ будет получен следующий или подобный JSON:

{
  "data": {
    "User": [
      {
        "version": "1585393144680150551",
        "username": "John Smith",
        "phones": [
          "+74951234567",
          "+79997654321"
        ],
        "id": 1
      }
    ]
  }
}

Берем значение «version»: «1585393144680150551», вычитаем из него 1, получаем «version»: «1585393144680150550», и указываем это значение как аргумент в повторном запросе.

{
  User(id: 1, version: 1585393144680150550) {
    id
    username
    phones
    version
  }
}

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

{
  "data": {
    "User": [
      {
        "version": "1585392369718590708",
        "username": "John Smith",
        "phones": [
          "+74951234567",
          "+79997654321",
          "+19001234567"
        ],
        "id": 1
      }
    ]
  }
}

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

Также возможно запросить все версии агрегата через аргумент all_versions:

{
  User(id: 1, all_versions: true) {
    id
    username
    version
  }
}

При использовании аргумента all_versions можно, конечно же, ограничить количество возвращаемых версий агрегата при помощи пагинации.

{
  User(id: 1, all_versions: true, first: 3) {
    id
    username
    version
  }
}

3.1.3.9. Ограничения запросов

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

Данные ограничения превентивно требуют качественного написания запросов, являясь по сути аналогом профилирования медленных запросов.

Настройка данных параметров возможна при конфигурации системы или с помощью специальных запросов и мутаций GraphQL.

3.1.3.10. Изменение данных

TDG поддерживает следующие запросы на изменение данных (мутации):

3.1.3.10.1. Вставка объекта

Общий вид запроса на вставку (добавление или обновление) объекта:

mutation {
  aggregate_name(insert: {JSON_input_object}) {
    fields
  }
}

где:

  • mutation — объявление типа запроса как запрос на изменение данных (мутация);

  • aggregate_name — имя агрегата;

  • JSON_input_object — объект для вставки в формате JSON. Необходимо указать все обязательные поля и их значения. Обязательными являются поля, описанные в модели данных для этого агрегата, тип которых отличен от «null»;

  • fields — (опционально) список полей возвращаемого объекта.

3.1.3.10.1.1. Пример запроса на вставку объекта

Для добавления нового или обновления существующего (если объект с таким первичным ключом уже есть) объекта перейдите на вкладку Graphql и выполните следующий запрос:

mutation {
  User(
    insert: {
      id: 1
      username: "John Smith"
      phones: ["+74951234567", "+79997654321"]
    }
  ) {
    id
    username
    phones
  }
}

В качестве альтернативы вы можете отправить HTTP-запрос, например при помощи программы curl. Для этого выполните следующую команду.

curl --request POST \
   --url 'http://172.19.0.2:8080/graphql?=' \
   --header 'Authorization: Bearer ee7fbd80-a9ac-4dcf-8e43-7c98a969c34c' \
   --data '{"query":"   mutation {User(insert: {id: 1, username: \"John Smith\", phones:[\"+74951234567\", \"+79997654321\"]}) {id username phones}}"}'

Примечание

Символ \" нужен при работе из командной строки для корректной обработки символов кавычек в команде.

Примечание

Используйте в качестве значения для параметра Authorization: Bearer токен приложений, сгенерированный заранее.

Какой бы способ выполнения запроса вы ни выбрали, в результате вы получите следующий ответ:

{
  "data": {
    "User": [
      {
        "username": "John Smith",
        "phones": [
          "+74951234567",
          "+79997654321"
        ],
        "id": 1
      }
    ]
  }
}

3.1.3.10.1.2. Пример запроса на вставку с оптимистичной блокировкой

В запросах могут использоваться оптимистичные блокировки. Для этого используйте параметр only_if_version, как это показано в следующем примере:

mutation {
  User(
    insert: {
      id: 1
      username: "John Smith"
      phones: ["+74951234567", "+79997654321"]
    }
    only_if_version: 1585392369718590708
  ) {
    id
    username
    phones
  }
}

3.1.3.10.2. Обновление объекта

Общий вид запроса на обновление объекта:

mutation {
  aggregate_name(update: filter [[mutator, path, new_value], ...]) {
    fields
  }
}

где:

  • mutation — объявление типа запроса как запроса на изменение данных (мутация);

  • aggregate_name — имя агрегата;

  • filter — список условий-предикатов для выбора объектов указанного типа;

  • [[mutator, path, new_value], ...] — список мутаторов:

    • mutator — имя мутатора. Возможные значения: set (устанавливает значение), add (увеличивает значение на указанное число), sub (уменьшает значение на указанное число);

    • path — строковый путь до поля объекта с точкой-разделителем (.). Путь до объекта массива должен включать индекс массива или символ * для захвата всех дочерних объектов;

    • new_value — новое значение.

  • fields — список полей возвращаемого объекта.

3.1.3.10.2.1. Пример запроса на обновление объекта

Обновим ранее добавленный объект типа User — изменим значение поля username. Нужный объект данного типа выберем по первичному ключу id. Перейдите на вкладку Graphql и выполните следующий запрос:

mutation {
  User(id:1 update:[["set", "username", "John D. Smith"]]) {
    id
    username
    phones
  }
}

В качестве альтернативы вы можете отправить HTTP-запрос, например, при помощи программы curl. Для этого выполните следующую команду:

curl --request POST \
  --url 'http://172.19.0.2:8080/graphql?=' \
  --header 'Authentication: Bearer ee7fbd80-a9ac-4dcf-8e43-7c98a969c34c' \
  --data '{"query":"mutation {User(update: id: 1 [[\"set\", \"username\", \"John D. Smith\"]]) {id username phones}}"}'

Примечание

  • Символ \" нужен при работе из командной строки для корректной обработки символов кавычек в команде.

  • Для параметра Authentication: Bearer используйте в качестве значения токен приложений, сгенерированный заранее.

Какой бы способ выполнения запроса вы ни выбрали, в результате вы получите следующий ответ:

{
  "data": {
    "User": [
      {
        "username": "John D. Smith",
        "phones": [
          "+74951234567",
          "+79997654321"
        ],
        "id": 1
      }
    ]
  }
}

3.1.3.10.3. Удаление объектов

Общий вид запроса на удаление объекта:

mutation {
  aggregate_name(delete: true) {
    fields
  }
}

где:

  • aggregate_name — имя агрегата. В качестве аргумента указывается delete: true. Остальные аргументы опциональны: их можно использовать, чтобы задавать логику того, что нужно удалить (например значение одного из ключей или only_if_version);

  • fields — (опционально) возвращаемые поля.

3.1.3.10.3.1. Примеры запросов на удаление объектов

Если не указаны другие аргументы помимо delete: true, будут удалены все объекты данного типа, например:

mutation {
  User(delete: true) {
    id
    username
  }
}

В результате вы получите следующий или подобный ответ, а все перечисленные объекты будут удалены.

{
  "data": {
    "User": [
      {
        "username": "John Smith",
        "id": 1
      },
      {
        "username": "Adam Sanders",
        "id": 2
      }
    ]
  }
}

Для выборочного удаления можно использовать все те же аргументы, которые используются для фильтрации в запросах на получение данных.

Например, удаление выборочного объекта по первичному ключу:

mutation {
  User(delete: true, id: 1) {
    id
    username
  }
}
3.1.3.10.3.1.1. Полное удаление

При обычном удалении информация об объекте помечается признаком удаления и перестаёт учитываться при выборках. Однако существует способ полного удаления информации из TDG без сохранения каких-либо данных, включая различные версии.

Для этого в запросе на удаление укажите параметр permanent_delete: True. Логика его работы совпадает с описанной для такого параметра в данном разделе.

3.1.3.11. Выполнение сервисов

GraphQL-запросы дают возможность вызова сервисов в TDG.

Общий вида запроса на выполнение сервиса:

query {
  service_name(arg1: value1, arg2: value2, ...)
}

3.1.3.11.1. Пример запроса на выполнение сервиса

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

services:
  select_user_books:
    doc: "select_user_books"
    function: select_user_books
    return_type: string
    args:
      user_id: long

Для вызова этого сервиса используйте следующий запрос:

{
  select_user_books(user_id: 1)
}

В ответе на данный запрос вернется результат вызова сервиса:

{
  "data": {
    "select_user_books": "[1, 3]"
  }
}

Как видно, в ответе действительно имеется массив с идентификаторами (id) всех книг, которые взял пользователь с user_id = 1.

3.1.4. Запросы в формате JSON

Рассмотрим обработку запросов в формате JSON на основе базового примера. Для отправки запросов мы используем простые скрипты на языке Python. Для приёма и обработки запросов нам понадобится кластер TDG, настроенный ранее.

3.1.4.1. Адаптация конфигурации из базового примера

Поскольку базовый пример использует JSON, то адаптация конфигурации системы из базового примера не потребуется.

3.1.4.2. Описание процесса обработки запроса

Логика обработки поступающего запроса изложена в файле конфигурации системы config.yml и состоит в следующем:

Обратите внимание, что вся лишняя информация, не относящаяся к типу объекта, описанному в модели данных, не будет сохранена.

Из всего файла конфигурации системы остался не рассмотренным участок, отвечающий за сервисы. В данном примере там описан простой сервис, вызывающий функцию select_user_books с аргументом user_id и возвращающий строковую переменную.

Логика работы этой функции такова: переданное значение user_id используется для поиска в объекте Subscription всех книг, записанных за данным пользователем. Затем выводятся все найденные book_id.

3.1.4.3. Подготовка запроса в формате JSON

Создайте файл request.py со скриптом на языке Python для отправки простейшего запроса с полями объекта типа User (из нашей модели данных: это поля id и username), который будет выглядеть следующим образом:

import requests

data = {'username' : 'John Smith', 'id' : 1}
header = {'Authorization' : 'Bearer ee7fbd80-a9ac-4dcf-8e43-7c98a969c34c'}

r = requests.post(url = "http://172.19.0.2:8080/http", json = data, headers = header)

Примечание

Используйте в качестве значения для параметра Authorization: Bearer токен приложений, сгенерированный ранее.

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

Процедура отправки запроса и ожидаемые результаты описаны ранее в пункте Отправка запросов.

3.1.5. Запросы в формате XML (SOAP)

Рассмотрим обработку запросов в формате XML (SOAP) на основе базового примера. Для отправки запросов мы используем простые скрипты на языке Python. Для приёма и обработки запросов нам понадобится кластер TDG, настроенный ранее.

3.1.5.1. Адаптация конфигурации из базового примера

Для повторения примеров из данного раздела нам потребуется внести определенные исправления в конфигурацию системы, загруженную ранее.

Разархивируйте архив с конфигурацией системы в отдельную директорию. Откройте файл config.yml и измените его так, чтобы он содержал следующий текст:

types:
  __file: model.avsc

functions:
  router: {__file: router.lua}

  classifier: {__file: classificator.lua}

  select_user_books: {__file: select_user_books.lua}

  process_user: {__file: process_user.lua}

  process_book: {__file: process_book.lua}

  process_sub: {__file: process_sub.lua}

pipelines:
  router:
    - router
  classifier:
    - classifier
  select_user_books:
    - select_user_books
  process_user:
    - process_user
  process_book:
    - process_book
  process_sub:
    - process_sub

connector:
  input:
    - name: soap
      type: soap
      wsdl: {__file: example.wsdl}
      handlers:
        - function: Connect
          pipeline: router

  routing:
    - key: input_key
      output: to_input_processor

  output:
    - name: to_input_processor
      type: input_processor

input_processor:
  classifiers:
    - name: classifier
      pipeline: classifier

  routing:
    - key: process_user
      pipeline: process_user
    - key: process_book
      pipeline: process_book
    - key: process_sub
      pipeline: process_sub

  storage:
    - key: add_user
      type: User
    - key: add_book
      type: Book
    - key: add_subscription
      type: Subscription

services:
  select_user_books:
    doc: "select_user_books"
    function: select_user_books
    return_type: string
    args:
      user_id: long

Обратите внимание на появившийся раздел input_processor/routing и связанные с ним описания новых конвейеров обработки данных (pipeline) и функций. При этом модель данных не изменилась. В разделе connector появилось описание входа с типом SOAP, функцией Connect (не являющейся функцией TDG, но описываемой в XML/SOAP) и связанным с ней конвейером (уже известным нам по примеру с JSON — router).

Примечание

В секции wsdl: обязательно указывается файл спецификации веб-сервиса с расширением .wsdl. В нашем примере это example.wsdl. Данный файл должен обязательно быть включен в состав архива с конфигурацией системы. В том случае, если WSDL не используется, данный файл может быть пустым.

Теперь откройте файл classificator.lua и отредактируйте его так, чтобы он имел следующее содержимое:

#!/usr/bin/env tarantool

    local param = ...

    if (param.obj[1].tag == "username" or param.obj[2].tag == "username") then
        param.routing_key = "process_user"
        return param
    end

    if (param.obj[1].tag == "book_name" or param.obj[2].tag == "book_name") then
        param.routing_key = "process_book"
        return param
    end

    if ((param.obj[1].tag == "user_id" and param.obj[2] == "book_id") or (param.obj[2].tag == "user_id" and param.obj[1].tag == "book_id")) then
        param.routing_key = "process_sub"
        return param
    end

    param.routing_key = "unknown_type"
    return param

Создайте файлы process_user.lua, process_book.lua и process_sub.lua. Содержимое этих файлов — скрипт обработки данных, который должен формировать из получаемого TDG информационного объекта объект, соответствующий описанному в модели данных.

Далее приведен пример содержимого файла process_user.lua. Остальные файлы выполняются по аналогии.

#!/usr/bin/env tarantool

local param = ...

local id = param.obj[1][1]

local username = param.obj[2][1]

local data = {id = tonumber(id), username = username}

local ret = {obj = data, priority = 1, routing_key = 'add_user'}

return ret

Сформированный вышеуказанным скриптом объект должен содержать поля id и username, так как он получит routing_key для добавления объекта типа User в хранилище.

Важно

Для сохранения TDG ожидает объект в формате, представленном выше, где obj включает в себя весь информационный объект в виде перечисленных через запятую пар key = value, где для каждого обязательного поля объекта в модели данных задан одноимённый ключ (key) с непустым значением.

Закончив с подготовкой файлов, упакуйте их в zip-архив и загрузите его согласно инструкции.

3.1.5.2. Описание процесса обработки запроса

Логика обработки поступающего запроса изложена в файле конфигурации config.yml и состоит в следующем:

Обратите внимание, что вся лишняя информация, не относящаяся к типу объекта, описанному в модели данных, не будет сохранена.

Из всего файла конфигурации системы остался не рассмотренным участок, отвечающий за сервисы. В данном примере там описан простой сервис, вызывающий функцию select_user_books с аргументом user_id и возвращающий строковую переменную.

Логика работы этой функции такова — переданное значение user_id используется для поиска в объекте Subscription всех книг, записанных за данным пользователем. Затем выводятся все найденные book_id.

3.1.5.3. Подготовка запроса в формате SOAP (XML)

Создайте файл request.py со скриптом на языке Python для отправки простейшего запроса с полями объекта типа User (из нашей модели данных: это поля id и username), который будет выглядеть следующим образом:

import requests

data = """<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <NS2:Connect xmlns:NS2="http://172.19.0.2:8080/soap">
      <id>1</id>
      <username>John Smith</username>
    </NS2:Connect>
  </soap:Body>
</soap:Envelope>"""

header = {'Authorization' : 'Bearer c0b26a60-aebe-4899-9ab6-4458627ac61e'}

r = requests.post(url = "http://172.19.0.2:8080/soap", data = data, headers = header)

Передаваемый запрос содержит заголовок для авторизации и тело в виде SOAP объекта с обязательными полями для объекта модели данных типа User.

Примечание

Используйте в качестве значения для параметра Authorization: Bearer токен приложений, сгенерированный ранее.

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

Процедура отправки запроса и ожидаемые результаты описаны ранее в пункте Отправка запросов.

3.1.6. Взаимодействие с kafka

Рассмотрим настройку взаимодействия TDG по протоколу Kafka.

TDG может быть настроен как в качестве consumer (роль connector, секция input), так и в качестве producer (роль connector, секция output) в терминологии Kafka.

В целях простой демонстрации возможности взаимодействия с Kafka, в данном примере мы обеспечим получение объекта из заданной темы (topic), его небольшую модификацию и отправку обратно в ту же тему. В результате можно будет наблюдать рекурсивную переотправку модифицируемых объектов.

Для завершения рекурсивной обработки необходимо будет выключить Kafka или TDG, либо загрузить в TDG новую корректную конфигурацию без рекурсивной отправки с получением.

Для выполнения примера нам понадобится кластер TDG, настроенный ранее.

3.1.6.1. Конфигурация

Создайте файл config.yml и измените его так, чтобы он содержал следующий текст:

types:
  __file: model.avsc

functions:
  kafka_hlr: {__file: kafka_handler.lua}

pipelines:
  kafka_handler:
    - kafka_hlr

connector:
  input:
    - name: from_kafka
      type: kafka
      brokers:
        - localhost:9092
      topics:
        - items
      group_id: kafka
      pipeline: kafka_handler

  routing:
    - key: input_key
      output: to_kafka

  output:
    - name: to_kafka
      type: kafka
      brokers:
        - localhost:9092
      topic: items

Обратите внимание, в разделе connector имеется описание входа с типом kafka, реализующего роль consumer в терминологии Kafka, для которого указаны такие параметры как:

В разделе output появилось описание исходящего маршрута с типом kafka, реализующего роль producer в терминологии Kafka, для которого указаны следующие параметры:

Объекты в данном примере не сохраняются локально, поэтому модель данных может быть пустой. Создайте пустой файл model.avsc.

Вся обработка данных ведется конвейером kafka_handler в файле kafka_handler.lua.

Создайте файл kafka_handler.lua и наполните его следующим содержанием.

#!/usr/bin/env tarantool

local param = ...

param.version = param.version + 1

local ret = {obj = param, priority = 1, routing_key = 'input_key'}

return ret

Содержимое этого файла — скрипт обработки данных, который получает на вход JSON, поступивший из Kafka. В этом файле можно выполнить предварительную обработку поступившей информации, а также обернуть данные в JSON с ключом routing_key для дальнейшей обработки (см. подробнее).

Важно

Kafka коннектор в TDG поддерживает только валидные JSON объекты.

Сейчас в данном файле приведен пример простейшей модификации (увеличение числа, содержащегося в поле version, которое было получено из Kafka JSON) и оборачивания данного модифицированного JSON в формат для дальнейшей обработки с ключом routing_key равным input_key.

Закончив с подготовкой файлов, упакуйте их в zip-архив и загрузите его согласно инструкции.

3.1.6.2. Описание процесса обработки запроса

Логика обработки данного примера изложена в файле конфигурации config.yml и состоит в следующем:

Обратите внимание, что сохранения информации в системе не происходит. Обработка объекта прекращается с отправкой его во внешнюю систему, поэтому в ремонтную очередь ничего не добавляется.

3.1.6.3. Запуск рекурсивной отправки Kafka

Для выполнения действий с Kafka необходимо установить и запустить сервер Kafka, а также создать в нем тему (topic) с именем items. Для этого следуйте инструкции из официальной документации по Kafka (http://kafka.apache.org/quickstart), изменив название темы на items.

В целях наглядной демонстрации работы примера и просмотра сообщений, передаваемых в выбранную тему (topic) Kafka, используйте любой consumer Kafka, подключенный к тому же брокеру и теме items.

Далее мы рассмотрим использование модуля kafka-python, установить который можно командой pip install kafka-python. Тогда для просмотра сообщений Kafka выполните следующий скрипт на языке Python (используя интерактивный режим интерпретатора или сохранив его в файл consumer.py и запустив командой python consumer.py):

from kafka import KafkaConsumer
consumer = KafkaConsumer('items')
for message in consumer:
    print (message)

Примечание

Для запуска скриптов потребуется Python версии 3 и выше, запуск которого в вашей системе может выполняться командой python3.

Для начала демонстрации примера необходимо отправить в Kafka валидный JSON объект с полем version. Откройте новую консоль (оставив работать consumer, запущенный ранее) и выполните следующий скрипт на языке Python (используя интерактивный режим интерпретатора или сохранив в файл его в файл producer.py и запустив командой python producer.py):

from kafka import KafkaProducer
producer = KafkaProducer(bootstrap_servers='localhost:9092')
producer.send('items', b'{"id": "tarantool", "version": 0}')

Данный скрипт содержит подключение к Kafka в качестве producer и отправку простого JSON объекта: {"id": "tarantool", "version": 0}.

В случае успеха TDG получит данный объект, обработает (увеличив значение поля «version») и отправит его в ту же тему Kafka, вызывая повторное получение, обработку, отправку и так далее. В окне с consumer при этом будут появляться все новые сообщения с постоянно возрастающим значением поля version.

Примечание

Для остановки рекурсивной отправки сообщений из TDG вам придется загрузить другую корректную конфигурацию в TDG, либо отключить TDG или Kafka.

3.2. Запросы на изменение настроек

Этот раздел посвящен различным запросам, позволяющим изменять настройки TDG.

Все запросы на изменение настроек TDG передаются по протоколу HTTP в формате GraphQL.

При этом они должны иметь соответствующий заголовок для авторизации.

Примечание

Для выполнения GraphQL-запросов можно использовать встроенный веб-клиент GraphiQL (на вкладке Graphql веб-интерфейса) или любой сторонний GraphQL-клиент, либо иное средство для отправки HTTP-запросов. При этом специализированные GraphQL-клиенты, в отличие от средств отправки HTTP-запросов, могут использовать функции автодополнения и проверки синтаксиса запросов, а также автоматического формирования документации на GraphQL API. Данные стандартные возможности GraphQL позволяют определять состав функций API, а также состав аргументов функций, типы исходных данных и возвращаемых результатов.

GraphQL-запросы от клиентов (за исключением встроенного веб клиента GraphiQL) необходимо направлять на соответствующие адреса (endpoints):

Данные по аргументам вызова функций и возвращаемым результатам не приводятся, исходя из того, что GraphQL обладает встроенными механизмами обмена этой информацией с клиентским программным обеспечением, выполняющим запросы. Описания параметров и аргументов приведены в исключительном порядке для отдельных случаев, требующих пояснения.

3.2.1. Основные настройки TDG

Для выполнения запроса, его необходимо направить по протоколу HTTP на HTTP-порт любого экземпляра кластера с указанием адреса ресурса (endpoint) /graphql и заголовком admin, а также данными авторизации.

Пример выполнения запроса при помощи утилиты curl:

curl --request POST \
  --url http://172.19.0.2:8080/graphql \
  --header 'Authorization: Bearer 2fc136cf-8cae-4655-a431-7c318967263d' \
  --header 'schema: admin' \
  --data '{"query":"query{  user{  list{  username  }  }  }  "}'

Далее приведены все типы запросов на чтение или изменение основных настроек TDG. Для некоторых запросов дополнительно указаны возвращаемые значения и пояснения к ним.

3.2.1.1. Запросы на получение информации по текущим настройкам и состоянию (query)

  • jobs — чтение ремонтной очереди неудавшихся отложенных работ (попытка выполнения которых закончилась неудачно, вкладка Failed jobs):

    • get_list — возвращает список объектов ремонтной очереди отложенных работ;

  • repair_list — возвращает список объектов, находящихся в ремонтной очереди (вкладка Repair);

  • get_logs — возвращает записи общего журнала событий (логи);

  • tasks — чтение списка задач:

    • get_list — возвращает список задач и результатов их исполнения;

  • password_generator — генерация и проверка валидности паролей, чтение настроек требований к сложности паролей:

    • generate — возвращает сгенерированный пароль;

    • validate — выполняет проверку переданного пароля на соответствие имеющимся требованиям к сложности пароля;

    • config — возвращает текущие настройки требований к сложности пароля;

  • output_processor — чтение данных ремонтной очереди объектов на отправку (вкладка Output Processor):

    • get_list — возвращает список объектов в ремонтной очереди на отправку (объекты, отправка которых не удалась);

  • servers — возвращает информацию о состоянии экземпляров TDG в кластере;

  • access_role — чтение настроек ролевой модели:

    • actions_list — возвращает список всех возможных действий, доступ к которым настраивается при помощи ролевой модели;

    • get_access_role_actions — возвращает список действий, доступных для роли по ее id;

    • list — возвращает список ролей;

    • get — возвращает данные о роли по ее id;

  • cartridge — чтение данных из конфигурации:

    • test_soap_data — возвращает текст подсказки по умолчанию на вкладке Test веб-интерфейса;

    • self — отображает информацию о текущем сервере (экземпляре TDG);

  • data_access_action — чтение информации о шаблонах доступа к действиям над данными:

    • list — возвращает список настроенных шаблонов доступа;

    • get — возвращает информацию о шаблоне по его id;

  • user — чтение информации о пользователях и настройке доступа анонимных пользователей:

    • is_anonymous_allowed — возвращает статус настройки, разрешающей доступ без авторизации;

    • self — возвращает информацию о текущем пользователе;

    • list — возвращает список пользователей;

  • model — возвращает модель данных в виде строки;

  • notifier_get_users — возвращает список подписчиков (вкладка Subscribers);

  • audit_log — чтение данных о журнале событий безопасности:

    • get — возвращает журнал событий безопасности (аудит лог);

    • enabled — возвращает статус настройки, отвечающей за включение и отключение ведения журнала аудита;

  • maintenance — чтение служебной информации:

    • clock_delta — данные по рассинхронизации времени на внутренних (системных) часах экземпляров. Может возвращать следующие значения:

      • value — возвращает максимальное текущее значение отклонения часов между экземплярами кластера;

      • is_threshold_exceeded — отвечает на вопрос, превышено ли предельное значение отклонения часов среди экземпляров кластера;

    • get_aggregates — возвращает список агрегатов модели данных;

    • tdg-version — проверяет версию TDG при применении конфигурации (только в схеме admin);

    • unlinked_space_list — возвращает список агрегатов, которые были удалены из модели, но при этом в хранилище остались их сохраненные данные;

  • token — чтение информации о токенах приложений:

    • list — выводит список всех токенов приложений;

    • get — выводит информацию о токене по его имени;

  • get_mail_servers — возвращает настройки почтового сервера для отправки оповещений;

  • expiration — чтение настроек устаревания данных:

    • get_list — возвращает настройки устаревания данных для всех агрегатов модели данных;

  • config — чтение настроек кластера:

    • vshard-timeout — возвращает таймаут выполнения удаленного вызова для операции модуля Tarantool vshard;

    • force_yield_limits — возвращает количество чтений записей спейса, после которых происходит принудительная передача управления (yield) для обеспечения кооперативной многозадачности;

    • hard_limits — возвращает текущие настройки ограничений при выполнении GraphQL-запросов. Может возвращать следующие значения:

      • scanned — ограничение числа записей в спейсах, которые могут быть прочитаны для выполнения запроса;

      • returned — ограничение числа записей, которые могут быть возвращены в ответе на запрос;

    • graphql_query_chache_size — возвращает ограничение количества кэшируемых уникальных GraphQL-запросов. Кэшируется только текст запроса, но не переменные;

    • locked_sections_list — список закрепленных секций. Если в список закрепленных секций добавить любую секцию, например, секцию metrics, а потом загрузить новый файл конфигурации, в котором секции metrics не будет, то эта секция не удалится — вместо нее будет использована последняя загруженная версия секции metrics. Прописать закрепленные секции в файле конфигурации явным образом нельзя. Список обновляется посредством мутаций.

3.2.1.2. Запросы на внесение изменений в настройки (mutation)

  • jobs — работа с ремонтной очередью неудавшихся отложенных работ (попытка выполнения которых закончилась неудачно, вкладка Failed jobs):

    • delete_all_jobs — удалить все отложенные работы из ремонтной очереди отложенных работ;

    • try_again_all — выполнить повторную попытку обработки всех отложенных работ из ремонтной очереди отложенных работ;

    • try_again — выполнить повторную попытку обработки неудавшейся отложенной работы по ее id;

    • delete_job — удалить неудавшуюся отложенную работу по ее id;

  • token — работа с токенами приложений:

    • remove — удалить токен приложения по его имени;

    • import — импортировать токен приложения. Возможные аргументы:

      • state_reason — пояснение к присвоению текущего статуса (необязательно);

      • expires_in — ограничение времени действия (в секундах, 0 — без ограничения);

      • uid — внутренний id токена;

      • role — имя роли из ролевой модели доступа;

      • state — статус (active/blocked);

      • created_at — дата и время создания (в формате Unix time);

      • name — имя токена;

      • last_login — дата и время последнего входа (в формате Unix time, необязательно);

      • unblocked_at — дата и время последней разблокировки (в формате Unix time, необязательно);

    • add — добавить новый токен приложения. Возможные аргументы:

      • expires_in — ограничение времени действия (в секундах, 0 — без ограничения);

      • name — имя токена;

      • role — имя роли из ролевой модели доступа;

    • update — отредактировать данные токена приложения. Возможные аргументы:

      • expires_in — ограничение времени действия (в секундах, 0 — без ограничения);

      • name — имя токена;

      • role — имя роли из ролевой модели доступа;

    • set_state — изменить статус токена приложения (заблокировать или разблокировать). Возможные аргументы:

      • state — статус (active/blocked/new);

      • reason — пояснение к присвоению нового статуса (необязательно);

      • name — имя токена;

  • notifier_upsert_user — добавление нового или редактирование существующего адреса для оповещения (вкладка Subscribers). Возможные аргументы:

    • name — имя контакта для оповещения;

    • addr — адрес электронной почты;

    • id — внутренний идентификатор (строка);

  • clear_repair_queue — очистить ремонтную очередь (вкладка Repair);

  • password_generator — изменение настроек требований к сложности паролей пользователей;

  • output_processor — работа с ремонтной очередью на отправку (вкладка Output processor):

    • clear_list — удалить все объекты на отправку из ремонтной очереди;

    • try_again_all — выполнить повторную попытку обработки всех объектов на отправку из ремонтной очереди;

    • try_again — выполнить повторную попытку обработки объекта на отправку из ремонтной очереди по его id;

    • delete_from_list — удалить объект на отправку из ремонтной очереди по его id;

  • access_role — управление настройками ролевой модели:

    • delete — удаление роли пользователя по ее id;

    • create — создание новой роли пользователя. Возможные аргументы:

      • name — имя новой роли;

      • description — описание новой роли (необязательно);

    • update — изменение имени или описания роли пользователя;

    • update_access_role_actions — изменение прав доступа для роли. Возможные аргументы:

      • id — идентификатор роли;

      • actions — список изменяемых прав:

        • id — идентификатор права;

        • allowed — данные о наличии права для роли (Boolean);

  • set_mail_server — изменение настроек почтового сервера для отправки оповещений (см. Подробнее про модуль SMTP). Возможные аргументы:

    • username — имя учетной записи, с которой будет проводиться рассылка;

    • password — пароль от учетной записи;

    • url — адрес почтового сервера;

    • from — адрес, указываемый в поле отправителя сообщения;

    • skip_verify_host — при установке true позволяет пропускать проверку валидности сертификата хоста;

    • timeout — таймаут отправки;

  • cartridge — изменение конфигурации:

    • load_config_example — загружает тестовый пример конфигурации вместо имеющейся конфигурации;

  • data_access_action — внесение изменений в шаблоны доступа к действиям над данным:

    • delete — удалить шаблон;

    • create — добавить новый шаблон;

    • update — отредактировать существующий шаблон;

  • user — управление пользователями:

    • import — импорт пользователя;

    • add — добавление нового пользователя;

    • remove — удаление существующего пользователя по его uid;

    • modify — редактирование существующего пользователя по его uid;

    • self_modify — редактирование пароля или имени учетной записи для текущего пользователя (из-под которого выполняется GraphQL запрос);

    • set_state — блокирование или разблокирование пользователя;

    • reset_password — сброс пароля пользователя по его uid;

  • model — задание новой модели данных;

  • tasks — управление задачами:

    • start — запуск задачи по ее id;

    • stop — остановка задачи по ее id;

    • forget — удаляет один из результатов выполнения задачи по его id;

  • maintenance — служебные функции:

    • drop_unlinked_spaces — удаление спейсов от агрегатов, которые были удалены из модели, но при этом в хранилище остались их сохраненные данные;

    • truncate_unlinked_spaces — удаление данных из спейсов агрегатов, которые были удалены из модели, но при этом в хранилище остались их сохраненные данные;

  • audit_log — ведение журнала событий безопасности (аудит лог):

    • enabled — включение функции ведения журнала событий безопасности;

    • clear — очистка журнала событий безопасности;

    • severity — настройка уровня важности событий, которые будут записываться в журнал событий безопасности;

  • notifier_delete_user — удаляет запись из списка подписчиков (вкладка Subscribers) по ее id;

  • expiration — изменение настроек устаревания данных:

    • set — установка значений настроек устаревания данных;

    • cleanup — очистка (сброс) настроек устаревания данных по имени агрегата;

  • repair_all — выполняет повторную попытку обработки всех объектов из ремонтной очереди (вкладка Repair);

  • repair — выполняет повторную попытку обработки объекта из ремонтной очереди (вкладка Repair) по его id;

  • delete_from_repair_queue — выполняет удаление объекта из ремонтной очереди (вкладка Repair) по его id;

  • config — изменение настроек кластера:

    • vshard-timeout — таймаут выполнения удаленного вызова для операции модуля Tarantool vshard;

    • force_yield_limits — количество чтений записей спейса, после которых происходит принудительная передача управления (yield) для обеспечения кооперативной многозадачности;

    • hard_limits — ограничения при выполнении GraphQL запросов. Возможные аргументы:

      • scanned — ограничение числа записей в спейсах, которые могут быть прочитаны для выполнения запроса;

      • returned — ограничение числа записей, которые могут быть возвращены в ответе на запрос;

    • graphql_query_chache_size — ограничение количества кэшируемых уникальных GraphQL запросов;

    • locked_sections_add — добавление секции в список закрепленных секций файла конфигурации;

    • locked_sections_delete — удаление секции из списка закрепленных секций файла конфигурации. Больше информации про закрепленные секции.

3.2.2. Настройки Tarantool Cartridge

Для выполнения запроса, его необходимо направить по протоколу HTTP на HTTP порт любого экземпляра кластера с указанием адреса ресурса (endpoint) /admin/api, а также данными авторизации.

Пример выполнения запроса при помощи утилиты curl:

curl --request POST \
  --url http://172.19.0.2:8080/admin/api \
  --header 'Authorization: Bearer 2fc136cf-8cae-4655-a431-7c318967263d' \
  --header 'content-type: application/json' \
  --data '{"query":"query{\n  cluster{\n    known_roles{\n      name\n      dependencies\n    }\n  }\n}"}'

Далее приведены все типы запросов на чтение или изменение основных настроек Tarantool Cartridge. Для некоторых запросов дополнительно указаны возвращаемые значения и пояснения к ним.

3.2.2.1. Запросы на получение информации по текущим настройкам и состоянию кластера (query)

  • cluster — управление кластером:

    • self — позволяет получить информацию о текущем сервере (который выполняет запрос);

    • schema — возвращает схему модели данных в формате строки (YAML). Данная функция недоступна в TDG;

    • failover — возвращает текущий статус включения функции failover;

    • failover_params — возвращает текущие настройки функции failover. Может возвращать следующие значения:

      • tarantool_params — параметры подключения:

        • uri — адрес подключения;

        • password — пароль для подключения;

      • mode — режим работы (disabled, eventual или stateful);

      • state_provider — тип внешнего хранилища для режима работы stateful;

    • vshard_bucker_count — возвращает число виртуальных бакетов в кластере;

    • users — возвращает список авторизованных пользователей (или информацию об одном из них, если передано имя пользователя). Данная функция недоступна в TDG;

    • issues — возвращает список проблем (issues), зарегистрированных в кластере;

    • auth_param — возвращает параметры авторизации. Эти параметры относятся к авторизации в Tarantool Cartridge, а не в TDG:

      • enabled — включена ли функция авторизации;

      • username — имя текущего пользователя;

      • cookie_max_age — максимальное время жизни пользовательской cookie (в секундах);

      • cookie_renew_age — если передаваемая пользовательская cookie старше, чем указано в данном параметре, то ее необходимо обновить;

      • implements_add_user — в кластере реализована функция добавления пользователей;

      • implements_remove_user — в кластере реализована функция удаления пользователей;

      • implements_edit_user — в кластере реализована функция редактирования пользователей;

      • implements_list_user — в кластере реализована функция вывода списка пользователей;

      • implements_get_user — в кластере реализована функция вывода информации о конкретном пользователе;

      • implements_check_password — в кластере реализована функция проверки аутентификатора пользователя;

    • known_roles — возвращает список всех известных ролей экземпляров и их зависимостей;

    • webui_blacklist — возвращает список страниц веб-интерфейса, которые должны быть скрыты (исключены из отображения). Обычно это те страницы, доступ к которым запрещен (запрет доступа осуществляется другими механизмами);

    • vshard_groups — информация об имеющихся группах модуля vshard, используемых для распределенного хранения данных;

    • vshard_known_gorups — данная функция недоступна в TDG;

    • can_bootstrap_vshard — имеется ли возможность вызвать функцию bootsrap_vshard;

    • config — возвращает текущую конфигурацию;

  • servers — возвращает информацию по серверам кластера;

  • replicasets — возвращает информацию по наборам реплик кластера.

3.2.2.2. Запросы на внесение изменений в настройки (mutation)

  • cluster — настройки кластера:

    • schema — применение новой модели данных;

    • failover — включение или отключение функции автоматического восстановления;

    • failover_params — настройка функции автоматического восстановления;

    • check_schema — проверяет передаваемую схему модели данных (в формате YAML строки) на применимость к текущему кластеру. Возвращает ошибку в случае обнаружения, либо null в случае успешного прохождения проверки. Данная функция недоступна в TDG;

    • config — позволяет применить новую конфигурацию ко всему кластеру. Возвращает примененную конфигурацию в случае успеха. Данная функция недоступна в TDG;

    • edit_topology — позволяет задавать топологию кластера (наборы реплик и их роли);

    • auth_params — настройка параметров авторизации. Эти параметры относятся к авторизации в Tarantool Cartridge, а не к TDG:

      • enabled — включена ли функция авторизации;

      • cookie_max_age — максимальное время жизни пользовательской cookie (в секундах);

      • cookie_renew_age — если передаваемая пользовательская cookie старше, чем указано в данном параметре, то ее необходимо обновить;

    • add_user — добавление пользователя в Tarantool Cartridge. Данная функция недоступна в TDG;

    • edit_user — редактирование пользователя в Tarantool Cartridge. Данная функция недоступна в TDG;

    • edit_vshard_options — изменение настроек vshard group. Данная функция недоступна в TDG;

    • failover_promote — переключение мастера в наборе реплик с указанным id на экземпляр с указанным id. Работает только в stateful-режиме функции автоматического восстановления (failover);

    • remove_user — удаление пользователя в Tarantool Cartridge. Данная функция недоступна в TDG;

    • disable_servers — временное отключение экземпляра от кластера. Данная функция недоступна в TDG;

  • edit_server — редактирование основных параметров сервера. Устаревшая функция. Оставлена для обратной совместимости. Используйте cluster/edit_topology вместо данной функции;

  • probe_server — проверяет, доступен ли экземпляр по указанному адресу для подключения его к кластеру;

  • edit_replicaset — редактирование основных параметров набора реплик. Устаревшая функция. Оставлена для обратной совместимости. Используйте cluster/edit_topology вместо данной функции;

  • join_server — подключение нового экземпляра к существующему набору реплик. Устаревшая функция. Оставлена для обратной совместимости. Используйте cluster/edit_topology вместо данной функции;

  • bootstrap_vshard — при вызове происходит распределение данных по серверам (См. bootsrap_vshard);

  • expel_server — необратимое удаление сервера из кластера. Устаревшая функция. Оставлена для обратной совместимости. Используйте cluster/edit_topology вместо данной функции.

4. Информация о выпусках

В этом разделе содержится информация о выпусках версий Tarantool Data Grid 1.*.

Содержание

4.1. Календарь выпуска версий

На этой странице приведена информация о циклах выпуска и поддержки версий Tarantool Data Grid 1.*. Жизненные циклы более ранних серий, которые не упоминаются на этой странице, считаются завершёнными. Подробная информация версиях доступна в журнале изменений.

Серия

Актуальная версия

Выпуск обновлений до

(End of life)

Окончание поддержки

(End of support)

1.8

1.8.12

7 июня 2023

7 июня 2024

1.7

1.7.21

5 октября 2022

7 июня 2024

4.2. Журнал изменений

Формат журнала основан на Keep a Changelog, версионирование подчиняется правилам Semantic Versioning.

4.2.1. [1.8.12] — 2024-02-26

4.2.1.1. Added

  • Many improvements in migration scripts

  • Updated Cartridge to 2.8.6

  • Updated bundle to 2.11.2-0-r616

4.2.2. [1.8.11] — 2023-12-11

4.2.2.1. Added

  • Updated bundle to 2.11.2-0-r609

4.2.3. [1.8.10] — 2023-11-23

4.2.3.1. Fixed

  • Reverted switching to datetime from icu-date because of regression, found by users

  • Fixed OperationError on extension load from config

4.2.4. [1.8.9] — 2023-11-17

4.2.4.1. Added

  • Internally changed icu-date to datetime module. As a result, behavior of datetime and timezone modules might have changed in some rare cases

  • Migration: process data types in parallel

  • Updated web UI dependencies

4.2.4.2. Fixed

  • Prohibit setting non-nullable fields to null

4.2.5. [1.8.8] — 2023-10-31

4.2.5.1. Added

  • Added metrics for output processing

  • Updated Cartridge to 2.8.4

4.2.5.2. Fixed

  • Fixed a backward compatibility break in task return value

4.2.6. [1.8.7] — 2023-10-10

4.2.7. [1.8.6] — 2023-09-21

4.2.7.1. Added

  • Optimized model validation

  • Updated Cartridge to 2.8.2

  • Updated bundle to 2.10.8-0-r589

4.2.7.2. Fixed

  • Fixed tasks being started before vshard has been bootstrapped

4.2.8. [1.8.5] — 2023-07-21

4.2.8.1. Added

  • Updated Cartridge to 2.8.1

4.2.8.2. Fixed

  • Fixed a bug in audit log initialization which led to assertion failure

4.2.9. [1.8.4] — 2023-06-07

4.2.9.1. Fixed

  • Fixed path traversal in config unzip

  • Whitelist file extensions in config unzip

4.2.10. [1.8.3] — 2023-05-30

4.2.10.1. Added

  • Update bundle to 2.10.7-0-r563

  • Update cartridge to 2.8.0

  • Update metrics to 1.0.0

  • Update avro-schema to 3.1.0

  • Update smtp to 0.0.7

  • Update kafka to 1.6.6

4.2.10.2. Fixed

  • Remove debug log from common.graphql

  • Fixed tasks starting before config is completely applied

  • Fixed GraphQL Any type handling for numeric types

  • Remove all string metrics from Kafka

4.2.11. [1.8.2] — 2023-04-11

4.2.11.1. Added

  • Update Cartridge to v2.7.9

  • Ban non-positive values for jobs.max_jobs_in_parallel option

4.2.11.2. Fixed

  • Fix task start time being after finish time (#911)

  • Fix possible jobs wait fiber crash

  • Add validation for twice indexed fields

4.2.12. [1.8.1] — 2022-12-19

4.2.12.1. Added

  • Update bundle to 2.10.4-0-r523

  • Remove kafka string metrics

  • Add enum as arg for grapqhl service

  • Introduce max_msg_in_log option for audit_log

4.2.13. [1.7.21] — 2022-10-05

4.2.13.1. Added

  • Update bundle to 2.10.3-0-r510

4.2.14. [1.7.20] — 2022-08-11

4.2.14.1. Added

  • Update bundle to 2.10.1-0-g88b6f502c-r498

4.2.15. [1.7.19] — 2022-07-15

4.2.15.1. Added

  • Update bundle to 2.10.0-6-gaaed1a3cb-r495

4.2.16. [1.8.0] — 2022-06-28

4.2.16.1. Added

  • Update bundle to 2.8.4-0-g47e6bd362-r491

  • icu-date 1.4.2

  • Metrics 0.14.0

  • Kafka 1.6.0

4.2.17. [1.7.18] — 2022-05-22

4.2.17.1. Breaking changes

  • Make all the default of debug option in Kafka debug mode

  • Remove disable output mode for Kafka logger

4.2.17.2. Added

  • Introduce set_key option for kafka producers

  • Update SDK version to 2.8.4-0-g47e6bd362-r471

4.2.18. [1.6.26, 1.7.17] — 2022-01-29

4.2.18.1. Added

  • Introduce enable_debug configuration option for Kafka connectors

  • Allow to return custom headers and status code from auth plugin

  • Add metrics for Kafka connector

  • Allow to specify read, balance, mode options for graphql data queries via @options directive

  • Now «logger» option in Kafka connector could be one of stderr, tdg, disable

  • Update bundle to 2.8.3-0-g01023dbc2-r442

4.2.18.2. Fixed

  • Fix error in task list when there is a deleted user

  • Consider auto_increment option change

  • Fix graceful shutdown of the connector role

  • Fix case when task could hang in pending state if runner was unavailable for some time

4.2.18.3. Breaking changes

  • (1.6.26 only) Permissions that were deprecated for than two years ago removed. It shouldn’t affect user since UI was hidden.

4.2.19. [1.6.25, 1.7.16] — 2021-12-15

4.2.19.1. Added

  • Update Cartridge to master (28cacde7)

  • Add availability to enable log callback for Kafka

4.2.20. [1.6.24, 1.7.15] — 2021-11-24

4.2.20.1. Added

  • Update Cartridge to master (372c68c)

  • icu-date 1.4.1

4.2.20.2. Fixed

  • Fix RPM package

4.2.21. [1.6.23, 1.7.14] — 2021-11-09

4.2.21.1. Fixed

  • Ban authorization with cluster cookie

  • Prevent watchdog triggering during log/audit_log queries

  • Output replication if update relates more than one record

  • Several UI issues

  • Several LDAP issues

  • An unhandled error inside soap.decode function

  • Assign null value to nested field

4.2.22. [1.6.22, 1.7.13] — 2021-09-24

4.2.22.1. Added

  • Allow pinning some sections in config to restore if they were removed from config

  • Metrics 0.11.0

  • Avro-schema 3.0.6

4.2.22.2. Fixed

  • Explicitly forbid an update of Entity/Entity array and ValueObject fields

  • Allow using dashes in index/relation names back

  • Fix services disappearing after some configuration updates

  • Ban «namespace» usage for types

  • Validation of fields with «long» type

4.2.23. [1.6.21, 1.7.12] — 2021-09-11

4.2.23.1. Added

  • Allow to create several Kafka inputs

4.2.23.2. Fixed

  • «Encountered multiple types» error

  • GraphQL queries with index with 2 or more Decimal field types

  • Prohibit connectors with the same names

  • Throw an error if input_processor.storage.type specified with non-Aggregate type

4.2.24. [1.6.20, 1.7.11] — 2021-08-24

4.2.24.1. Added

  • Cartridge 2.7.1

  • Metrics 0.10.0

  • Update Tarantool to 2.8.2

  • Close kafka producers/consumers asynchronously

4.2.24.2. Fixed

  • Attempt to reimport user’s/token’s own account

  • Error on output replication is there is no output processor

  • Incorrect handing of multipart keys with decimal fields in graphql

  • Error when type was removed from model but expiration section was not

4.2.25. [1.6.19, 1.7.10] — 2021-07-22

4.2.25.1. Added

  • Logs if request fails on storage

  • Allow passing vshard read options to repository functions

  • LDAP 1.0.2

  • Metrics for tasks and jobs

4.2.25.2. Fixed

  • LDAP validation became stricter

  • Ban empty names for some TDG entities

  • Restrict max password length with 1000 symbols

4.2.26. [1.6.18, 1.7.9] — 2021-06-30

4.2.26.1. Fixed

  • Properly handle internal errors when HTTP handler fails

  • Prohibit data actions with empty names

  • Slow validate config flow

  • Fail on attempt to delete permanently aggregate with nested entity

  • Fail if null is passed as tenant value

  • Unhandled error if config.yml is not valid yaml file

  • OperationError when index/relation could have empty name

4.2.27. [1.6.17, 1.7.8] — 2021-06-09

4.2.27.1. Added

  • «Plain» format for Kafka output

  • Ansible playbook for deploy

  • Metrics 0.9.0

  • Watchdog 1.1.1

  • Validation that instance DDL is compatible with configuration

  • Alpha version of authorization with LDAP

4.2.27.2. Fixed

  • Incorrect error message in account provider logs

  • OperationError on storage on sequence create

  • Performance issues when some buffers on routers could be sent to storage

4.2.28. [1.6.16, 1.7.7] — 2021-05-12

4.2.28.1. Added

  • Introduce synchronous mode for output processor (tarantool/tdg#688)

  • Allow configure metrics via config (tarantool/tdg2#1001)

  • Handle dependencies on library initialization (however, we still recommend organizing library code to eliminate any dependencies)

  • Update cartridge to d36ebf2

  • SMTP module 0.0.6 (tarantool/tdg2#708)

  • Metrics 0.8.0

  • ODBC module 1.0.1

4.2.28.2. Fixed

  • “Show more” button on logger page doesn’t return an error (tarantool/tdg#712)

  • Topology change should not affect data access (tarantool/tdg2#934)

  • Don’t show host twice in log message in case of error

4.2.29. [1.6.15, 1.7.6] — 2021-04-26

4.2.29.1. Added

  • Drop unzip/zip requirement (tarantool/tdg#677)

  • Allow to upload config without HTTP — admin.upload_config_api (tarantool/tdg2#272)

  • Cartridge with fixed stateful failover bug

  • Enterprise bundle 2.7.2-0-g4d8c06890-r399

4.2.29.2. Fixed

  • Error if uploaded config was invalid zip file (tarantool/tdg2#898)

  • Invalid cursor calculation if trailing nullable fields were part of index (tarantool/tdg#689)

  • Error if null value was passed to some repository.find filters (tarantool/tdg#691)

  • Change :auto_increment to sequence for to_output_processor space to avoid replication conflicts (tarantool/tdg#686)

  • Extend RBAC to support all modern cartridge queries and mutations (e.g. force config reapply) (tarantool/tdg2#919)

  • Revoke access rights to logs from user (affected only new installations)

  • Stop periodical tasks if they are removed from config (tarantool/tdg#699)

  • Rename storage_error to repository_error (tarantool/tdg2#933)

  • Scheduler can’t be run inside multiple replicasets. Add check for singleton role (tarantool/tdg#707)

  • Don’t start to read messages from kafka if token name is invalid (tarantool/tdg#644).

  • Fix disabling guest role on read-only instances

4.2.30. [1.6.14, 1.7.5] — 2021-03-30

4.2.30.1. Added

  • Cartridge with updated frontend-core (to be able to reload fronted modules)

4.2.30.2. Fixed

  • OperationError in case options defined for kafka producer

  • Error on user reimport (tarantool/tdg2#419)

4.2.31. [1.6.13, 1.7.4] — 2021-03-23

4.2.31.1. Added

4.2.31.2. Fixed

  • Enable coredumps when watchdog aborts Tarantool process

  • Spam into logs on storage startup

  • Incorrect log messages when output processing failed

  • Free resources after kafka/smtp output is removed from config (tarantool/tdg2#816)

  • Unclear vshard errors (tarantool/tdg2#384)

  • «OperationError» if empty config section is uploaded (tarantool/tdg#647)

  • Replace insert with replace in repair storage spaces to avoid replication conflicts (tarantool/tdg2#758)

  • Unique secondary index by time in repair buffer (tarantool/tdg#638)

  • Error if defaults are specified for unions (tarantool/tdg2#118)

4.2.32. [1.6.12, 1.7.3] — 2021-01-26

4.2.32.1. Added

4.2.33. [1.6.11, 1.7.2] — 2021-01-11

4.2.33.1. Fixed

4.2.33.2. Added

  • Cartridge 2.4.0

  • Updates via GraphQL API (tarantool/tdg2#575)

  • Add version compatibility option to config (tarantool/tdg2#431)

  • Deletion of removed indexes from model (tarantool/tdg2#367)

  • Luarapidxml 2.0.1

  • Kafka 1.3.0 (tarantool/tdg2#596)

  • SMTP 0.4.0

  • Metrics 0.6.0

  • Enable CPU usage metrics (tarantool/tdg2#442)

  • Extend datetime sandbox API with custom_datetime_str_to_nsec, millisec_to_formatted_datetime functions

  • Add “soap” module to sandbox

  • Enterprise bundle 2.4.3-0-g5180d98f1-r370.

4.2.34. [1.6.10, 1.7.1] — 2020-12-03

4.2.34.1. Fixed

4.2.34.2. Added

4.2.35. [1.7.0] — 2020-11-10

4.2.35.1. Fixed

4.2.35.2. Removed:

  • Frontend role

  • Permissions. Use data actions instead

4.2.35.3. Breaking changes

  • For TDG 1.7.x, use ‘Authorization’ header (Bearer Authentication) instead of ‘auth-token’. For TDG 1.6.x, the ‘auth-token’ key is still valid.

4.2.36. [1.6.9] — 2020-10-20

4.2.36.1. Fixed

  • Kafka: handle error during consumer closing

  • Fix “field is required by space format is missing” on new roles create

4.2.36.2. Added

  • Metrics 0.3.0

  • Checks 3.1.0

  • ODBC 0.7.2

4.2.37. [1.6.8] — 2020-10-01

4.2.37.1. Fixed

4.2.37.2. Added

  • ODBC 0.7.1

4.2.38. [1.6.7] — 2020-08-20

4.2.38.1. Fixed

4.2.39. [1.6.6] — 2020-08-05

4.2.39.1. Fixed

4.2.39.2. Added

4.2.40. [1.6.5] — 2020-07-15

4.2.40.1. Fixed

4.2.40.2. Added:

4.2.41. [1.6.4] — 2020-07-02

4.2.41.1. Fixed

4.2.42. [1.6.3] — 2020-06-05

4.2.42.1. Fixed

4.2.42.2. Added

4.2.43. [1.6.2] — 2020-05-21

4.2.43.1. Fixed

4.2.44. [1.6.1] — 2020-05-13

4.2.44.1. Fixed

4.2.44.2. Added

4.2.45. [1.6.0] — 2020-04-20

4.2.45.1. Fixed

4.2.45.2. Added

4.2.46. [1.6.0-alpha] — 2020-04-20

4.2.46.1. Added

4.2.46.2. Fixed

  • remove check existence of task_runner when storage init (tarantool/tdg#135)

  • [dev] implement ignore_hard_limits flag for document.tuple_select for some service/development purposes. It calls fiber.yield every force-yield-limit iterations. Can be configured via GraphQL, by default 1000

  • tdgctl: support new option is_master (boolean) for deploy config. The upgrade procedure will only run on such instances

  • decorate an archive name with instance name (tarantool/tdg#183)

  • do not treat responses with code 201, 204 as an error (tarantool/tdg#187)

  • tdgctl: upgrade automatically stops all instances

  • the only request context pass through netbox now (tarantool/tdg#189)

  • repository update for value object case (tarantool/tdg#259)

  • wrong (but without affect) bucket_id calculation in repository.find (tarantool/tdg#266)

  • prohibit the ability to log in if authorization is turned off (tarantool/tdg#277)

  • document: allow to specify multikey index as index check (tarantool/tdg#310, tarantool/tdg#311)

  • uploading configuration with a section removed does remove it clusterwide (tarantool/tdg#314)

  • add cursor field to repair storage get method (tarantool/tdg#344)

4.2.46.3. Removed:

  • batch_count option from map_reduce

4.2.46.4. Breaking changes

  • format of the return value in output_processor changed (tarantool/tdg#178)

  • map-reduce interface was updated (tarantool/tdg#192)

  • GraphQL maintenance_get_aggregates function renamed to maintenance.get_aggregates

  • optimistic lock semantic is changed (tarantool/tdg#283)

4.2.47. [1.5.0] — 2019-09-18

4.2.47.1. Added

  • default value for token_acl list

  • checking permissions by token

  • authorization with token name

  • default user for tasks

  • option to find deleted records in model_accessor

  • system tasks

  • ODBC support in sandbox

  • Kafka consumer in connector

  • request_id prefix for log messages (tarantool/tdg#541)

  • expose tracing into sandbox

  • funcall refactoring (tarantool/tdg#575)

  • Fix: UI: Permission filter fix

  • Fix: rename scheduler api because of clashing with cluster logic

  • Fix: call to utils datetime conversion in model_updater

  • Fix: call task_list API only from master

  • Fix: rename common.tracing role to tracing

  • QA: enable Lua and Python linters

  • UI: show asterisks on password fields (tarantool/tdg#561)

  • UI: logger lamp disable (tarantool/tdg#564)

  • UI: tracing flag for GraphQL and test sections (tarantool/tdg#546)

  • repository.call_on_storage (tarantool/tdg#49)

  • sandbox function this_storage.snapshot

  • connector SMTP output feature (tarantool/tdg#5)

  • delegate arguments parsing to cluster.argparse (tarantool/tdg#93)

  • rename cluster to cartridge (tarantool/tdg#95)

  • Fix: output replication on entity update (tarantool/tdg#61)

  • add permanent_delete option to repository.delete

  • expose if_only_version option to GraphQL mutations

  • GraphQL query time and fail monitoring (tarantool/tdg#101)

  • Add response_body and status_code to failed requests from output_connector (tarantool/tdg#75)

  • Functions refactoring (tarantool/tdg#131). In functions you must get arguments like local x, y = ... instead of local x, y = unpack(...) or using array semantics

  • Tarantool version updated to 2.2

4.2.47.2. Fixed

4.2.48. [1.4.1] — 2019-09-06

4.2.49. [1.3.0] — 2019-05-31

4.2.50. [1.2.0] — 2018-09-29

4.2.50.1. Added

  • monitoring a replication lag

  • logger pagination

  • profile the pipelines

  • fixed systemd start service on boot

  • save backup files before deployment

  • ‘try again all’ button in the repair queue

  • singleton mechanism of instance

  • migrated to new logger

  • GraphQL refactoring

  • break the build if any module is missing

  • check deploy permissions

  • download logs with tdgctl

  • add rm data command to tdgctl

  • display cluster memory usage in UI

  • vshard call timeout

  • deploy the project on the bare metal

  • migrate Docker image to static Tarantool and CentOS 7

  • add datacenter name information to every node

  • web console

  • add cluster cookie to deploy script

  • cluster: added GraphQL self query

4.2.51. [1.1.1] — 2018-07-10

4.2.51.1. Added

  • privileged mode

  • keep DDL in sync across storage nodes

  • simple deployment script based on Docker and Fabric

  • wrap net.box.call with errors

4.2.52. [1.1.0] — 2018-07-01

4.2.52.1. Added

  • authentication and external app token authentication

  • port repair queue to vshard

  • notifier as separate role

  • collect messages before sending

  • collect metrics from dcos deployment to Prometheus

  • multipart index

  • email notifications about repair queue events

4.2.53. [0.3.0] — 2018-02-28

4.2.53.1. Added

  • support for sharded storage

  • proof-of-concept of dynamically adding/replacing replicas of shards, using the ‘shard’ module and docker as ‘backend’

  • Avro-based modeling language

  • fixed large GraphQL requests parsing

4.2.54. [0.2.0] — 2018-01-23

4.2.54.1. Added

  • Prometheus-based monitoring

  • “on insert” subscriptions

  • JSON output adapter

4.2.55. [0.1.0] — 2017-12-20

4.2.55.1. Added

  • Initial version of connector with SOAP input and Tarantool protocol output

  • Data processing pipelines based on Lua code

  • Schema description language loosely based on graphql-lua

  • Ability to dynamically reload schema

  • Schema verification for incoming objects

  • Basic same-node storage backend

  • GraphQL query API based on the schema

  • Frontend for testing GraphQL queries

  • Frontend for editing schema

  • Frontend for testing SOAP requests