# Рекомендации по сайзингу

В данном разделе приведены рекомендации по сайзингу вычислительных
ресурсов при планировании нагрузки на кластер Picodata. Эта информация
поможет вам рассчитать необходимые вычислительные ресурсы для
использования СУБД Picodata.

## Задачи сайзинга {: #sizing_goals }

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

Сайзинг заключается в:

- оптимальном распределении уже имеющихся ресурсов для запуска кластера
  Picodata.

- расчете необходимого количества аппаратных ресурсов для Picodata
  исходя из оценочного размера хранимых данных.

<!--
- фактор репликации
- RPS на подсистему
- размер шарда (Гб)
- желательный RPS на шард, memtx
- желательный RPS на шард, vinyl
- место для ОС с логами (Гб)
- объем RAM в одном сервере (Гб)
- объем дисков на 1 сервер (Гб)
- место под бекапы (Гб)
- количество CPU на шард (MEMTX)
- количество CPU на шард (VINYL)
- размер RAM для данных (%%) (VINYL)
 -->

## Распределение имеющихся ресурсов {: #resources_distribution }

Для одного узла Picodata необходимо:

- **CPU** — при использовании движка `memtx` следует выделять на каждый
  инстанс Picodata 1 ядро CPU. При использовании движка `vinyl` — 3 ядра
  (из-за интенсивного дискового I/O)
- **RAM** — объем выделяемой памяти на инстанс зависит от объема данных,
  который будет на нем храниться (см. [ниже](#sizing_db)), однако
  рекомендуется выделять от 8 ГБ (для движка `memtx`). При распределении
  значительного пула ресурсов RAM рекомендуется выдавать каждому узлу
  Picodata 32 ГБ RAM.
- **дисковое хранение** — для движка `memtx` оптимальный размер
  дискового хранения рассчитывается как трехкратный размер RAM. Для
  движка vinyl рекомендуемое значение можно получить только после
  детального планирования состава и динамики роста БД.

Для определения количества узлов следует разделить [общий размер
БД](#sizing_db) на размер 1 узла (например, 32 ГБ) и умножить результат
на [число реплик].

[число реплик]: ../overview/glossary.md#replication_factor

## Вычисление нагрузки {: #load_estimation }

### Расчет ожидаемого размера БД {: #sizing_db }

Размер БД можно оценить следующим образом:

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

#### Расчет размеров полей {: #sizing_values }

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

Примеры размеров значений разных типов:

Целые числа ([INTEGER]):

- `0-127` — 1 байт (без префикса)
- `127-255` — 2 байта (без префикса)
- `255-65535` — 3 байта (без префикса)
- `65536` — 5 байт (1 префиксный байт + 4 байта uint32)
- `10000000000` — 9 байт (1 префиксный байт + 8 байт uint64)

UUID-идентификаторы ([UUID]):

- `102be9bf-215f-4180-b4c9-cc11983e988d` — 18 байт (2 префиксных байта
  массива + 16 байт для всего значения UUID)

Текст ([TEXT]):

- `abc` — 4 байта (1 префиксный байт + 3 байта на текстовые символы)
- `John Doe` — 9 байт (1 префиксный байт + 8 байт на текстовые символы)

Дата/время ([DATETIME]):

- `2024-10-18 23:59:59` — 10 байт
- `2024-10-18` — 10 байт (отсутствующие значения будут заполнены нулями,
  например `2024-10-18 00:00:00`)

Пустое значение поля (`nil`) в непустом кортеже занимает 1 байт.

[INTEGER]: ../reference/sql_types.md#integer
[UUID]: ../reference/sql_types.md#uuid
[TEXT]: ../reference/sql_types.md#text
[DATETIME]: ../reference/sql_types.md#datetime

#### Расчет размера кортежей {: #sizing_rows }

Размер кортежа представляет собой сумму размеров полей, входящих в его
состав, плюс 4 байта смещения, требуемое форматом `msgpack` для всех
значений кроме `0`/`nil`.

Проиллюстрируем это примерами таблиц с разным числом колонок:


```yaml title="Размер: 5 байт"
+----+
| id |
+====+
| 1  |
+----+
```

```yaml title="Размер: 9 байт"
+----+------+
| id | name |
+===========+
| 1  | bob  |
+----+------+
```

```yaml title="Размер: 27 байт"
+----+------+--------------------------------------+
| id | name | uuid                                 |
+==================================================+
| 1  | bob  | 989259df-7435-429b-86bc-6ecf2c125197 |
+----+------+--------------------------------------+
```

```yaml title="Размер: 30 байт"
+----+------+--------------------------------------+------+
| id | name | uuid                                 | year |
+=========================================================+
| 1  | bob  | 989259df-7435-429b-86bc-6ecf2c125197 | 1989 |
+----+------+--------------------------------------+------+
```

```yaml title="Размер: 18 байт"
+----+------+------+------+----------------------+
| id | name | uuid | year | date                 |
+================================================+
| 1  | nil  | nil  | nil  | 2024-10-18T23:59:59Z |
+----+------+------+------+----------------------+
```

#### Расчет размера таблицы {: #sizing_tables }

Зная размер кортежа, можно рассчитать примерный [размер
таблицы](#sizing_example) без индексов. Для этого размер кортежа в байтах
следует умножить на количество этих кортежей (т.е. строк в таблице). Для
представления величины в Мб нужно полученное значение дважды разделить на 1024.
Пример:

    Размер кортежа: 30 байт
    Количество кортежей: 100 000 000
    Размер таблицы: 30 * 100 000 000 / 1024 /1024 = 2861 Мб

### Расчет индексов БД {: #sizing_indices }

Размер отдельного индекса БД можно оценить следующим образом: количество
кортежей в таблице умножить на 18 (число байт на индексные
данные) и затем умножить на количество индексов в таблице. Если
предполагается, к примеру, иметь 2 индекса для таблицы, то общий размер
можно вычислить так:

    Количество кортежей: 100 000 000
    Количество индексов: 2
    Общий размер индексов в таблице: 100 000 000 * 18 * 2 / 1024 /1024 = 3434 Мб

### Расчет требуемого объема для движка memtx {: #sizing_memtx }

Если в БД будет только одна таблица, то для приведенного выше примера
общий объем памяти, необходимый для хранения с использованием движка
`memtx`, составит 2861 + 3434 = 6301 Мб. Если таблиц будет несколько, то
следует посчитать сумму размеров всех таблиц и всех индексов.

## Пример расчета размера таблицы {: #sizing_example }

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

Реальный размер таблицы в памяти может быть на 5-20% больше (в
зависимости от количества строк, наличия/отсутствия пустых полей т.д.).
Это связано с необходимостью хранить данные бакетов (`bucket_id`) и
особенностью хранения массивов данных в формате `msgpack`.

Для примера сгенерируем тестовую таблицу с помощью [Picostress] —
генератора нагрузки, развиваемого командой Picodata. Исходным файлом
конфигурации для этой таблицы будет [готовый шаблон].

[Picostress]: https://git.picodata.io/core/picostress
[готовый шаблон]: https://git.picodata.io/core/picostress/-/blob/main/scripts/configs/bench.yml

Результирующая таблица будет содержать 100 строк следующего вида:

```yaml title="таблица cars_1"
+----+-----------+--------+--------------------------+-------------------------+
| id | mark      | rating | uid                      | dt                      |
+==============================================================================+
| 0  | RiIicFq   | 0      | 22301fb8-d829-48da-b007- | 1988-01-06T05:14:08+030 |
|    |           |        | b05614969f34             | 0                       |
|----+-----------+--------+--------------------------+-------------------------|
| 1  | RiIicFq   | -2     | 03d00626-73f5-4944-9579- | 1991-04-04T22:14:46+030 |
|    |           |        | 8d340c0a17e8             | 0                       |
|----+-----------+--------+--------------------------+-------------------------|
| 2  | RiIicF    | -2     | f9c93b9d-209d-4fc7-8d92- | 2010-04-16T05:35:24+040 |
|    |           |        | b4a1351f2a09             | 0                       |
|----+-----------+--------+--------------------------+-------------------------|
...
```

При среднем размере кортежа 45-49 байт, фактический размер этой таблицы
в памяти составит 5045 байт.

Экстраполяция при подсчете всегда предполагает некоторую погрешность (до 20%).

<!--
### Расчет прироста размера БД {: #sizing_growth }

Зная базовое значение требуемой памяти для `memtx` (SDB), можно рассчитать его
прирост по следующей формуле:

```
SDU = SDB * (1 + P/100) * KOS
```

где:

- `SDU` — ожидаемый размер БД
- `P` — ожидаемый рост размера БД (в %% в год)
- `KOS` — коэффициент для ОС и кэша (1,2)

Пример для роста в 20%:

    6301 * (1 + 20 / 100) * 1,2 = 9073 Мб

Таким образом, за год эксплуатации БД потребует почти в 1,5 раза больше
ОЗУ, чем изначально, что является реалистичным показателем для
большинства применений.
-->
