# Глоссарий

## Общие сведения {: #intro }

Данный раздел содержит описание терминов и определений, используемых в Picodata и необходимых для понимания работы распределенной СУБД.

## Подсистемы {: #subsystems }

### Raft {: #raft }

**Raft** является алгоритмом распределенного консенсуса, который нужен, чтобы несколько участников могли совместно решить, произошло ли событие или нет, и что за чем следовало. Raft используется в Picodata для согласования работы узлов и поддержания консистентности в [кластере](#cluster). Концепция распределенного консенсуса предполагает, что в кластере всегда есть только один [лидер](#leader) и некоторое количество голосующих узлов. Эти узлы в нормальном состоянии подтверждают легитимность лидера, а при отказе текущего лидера организуют выборы нового.
См. [подробнее](https://raft.github.io/raft.pdf).

### Терм (term) {: #term }

Период между выборами лидера в [raft](#raft)-группе называется **термом** (term). Каждый терм начинается в момент объявления выборов нового лидера. Обычно это происходит после потери связи с прежним лидером. Терм состоит из двух частей: выборов и периода нормальной работы raft-группы. Исключением служат термы, в течение которых не удалось выбрать лидера группы: у таких термов есть только первая часть (выборы).
Важно помнить, что в одном терме не может существовать более одного лидера raft-группы.

### Состояния узлов в Raft-группе {: #node_states }

В raft-группе любой узел может быть в одном из трех состояний:

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

**Кандидат в лидеры (candidate)** — состояние инстанса во время выборов лидера. Когда начинается новый терм, инстансы в статусе follower увеличивают значение терма и переходят в статус кандидатов, голосуют сами за себя и затем ждут результатов выбора. Выходов из этого состояния три:

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

**Лидер raft-группы (leader)** — избранный узел, который отвечает за обработку запросов и [репликацию](#replication) raft-журнала.

### Raft-лидер {: #raft_leader }

**Лидер в raft-группе** — это один из узлов, который несет ответственность за [репликацию](#replication) raft-журнала. Лидер избирается на голосовании и признается таковым всеми участниками голосования. Задача лидера состоит в приеме сообщений от клиентов [кластера](#cluster) и отправке сообщений на узлы кластера таким образом, чтобы в любой момент времени все узлы имели консистентную, непротиворечивую версию raft-журнала. Лидерство в Raft предполагает, что все остальные узлы признают приоритет версии журнала, предлагаемую лидером.

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

### Репликация raft-журнала {: #log_replication }

**Репликация raft-журнала** нужна для того, чтобы на каждом узле [кластера](#cluster) (raft-группы) была одинаковая история команд. Когда лидеру группы нужно добавить в журнал новую команду, он сначала отправляет ее всем узлам, ждет подтверждения записи (commit), и лишь затем добавляет эту команду в собственный журнал. В случае, если журнал обычного узла отличается от журнала лидера, то лидер настаивает на приоритете своего журнала и перезаписывает журнал обычного узла, считая его устаревшим.
Для упрощения репликации алгоритм Raft придерживается двух правил при сравнении журналов разных узлов:

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

Так как а) записи в журнале не могут менять порядок и б) каждой записи соответствует только один индекс и терм, то указанные выше правила гарантирует консистентность журнала. Raft-журнал хранится в ОЗУ узла, на котором запускается инстанс.

### Журнал аудита {: #audit_log }

**Журнал аудита** позволяет вести учет событий безопасности в [кластере](#cluster) Picodata. Ведение журнала включается явным образом при запуске [инстанса](#instance).

См. также:

- [Использование журнала аудита](../admin/audit_log.md)
- [Регистрируемые события безопасности](../reference/audit_events.md)

### Web UI {: #webui }

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

### CLI (Command-line interface) {: #cli }

**CLI** — это интерфейс командной строки для запуска и управления как отдельными [инстансами](#instance), так и всем [кластером](#cluster) Picodata.

### Дискавери (discovery) {: #discovery }

**Discovery** — [алгоритм](../architecture/discovery.md), по которому инстансы обнаруживают друг друга. Этот шаг необходим на старте каждого [инстанса](#instance) для корректной работы [кластера](#cluster) .

### Vshard {: #vshard }

**Vshard** — библиотека из экосистемы СУБД Tarantool, используемая в Picodata для [горизонтального масштабирования](#sharding) — сегментирования данных по нескольким узлам в [кластере](#cluster). Это становится важным по мере увеличения объема хранимых данных, ввода в строй новых узлов — т.е. роста кластера.
Библиотека Vshard встроена в Picodata и является неотъемлемой ее частью.
В клиентских интерфейсах Vshard желательно прятать за фасадом, но при острой необходимости ничто не помешает им воспользоваться.

## Ролевая модель {: #access_control }

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

См. [Управление доступом](../admin/access_control.md)

### Объекты доступа {: #access_objects }

Объектами доступа являются:

<!-- Keep in sync with admin/access_control.md#role_model -->
- `table` – [таблица БД](#table)
- `user` – учетная запись [пользователя СУБД](#user)
- `role` – [роль](#role)
- `procedure` – [процедура](#stored_procedure)

### Пользователь {: #user }

Пользователь является субъектом доступа. Он указывает имя учетной
записи, от имени которой происходит подключение к
[инстансу](#instance) Picodata. Действия, которые пользователь может
совершать в системе, определяются доступными ему
[привилегиями](#privilege).

### Привилегия {: #privilege }

Привилегия – это явное разрешение на выполнение указанных действий, см.
[Управление доступом](../admin/access_control.md#privileges).

### Роль пользователя {: #role }

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

## Сущности {: #essentials }

В начале идет общее обозначение термина, затем в скобках указан
предпочтительный вариант употребления в коде (без пробелов в “змеином
регистре”).

### Инстанс (instance) {: #instance }

**Обозначение единицы кластера СУБД и сервера приложений**.

При описании [кластера](#cluster) мы различаем программный и логический уровни.

На программном уровне единицей кластера является экземпляр приложения
Picodata, также на техническом жаргоне называемый _инстансом_. Среда
выполнения приложения может быть как виртуальной, так и физической. В
контексте операционных систем каждый инстанс соответствует одному
[процессу](https://ru.wikipedia.org/wiki/Процесс_(информатика)). В
составе [репликасета](#replicaset) инстанс является репликой.

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

### Тир (tier) {: #tier }

**Тир** — это группа [инстансов](#instance), объединенных по функциональному назначению.

В части хранения [шардированных](#sharding) данных тир представляет собой отдельную
группу хранения. Для каждой шардированной таблицы определена
принадлежность конкретному тиру.

См. также:

- [Создание кластера — Кластер из нескольких тиров](../tutorial/deploy.md#multi_tier_cluster)

### Кластер (cluster) {: #cluster }

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

**Кластер** является наиболее крупной сущностью в системе хранения, в некотором смысле он и есть система хранения. Внутри кластера находятся [инстансы](#instance), объединенные в [репликасеты](#replicaset), которые, в свою очередь, входят в состав [тиров](#tier).

### Репликасет (replicaset) {: #replicaset }

**Репликасет** — буквально «набор реплик», экземпляров приложений, в которых хранится один и тот же набор данных. Реплика в составе репликасета может быть в одном из двух состояний:

- активная (active) — доступная на запись, иногда ее называют мастером или лидером репликасета.
- резервная (standby) — доступная только на чтение, read-only.

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

### Лидер (leader) {: #leader }

В Picodata есть две разновидности лидеров:

- [raft-лидер](#raft_leader) — лидер raft-группы,
- и “репликасет-лидер” — активная реплика ([инстанс](#instance)) репликасета.

Термин _лидер_ часто путают с _мастером_ применительно к репликации Tarantool. В Picodata они хоть и близки, но все же отличаются по смыслу. Под _мастером_ следует понимать инстанс, который выполняет пользовательские DML-операции (`insert` | `update` | `delete`). На практике чаще всего такой инстанс один, и в таком случае оба термина описывают один и тот же инстанс (отсюда и путаница), но в Tarantool архитектурно заложена возможность вести запись на нескольких узлах репликасета одновременно — т.н. режим мультимастера (multi-master). Даже в таком режиме операции DDL (`box.schema.create_space` и т.д.) должен выполнять лишь один инстанс из всех, и здесь становится важно отличать _лидера_ от _мастера_. Несмотря на то, что в Picodata режим мультимастера пока не реализован, документация и код должны использовать эти термины корректно.

### Домен отказа (failure_domain) {: #failure_domain }

**Домен отказа** является признаком физического расположения сервера, на котором запущен [инстанс](#instance). Указание домена отказа позволяет обозначить наличие единой точки отказа у двух инстансов. Смысл данного параметра состоит в том, чтобы в один [репликасет](#replicaset) попадали инстансы из разных физических локаций, что повышает отказоустойчивость [кластера](#cluster).

**Домен отказа** представляет собой набор пар “ключ=значение”, которые соответствуют отдельным зонам (географический регион, датацентр, стойка и т.д.). Зоны задаются пользователем исходя из фактической конфигурации оборудования, будь то виртуальные машины в облаке (`“region=eu”`) или физические сервера (`“dc=msk”`). Домен отказа может включать несколько зон (`“dc=msk,srv=msk-1”`).

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

Если домены отказа двух инстансов имеют хотя бы одну общую зону (и ключ, и значение), то допускается возможность одновременной потери связи с обоими. Поэтому инстансы, делящие общую зону, не будут объединены в репликасет. Picodata также стремится распределить [голосующие raft-узлы](#node_states) таким образом, чтобы их домены отказа имели минимум общих зон.

### Фактор репликации (replication_factor) {: #replication_factor }

**Фактор репликации** — параметр, определяющий число [реплик](#instance)
в [репликасете](#replicaset) (то есть, сколько копий данных хранится в кластере).
Задается общим на [тир](#tier).

См. также:

- [Создание кластера — Репликация и зоны доступности](../tutorial/deploy.md#failure_domains)

### Бакет {: #bucket}

**Бакет** — виртуальная неделимая единица хранения данных, обеспечивающая их локальность (т. е. нахождение на каком-то одном [репликасете](#replicaset)).

### Таблица {: #table }

**Таблица** — пространство хранения данных. В Picodata есть следующие виды пользовательских таблиц:

1. Глобальные (_global_) — их содержимое реплицируется на весь [кластер](#cluster)
1. Шардированные (_sharded_) — каждый [репликасет](#replicaset) хранит лишь часть общего
  набора данных. Данные реплицируются внутри репликасета

Также в рамках кластера существуют [системные
таблицы](../architecture/system_tables.md). Они являются глобальными, но
используются для служебных целей, например для хранения списка
[пользователей](#user), их [привилегий](#privilege), созданных ими таблицах и т.п.

Метаданные всех таблиц Picodata присутствуют на всех узлах кластера.
Фактически для пользователя не существует понятия “не кластерных”
таблиц, он лишь выбирает между стратегиями [шардирования](#sharding) и [репликации](#replication)
тех таблиц, с которыми он работает.

### Движок хранения {: #db_engine }

В Picodata возможно использование разных движков хранения данных в СУБД. Доступны следующие варианты:

- `'memtx'` — движок по умолчанию (если при создании [таблицы](#table) явно не указывать способ хранения данных, то будет использован именно он). Движок `'memtx'` обеспечивает резидентное (in-memory) хранение данных, т.е. их нахождение в ОЗУ. Данный вариант означает наивысшую производительность и скорость доступа к данным. Ограничением является размер БД, который зависит от доступного объема ОЗУ. Несмотря на то, что все данные хранятся в ОЗУ, в Picodata предусмотрено сохранение данных на диск (для восстановления после перезапуска инстанса). См. [подробнее](#persistence);
- `'vinyl'` — дисковый движок хранения данных. Позволяет работать с БД, размер которой превышает размер ОЗУ. При этом, основная часть данных находится на диске, а в ОЗУ доступен лишь кэш часто используемых данных. Движок `'vinyl'` работает на основе журнально-структурированных деревьев со слиянием, или LSM-деревьев (Log Structured Merge Tree), которые показывают хорошую производительность при работе c твердотельными дисками (SSD). Последние отличаются высокими показателями чтения, особенно в сравнении с более медленной записью данных.

### Индекс (index) {: #index }

**Индекс** — это структура данных, обеспечивающая быстрый доступ к
строкам [таблицы](#table) по значениям одного или нескольких столбцов.

В Picodata индексы делятся по способу создания на _автоматические_
и _пользовательские_.

#### Автоматически создаваемые индексы {: #auto_index }

- **Первичный индекс**
  Определяет физический порядок хранения записей в таблице на отдельном
  экземпляре Picodata. Уникальность записей гарантируется только в пределах
  одного экземпляра и применяется лишь к глобальным таблицам. Для обеспечения
  уникальности в шардированных таблицах необходимо создать пользовательский
  уникальный индекс с включением ключа распределения в префикс ключа.

- **Индексы служебных колонок**
  Создаются автоматически при создании таблицы. Например, для шардированных
  таблиц формируется индекс по системной колонке `bucket_id`.

#### Пользовательские индексы {: #user_index }

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

#### Организация данных {: #index_layout }

В общем случае индекс хранит пары _ключ - ссылка на кортеж_, где:

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

Например:

- в `memtx` ссылка представляет собой указатель в памяти,
- в `vinyl` — значение первичного ключа.

#### Покрывающее сканирование {: #covering_index_scan }

Picodata поддерживает покрывающее сканирование индекса (аналогично механизму
`covering index scan` в SQLite). Если все запрашиваемые в запросе столбцы
входят в ключ индекса, то переход к исходному кортежу не выполняется — чтение
происходит напрямую из ключей индекса, что снижает накладные расходы при
выполнении запросов.

### LSN (log sequence number) {: #lsn }

Термин **LSN** (log sequence number) относится к архитектурным особенностям Tarantool, в котором все обновления БД фиксируются в журнале упреждающей записи ([WAL](#wal)) в виде отдельных записей. Каждая запись представляет собой запрос на изменение данных (`insert` | `update` | `delete`) и маркируется монотонно возрастающим номером LSN. Наибольший номер обозначает номер наиболее свежей записи, находящейся в конце журнала WAL.

### WAL (write-ahead log) {: #wal }

**WAL** — это журнал упреждающей записи (write-ahead log), в который попадают все изменения БД в первую очередь. Журнал представляет собой последовательность нескольких файлов `*.xlog` для таблиц на [движке](#db_engine) `memtx` и `*.vylog` для таблиц на движке `vinyl`. Каждый из файлов журнала не самостоятелен: в нем изменения записываются относительно предыдущего файла с инкрементными изменениями.

### Vclock (vector clock) {: #vclock }

[Репликация](#replication) в Tarantool предполагает обмен записями между инстансами в [репликасете](#replicaset). Благодаря этому обмену, на каждом отдельном инстансе имеется специальный набор записей, полученный от других инстансов с разными LSN — это и есть **Vclock** (vector clock, векторные часы). Vclock описывает состояние БД для отдельного инстанса в репликасете.

Vclock [репликасет-лидера](#leader) играет важную роль в поддержании консистентности при переключении лидера (consistent switchover). В случае аварийного переключения ([фейловера, failover](#failsoft)), когда консистентность сохранить невозможно и она жертвуется в угоду доступности, отслеживание vclock позволяет строить метрики точек восстановления (RPO, recovery point objective).

### Сетевой адрес (address) {: #address }

**Сетевой адрес** — это комбинация `host:port`, используемая для связи [инстансов](#instance) друг с другом по сети. Другие названия для связки `host:port` (например URL, URI) мы стараемся искоренить. Расширенная версия `user:pass@host:port` все равно определяется термином _адрес_.

### Стейт (state) {: #state }

**State (стейт)** — специфичный для Picodata способ обозначения состояния [инстанса](#instance). Стейт отражает то, как инстанс сконфигурирован его соседями. Существуют текущий (`current`) и целевой (`target`) типы стейтов. За приведение первого ко второму отвечает [governor (губернатор)](#governor).

### Крейт (crate) {: #crate }

**Крейт** (буквально “ящик”) — наименьшая логическая единица проекта, написанного на Rust. С точки зрения компилятора `rustc`, любой отдельный фрагмент кода является крейтом. Из одного крейта может быть скомпилирован бинарный исполняемый файл, либо разделяемая библиотека. Несколько крейтов могут вместе составлять пакет (package). Пакет может состоять также и из одного крейта. Если крейтов в пакете несколько, то из них только один может предоставлять разделяемую библиотеку.

### Снапшот (snapshot) {: #snapshot }

**Снапшот**, в самом широком смысле этого слова — это снимок состояния распределенного конечного автомата. В контексте Picodata можно говорить о двух независимых (почти) распределенных конечных автоматах, и, соответственно, о двух видах снапшотов — Tarantool и Raft.

Picodata прилагает все усилия, чтобы эти состояния были одинаковыми на каждом узле [кластера](#cluster), но т.к. изменения на узлах происходят через применение команд из журнала ([WAL](#wal) или [raft](#log_replication)), то даже в штатном режиме это случается не одновременно.

Более детально, состояние [инстанса](#instance) включает в себя две части:

- персистентные данные, которые можно сериализовать и сохранить на диск;
- транзиторное (transient) состояние — все структуры, которые Tarantool строит в оперативной памяти для обработки [DML](#dml)-запросов.

См. также:

- [Tarantool — Persistence](https://www.tarantool.io/en/doc/latest/platform/storage/persistence/)

### Файбер (fiber) {: #fiber }

**Файбер** — это легковесный поток исполнения, управление которыми в
Picodata происходит по принципу кооперативной многозадачности.

Кооперативная многозадачность в Picodata построена на основе цикла
событий (event loop), реализуемого библиотекой `libev`. В рамках одного
потока ОС существует множество файберов, выполняющихся
псевдопараллельно, см. [Файберы, потоки и
многозадачность](../architecture/fibers.md)

### Плагин (plugin) {: #plugin }

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

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

Плагины в Picodata работают глобально во всем [кластере](#cluster), т.е.
разворачиваются на каждому его узле. Управление жизненным циклом плагина
организовано с помощью [миграций](#migration).

#### Миграции {: #migration }

Применительно к плагинам, под _миграцией_ в Picodata понимается
управление служебной схемой данных [плагина](#plugin) при помощи
SQL-команд. Миграции выполняются специальной командой. Каждая миграция —
это набор [DML](#dml)- и [DDL](#ddl)-команд внутри файла с расширением
*.db. Различают два вида миграции:

- `UP` — команды для развёртывания плагина в кластере
- `DOWN` — команды для корректного удаления плагина из кластера

Файлы миграции определяются в [манифесте](#manifest) плагина.

#### Манифест {: #manifest }

Каждый плагин в Picodata обязательно содержит _манифест_ — файл в
формате YAML (manifest.yaml) c описанием плагина, списком его сервисов и
их конфигурации, а также списком необходимых [миграций](#migration).

#### Сервис {: #service }

Сервис в плагине представляет собой некоторый программный код на языке
Rust, который может быть инстанцирован на одном или нескольких [тирах] и
обладает жизненным циклом и состоянием. Технически сервис представляет
собой реализацию trait’a Service и является набором callback’ов (которые
определены явно, контрактом trait’a) а также некоторого состояния
(которое определяет разработчик). Сервис может декларировать
конфигурацию. Сервисы объединяются в плагин при помощи
[манифеста](#manifest).

[тирах]: #tier

#### Директории плагина {: #plugin_path }

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

- `share-dir` — параметр запуска Picodata, устанавливающий корневую
  директорию для плагинов (например, `build`)
- `plugin_path`— путь к файлам плагина, последовательно состоящий из
  корневой директории плагинов, имени плагина и его версии (например,
  `build/weather_cache/0.1.0`)

## Процессы и алгоритмы {: #processes_and_algorithms }

### Компактизация raft-журнала (raft log compaction) {: #raft_log_compaction }

**Компактизация** — процесс, не допускающий бесконтрольного роста журнала записей Raft. Компактизация заключается в удалении части журнала, относящейся к сделанному ранее [снапшоту](#snapshot).

### Создание снапшотов (snapshotting) {: #snapshotting }

**Создание снапшотов** — процесс периодического сохранения состояния [инстанса](#instance) на жесткий диск. Наличие [снапшотов](#snapshot) позволяют восстановить инстанс в прежнем виде после его перезапуска.

### Губернатор (governor) {: #governor }

**Governor (губернатор)** — алгоритм автоматического централизованного управления конфигурациями [инстансов](#instance)
(подробнее [здесь](../architecture/topology_management.md#governor)).
С точки зрения реализации, governor — это поток управления (fiber), всегда выполняющийся на [raft-лидере](#raft_leader).
Governor управляет жизненными циклами инстансов, реагируя на изменения их [стейтов](#state).

### Дозорный (sentinel) {: #sentinel }

**Sentinel (дозорный)** — алгоритм корректного отключения [инстанса](#instance), а также отслеживания
недостижимых инстансов.
С точки зрения реализации, sentinel — это [файбер](#fiber), работающий на
каждом инстансе. Работа по отслеживанию недостижимых инстансов выполняется только
на [raft-лидере](#raft_leader).

### Фенсинг (fencing) {: #fencing }

**Фенсинг** — это подпись всех запросов в [кластере](#cluster) номером эпохи или [терма](#term), и отказ обслуживать запросы с устаревшей эпохой. Данный инструмент используется для корректной работы распределенной блокировки, т.е. ситуации, когда из нескольких узлов нужно гарантированно выбрать один для выполнения запроса.

### CaS (compare and swap) {: #cas }

**Compare and swap** — особый алгоритм в составе Picodata. Он
обеспечивает уровень изоляции транзакций [serializable](#isolation), тем
самым не допуская случаев несогласованности данных в результате
выполнения конкурирующих запросов/транзакций. Таким случаем, например,
может быть ситуация, когда одна транзакция затирает результат действия
другой, выполняющейся в тоже время. _Compare and swap_ решает эту
проблему с помощью проверки предиката, т.е. меняет данные какого-либо
параметра кластера только в том случае, если исходное ожидаемое значение
этого параметра соответствует исходному фактическому.

Технически данный алгоритм реализован в виде RPC-функции
[`.proc_cas_v2`](../architecture/rpc_api.md#proc_cas_v2).

### Бутстрап (bootstrap) {: #bootstrap }

**Bootstrap** — процесс первоначального объединения разрозненных [инстансов](#instance) в единый [кластер](#cluster). В контексте Picodata речь обычно идет о бутстрапе инстанса, когда инстанс запускается в чистой директории без [снапшотов](#snapshot). При необходимости можно уточнить, бутстрапится _лидер репликасета_ или _read-only-реплика_ — алгоритмы для них отличаются.

Случай, когда инстанс запускается на существующих снапшотах, называется _восстановлением из снапшота_ (recovery from a snapshot). Этот процесс сопутствует перезапуску инстанса.

Другой эксплуатационный сценарий, когда при перезапуске удаляются все данные инстанса, называют _ребутстрапом_ (rebootstrap), т.е. повторным запуском. Ребутстрап всегда сопровождается сменой `raft_id`, хотя `instance_name` может при этом переиспользоваться.

_Бутстрап кластера_ — бутстрап первого инстанса + [присоединение](#joining) некоторого количества других.

_Бутстрап репликасета_ — бутстрап лидера репликасета + присоединение к нему реплик.

### Присоединение (joining) инстанса к кластеру {: #joining }

_Присоединение инстанса_ близко по смыслу к [бутстрапу](#bootstrap), но делает акцент на процессах, происходящих в самом [кластере](#cluster). Чтобы [инстанс](#instance) мог присоединиться, другие (уже существующие) члены кластера должны сначала сохранить информацию о нем в raft-журнал. См [Присоединение инстанса к кластеру](../architecture/topology_management.md#joining)

### Репликация (replication) {: #replication }

**Репликация** — один из механизмов [актуализации](#actualization) данных между [инстансами](#instance). В Picodata имеется несколько видов репликации.

В зависимости от уровня применения:

- **встроенная** внутри [репликасета](#replicaset)
- **Raft-репликация** (глобальная на весь [кластер](#cluster)).

Соответственно, _репликация_ как процесс обычно означает пересылку записей журналов ([WAL](#wal) или [raft](#log_replication) в зависимости от того, о каком виде репликации идет речь).

В зависимости от уровня абстракции:

- **физическая**. Работает на низком уровне, копируя физические изменения данных (например, блоки данных на диске или бинарные журналы изменений). Она создает полную и точную копию исходной БД, не учитывая семантику самих данных. Встроенная и Raft-репликация относятся к физическому виду.

- **логическая**. Работает на более высоком уровне, передавая изменения данных в виде логических операций (например, SQL-запросов: `INSERT`, `UPDATE`, `DELETE`). Она понимает семантику данных и передает только изменения, связанные с конкретными таблицами или строками.

### Актуализация (catch-up) инстанса {: #actualization }

Актуализация — это по сути синхронизация данных между [инстансами](#instance). Существует два механизма актуализации: посредством [репликации](#replication) журнала (catch-up by log replication), и посредством применения [снапшота](#snapshot) (catch-up by snapshot).

Актуализация снапшотом поддерживается только для Raft, но не для Tarantool. Она требуется, когда на [raft-лидере](#raft_leader) отсутствуют нужные записи в raft-журнале. Если аналогичная ситуация происходит с [WAL](#wal) Tarantool, пользователю не остается выбора кроме как делать [ребутстрап](#bootstrap) инстанса.

## Общие концепции {: #concepts }

### Отказоустойчивость {: #failsoft }

**Отказоустойчивость** — свойство [кластера](#cluster) сохранять работоспособность
при выходе из строя части узлов. В Picodata отказоустойчивость
обеспечивают следующие механизмы:

- выборы лидера, реализуемые [алгоритмом Raft](#raft) и автоматическое
  переключение голосующих узлов, (см. [Архитектура — Raft и
  отказоустойчивость](../architecture/raft_failover.md))
- [репликация данных](#replication) и автоматическое переключение
  лидеров репликасеов.
  <!-- см. [Архитектура — Отказоустойчивость в репликасетах]() -->

### Персистентность {: #persistence }

**Персистентность** — свойство кластера поддерживать постоянную доступность данных и обеспечивать их максимальную сохранность. В контексте in-memory-системы это означает наличие механизмов журналирования и сохранения данных инстанса на диске с тем, чтобы при перезапуске инстанса (плановом или из-за нештатной ситуации) его данные могли быть надежно восстановлены. Таких механизмов в Picodata два:

- сохранение изменений БД и ее метаданных при помощи журнала упреждающей записи ([WAL](#wal)) в виде снимков. При отсутствии снимков данных (см. ниже) для восстановления инстанса потребуется полный набор этих файлов;
- полные снимки данных инстанса в виде файлов `*.snap`. Каждый такой файл самостоятельный и хранит информацию о полном состоянии инстанса на определенный момент времени. Для восстановления данных инстанса может быть достаточно лишь наиболее свежего файла `*.snap`, однако иногда требуется комбинация снимок+журнал: используется снимок (`*.snap`) и один/несколько файлов `*.xlog`/`*.vylog` с изменениями, произошедшими после создания того снимка.

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

```
00010.xlog -- изменения начиная с пустой базы, заканчивая моментом t1
00020.xlog -- изменения начиная с момента t1, заканчивая моментом t2
00030.snap -- изменения начиная с пустой базы, заканчивая моментом t2
00030.xlog -- изменения начиная с момента t2, заканчивая моментом t3
00040.xlog -- изменения начиная с момента t3, заканчивая моментом t4
00050.snap -- изменения начиная с пустой базы, заканчивая моментом t4
```

В этом примере есть несколько способов восстановить полное состояние
инстанса на момент `t4`:

- либо `00010.xlog` + `00020.xlog` + `00030.xlog` + `00040.xlog`
- либо `00030.snap` + `00030.xlog` + `00040.xlog`
- либо `00050.snap`

### Горизонтальное масштабирование {: #sharding }

**Горизонтальное масштабирование** (оно же сегментирование или шардирование, sharding) — подход, предполагающий разделение данных на [бакеты](#bucket), которые могут храниться на отдельных [репликасетах](#replicaset) в [кластере](#cluster). С точки зрения набора хранимых данных, каждый репликасет называется шардом. Деление на шарды — это еще один вариант логического деления кластера, но без привязки к серверам, на которых выполняются инстансы.

### Линеаризуемость {: #linearizability }

В контексте распределенных баз данных **линеаризуемость** обозначает свойство хранилища обеспечивать целостность и согласованность данных на разных репликах БД. Линеаризуемость в Picodata обеспечивается алгоритмом консенсуса Raft, который обновляет данные на мастер-реплике только после того, как они записаны на резервные реплики.

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

```
sharding_key:
  - id
  - name
```

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

### Уровень изоляции транзакций {: #isolation }

Уровень изоляции транзакций является одним из компонентов ACID (_atomicity, consistency, isolation, durability_), который представляет собой набор требований к СУБД согласно стандарту [ANSI/ISO SQL](https://en.wikipedia.org/wiki/ISO/IEC_9075). Уровень изоляции транзакций определяет степень строгости, которую СУБД применяет к возможной несогласованности данных при исполнении нескольких транзакций одновременно. Различают следующие уровни (по мере повышения строгости и усиления блокировок):

- **Read uncommitted**. Низший уровень изоляции, допускающий чтение незафиксированных данных. В результат чтения могут попасть данные от других, еще не завершившихся операций записи.
- **Read committed.** Чтение уже зафиксированных данных. Данный уровень гарантирует, что в момент чтения данные были ранее зафиксированы, однако позволяет изменять данные сразу после этого. Т.е. повторное чтение внутри транзакции уже не гарантирует получение такого же набора данных.
- **Repeatable read**. Повторяемое чтение данных, при которых нельзя изменять данные до тех пор, пока читающая их транзакция не завершилась.
- **Serializable**. Наивысший уровень изоляции, предполагающий полное упорядочивание (сериализацию) транзакций. Результат выполнения нескольких параллельных транзакций должен быть таким, как если бы они выполнялись последовательно.

### Read phenomena (проблемы чтения данных) {: #read_phenomena }

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

- **Lost update** (потерянное обновление). При одновременном изменении данных разными транзакциями теряются все изменения, кроме последнего.
- **Dirty read** (неточное чтение). В результат чтения добавятся данные, привнесенные другой транзакцией, которая впоследствии будет отменена (не получит статуса committed).
- **Non-repeatable read** (проблема однократного чтения). Несколько последовательных операций чтения одних и тех же данных дают разный результат, т.к. между ними вклинилась сторонняя операция записи.
- **Phantom read** (фантомное чтение). Проблема схожа с предыдущей и также касается изменения данных после начала операции чтения. Однако, “фантомное чтение” предполагает изменение самой выборки (параллельная операция записи добавляет/удаляет строки).

## Термины SQL {: #sql_terms }

В этом подразделе собраны определения терминов, встречающихся при работе с распределенным SQL в Picodata.

### Data Definition Language (DDL) {: #ddl }

Язык описания схемы данных. Набор команд для управления таблицами в SQL (создание/удаление таблиц).

### Data Manipulation Language (DML) {: #dml }

Язык модификации данных. Набор команд для изменения данных в таблицах SQL (вставка/обновление/удаление строк).

### Data Query Language (DQL) {: #dql }

Язык получения данных (команда `SELECT` для чтения данных из таблиц).

### Команда SQL {: #query }

Запрос (и, опционально, значения передаваемых параметров) к базе данных Tarantool на языке SQL.

### План запроса {: #execution_plan }

Схема и последовательность шагов, требуемая для исполнения запрос. План строится на узле-маршрутизаторе и исполняется во всем кластере.

### Строгая функция {: #strict_function }

Если хотя бы один аргумент равен `NULL`, функция вернёт `NULL` без каких-либо вычислений.

### Проекция {: #projection }

Фильтрация или модификация столбцов таблицы.

### Ключ шардирования {: #sharding_key }

Столбец, по которому таблица распределена в кластере.

### Материализация данных {: #data_materialization }

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

### Хранимая процедура {: #stored_procedure }

Представляет собой набор SQL-инструкций для
выполнения DML-операций, т.е. изменения данных в таблице. Такой набор
является отдельным объектом БД и выполняется как единое целое. В простом
виде он может состоять из нужной пользователю DML-команды.

### Опкод {: #opcode }

Опкод — элемент исполнения скомпилированной SQL-программы.
Пользовательские DML- и DQL-запросы преобразуются в программы и исполняются в
Picodata с помощью виртуальной машины VDBE (Virtual Database Engine),
которая оперирует потоком байтовых инструкций (байткодом). Опкод
является частью такой инструкции.

Количество опкодов, необходимых для выполнения SQL-запроса, зависит от
его сложности, наличия дополнительных условий, а также от размера
запрашиваемой таблицы. Запрос, требующий слишком большого числа опкодов,
может надолго заблокировать основной транзакционный поток (tx thread).

### Окно {: #window }

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

### Оконная функция {: #window_function }

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

### Рамка раздела {: #frame }

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

### Раздел окна {: #partition }

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

### Упорядочивание раздела {: #ordering }

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

## Подготовленный запрос {: #prepared_statement }

Prepared Statement (Подготовленный запрос) — это механизм в СУБД для
многократного выполнения SQL-запросов с параметрами, который заранее
компилирует шаблон запроса, а затем подставляет данные, что повышает
производительность (за счет кэширования) и, самое главное, надежно
защищает от SQL-инъекций, разделяя код запроса и данные.
