[Документация](../../README-ru.md#документация) → Использование → VitastorFS и псевдо-ФС

-----

[Read in English](nfs.en.md)

# VitastorFS и псевдо-ФС

В Vitastor есть две реализации файловой системы. Обе используются через `vitastor-nfs`.

Команды:
- [mount](#mount)
- [start](#start)
- [upgrade](#upgrade)
- [defrag](#defrag)

⚠️ Важно: для оптимальной производительности Vitastor NFS в Linux при использовании
HDD и EC (erasure кодов) выполните инструкции из раздела [Размер записи Linux NFS](#размер-записи-linux-nfs).

## Псевдо-ФС

Упрощённая реализация псевдо-ФС используется для эмуляции файлового доступа к блочным
образам Vitastor. Это не полноценная файловая система - в ней отсутствуют многие функции
POSIX ФС, а метаданные всех файлов (образов) сохраняются в etcd и всё время хранятся в
оперативной памяти - то есть, псевдо-ФС подходит для сотен или тысяч файлов, но не миллионов.

Псевдо-ФС предназначена для доступа к образам виртуальных машин в средах, где другие
способы невозможны или неудобны - например, в VMWare. Для VMWare это лучшая опция, чем
iSCSI, так как при использовании iSCSI VMWare размещает все виртуальные машины в одном
большом блочном образе внутри собственной ФС VMFS, а с NFS VMFS не используется и каждый
диск ВМ представляется в виде одного файла, то есть, соответствует одному блочному образу
Vitastor, как это и задумано изначально.

Чтобы подключить псевдо-ФС Vitastor, выполните команду `vitastor-nfs mount --block /mnt/vita`.

Либо же запустите сетевой вариант сервера:

```
vitastor-nfs start --block --etcd_address 192.168.5.10:2379 --portmap 0 --port 2050 --pool testpool
```

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

```
mount server:/ /mnt/ -o port=2050,mountport=2050,nfsvers=3,soft,nolock,tcp
```

## VitastorFS

VitastorFS - полноценная кластерная (Read-Write-Many) файловая система. Она поддерживает
большую часть функций POSIX - иерархическую организацию, символические ссылки, жёсткие
ссылки, быстрые переименования и так далее.

Метаданные VitastorFS хранятся в собственной реализации БД формата ключ-значения,
основанной на Параллельном Оптимистичном Б-дереве поверх обычного блочного образа Vitastor.
И записи каталогов, и иноды, как обычно в Vitastor, хранятся в простом человекочитаемом
JSON-формате :-). Для инспекции содержимого БД можно использовать инструмент `vitastor-kv`.

Чтобы использовать VitastorFS:

1. Создайте пул для данных ФС или выберите существующий пустой пул
2. Создайте блочный образ для метаданных ФС, желательно, в более быстром пуле (на SSD
   или по крайней мере на HDD, но без EC), но можно и в том же пуле, что данные
   (размер образа значения не имеет):
   `vitastor-cli create -s 10G -p fastpool testfs`
3. Пометьте пул данных как ФС-пул: `vitastor-cli modify-pool --used-for-app fs:testfs data-pool`
4. Либо примонтируйте ФС: `vitastor-nfs mount --fs testfs --pool data-pool /mnt/vita`
5. Либо запустите сетевой NFS-сервер: `vitastor-nfs start --fs testfs --pool data-pool`

### Поддерживаемые функции POSIX

- Чтение актуальной версии данных сразу после записи
- Последовательное и произвольное чтение и запись
- Запись за пределами текущего размера файла
- Иерархическая организация, мгновенное переименование файлов и каталогов
- Изменение размера файла (truncate)
- Права на файлы (chmod/chown)
- Фиксация данных на диски (когда необходимо) (fsync)
- Символические ссылки
- Жёсткие ссылки
- Специальные файлы (устройства, сокеты, каналы)
- Отслеживание времён модификации (mtime), изменения атрибутов (ctime)
- Ручное изменение времён модификации (mtime), последнего доступа (atime)
- Корректная обработка изменений списка файлов во время листинга

### Ограничения

Отсутствующие на данный момент в VitastorFS функции POSIX:
- Блокировки файлов не поддерживаются
- Фактически занятое файлами место не подсчитывается и не возвращается вызовами
  stat(2), так что `du` всегда показывает сумму размеров файлов, а не фактически занятое место
- Времена доступа (`atime`) не отслеживаются (как будто ФС смонтирована с `-o noatime`)
- Времена модификации (`mtime`) отслеживаются асинхронно (как будто ФС смонтирована с `-o lazytime`)
- Привилегии доступа по умолчанию не проверяются сервером (клиент NFS Linux их также не проверяет).
  Чтобы включить проверки, используйте опцию `--enforce 1`.

Другие недостающие функции, которые нужно добавить в будущем:
- Переиспользование номеров инодов. В текущей реализации номера инодов всё время
  увеличиваются, так что в теории вы можете упереться в лимит, если насоздаёте
  и наудаляете больше, чем 2^48 файлов.
- Очистка места в Б-дереве метаданных. Текущая реализация никогда не сливает и не
  удаляет блоки Б-дерева, так что в теории дерево может разростись и стать неоптимальным.
  Если вы столкнётесь с такой ситуацией сейчас, вы можете решить её с помощью
  команд `vitastor-kv dumpjson` и `loadjson` (т.е. пересоздав и загрузив обратно все метаданные ФС).
- Инструмент проверки метаданных файловой системы. У VitastorFS нет журнала, так как
  журнал бы сильно замедлил реализацию, вместо него используются оптимистичные
  транзакции на основе CAS (сравнить-и-записать), и теоретически при нештатном
  завершении сервера ФС в БД также могут оставаться неконсистентные "мусорные"
  записи. ФС устроена так, что на работу они не влияют, но для порядка и их стоит
  уметь подчищать.

## Размер записи Linux NFS

Клиент Linux NFS (модули ядра nfs/nfsv3/nfsv4) имеет фиксированный в коде максимальный
размер запроса ввода-вывода, равный 1 МБ - см. `rsize` и `wsize` в [man 5 nfs](https://linux.die.net/man/5/nfs).

Это означает, что когда вы записываете в файл в примонтированной по NFS файловой системе,
максимальный размер запроса записи составляет 1 МБ, даже в режиме O_DIRECT и даже если
исходный запрос записи был больше.

Однако для оптимальной скорости линейной записи в Vitastor при использовании EC-пулов
(пулов с кодами коррекции ошибок) запросы записи должны быть по размеру кратны
[block_size](../config/layout-cluster.ru.md#block_size), умноженному на число частей
данных пула ([pg_size](../config/pool.ru.md#pg_size)-[parity_chunks](../config/pool.ru.md#parity_chunks)).
Если запросы записи меньше или не кратны, то Vitastor приходится сначала прочитать
с дисков старые версии парных блоков данных, рассчитать новые блоки чётности и только
после этого записать их на диски. Естественно, это в 2-3 раза медленнее простой записи
на диск.

При этом block_size на жёстких дисках по умолчанию устанавливается равным 1 МБ.
Таким образом, если вы используете EC 2+1 и HDD, для оптимальной скорости записи вам
нужно, чтобы NFS-клиент писал по 2 МБ, если EC 4+1 и HDD - то по 4 МБ, и т.п.

А Linux NFS-клиент пишет только по 1 МБ. 😢

Но это можно исправить, пересобрав модули ядра Linux NFS 😉 🤩! Для этого нужно
поменять значение переменной NFS_MAX_FILE_IO_SIZE в заголовочном файле nfs_xdr.h,
после чего пересобрать модули NFS.

Инструкция по пересборке на примере Debian (выполнять под root):

```
# скачиваем заголовки для сборки модулей для текущего ядра Linux
apt-get install linux-headers-`uname -r`

# заменяем в заголовках NFS_MAX_FILE_IO_SIZE на желаемый (здесь 4194304 - 4 МБ)
sed -i 's/NFS_MAX_FILE_IO_SIZE\s*.*/NFS_MAX_FILE_IO_SIZE\t(4194304U)/' /lib/modules/`uname -r`/source/include/linux/nfs_xdr.h

# скачиваем исходный код текущего ядра
mkdir linux_src
cd linux_src
apt-get source linux-image-`uname -r`-unsigned

# собираем модули NFS
cd linux-*/fs/nfs
make -C /lib/modules/`uname -r`/build M=$PWD -j8 modules
make -C /lib/modules/`uname -r`/build M=$PWD modules_install

# убираем в сторону штатные модули NFS
mv /lib/modules/`uname -r`/kernel/fs/nfs ~/nfs_orig_`uname -r`
depmod -a

# выгружаем старые модули и загружаем новые
rmmod nfsv3 nfs
modprobe nfsv3
```

После такой (относительно нехитрой 🙂) манипуляции NFS начинает по умолчанию
монтироваться с новыми wsize и rsize, и производительность линейной записи в Vitastor-NFS
исправляется.

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

Клиент Linux NFS 3.0 не поддерживает встроенное масштабирование или отказоустойчивость.
То есть, вы не можете задать несколько адресов серверов при монтировании ФС.

Однако вы можете использовать любые стандартные сетевые балансировщики нагрузки
или схемы с отказоустойчивостью. Это точно безопасно при настройках `immediate_commit=all` и
`client_enable_writeback=false`, так как с ними NFS-сервер Vitastor вообще не хранит
в памяти ещё не зафиксированные на дисках данные; и вполне вероятно безопасно
даже без `immediate_commit=all`, потому что NFS-клиент ядра Linux повторяет все
незафиксированные запросы при потере соединения.

## RDMA

vitastor-nfs поддерживает NFS через RDMA. В теории это также должно позволять использовать
VitastorFS из GPUDirect.

Вы можете протестировать NFS-RDMA, даже если у вас нет RDMA-карты, с помощью SoftROCE:

1. Сначала создайте SoftROCE устройства на обоих тестовых серверах: `rdma link add rxe0 type rxe netdev eth0`.
   Утилита `rdma` входит в состав пакета iproute2, а `eth0` вам нужно заменить на имя своей
   сетевой карты.

2. Запустите vitastor-nfs с RDMA: `vitastor-nfs start (--fs <NAME> | --block) --pool <POOL> --port 20049 --nfs_rdma 20049 --portmap 0`

3. Смонтируйте ФС: `mount 192.168.0.10:/mnt/test/ /mnt/vita/ -o port=20049,mountport=20049,nfsvers=3,soft,nolock,rdma`

## Команды

### mount

`vitastor-nfs (--fs <NAME> | --block) mount [-o <OPT>] <MOUNTPOINT>`

Запустить локальный сервер и примонтировать ФС в директорию <MOUNTPOINT>.

Чтобы отмонтировать ФС, используйте обычную команду `umount <MOUNTPOINT>`.

Сервер автоматически останавливается при отмонтировании ФС.

- `-o|--options <OPT>` - Передать дополнительные опции монтирования NFS (пример: -o async).

### start

`vitastor-nfs (--fs <NAME> | --block) start`

Запустить сетевой NFS-сервер. Опции:

| <!-- -->               | <!-- -->                                                                                                                    |
|------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| `--bind <IP>`          | принимать соединения по адресу \<IP> (по умолчанию 0.0.0.0 - на всех)                                                       |
| `--port <PORT>`        | использовать порт \<PORT> для NFS-сервисов (по умолчанию 2049). Укажите "auto", чтобы выбрать и напечатать случайный порт   |
| `--portmap 0`          | отключить сервис portmap/rpcbind на порту 111 (по умолчанию включён и требует root привилегий)                              |
| `--nfs_rdma <PORT>`    | включить NFS-RDMA на порту RDMA-CM \<PORT> (попробуйте 20049). Если RDMA включено и указано `--port 0`, TCP будет отключено |
| `--nfs_rdma_credit 16` | максимальный "кредит", глубина очереди для NFS-клиентов                                                                     |
| `--nfs_rdma_send 1024` | максимальное число операций RDMA отправки (должно быть больше nfs_rdma_credit)                                              |
| `--nfs_rdma_alloc 1M`  | округление выделения памяти для RDMA-клиентов                                                                               |
| `--nfs_rdma_gc 64M`    | максимальный объём неиспользуемой памяти RDMA-клиентом перед освобождением                                                  |

### upgrade

`vitastor-nfs --fs <NAME> upgrade`

Обновить метаданные ФС. Можно запускать онлайн (при запущенных серверах NFS), но после выполнения их всё
же желательно перезапустить.

### defrag

`vitastor-nfs --fs <NAME> defrag [OPTIONS] [--dry-run]`

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

На уровне реализации ФС файлы, меньшие, чем размер объекта пула (block_size умножить на число
частей данных, если пул EC), упаковываются друг за другом в большие "тома" / "общие иноды".
Когда такие файлы удаляются или увеличиваются, они перемещаются и оставляют за собой "мусор".

При дефрагментации мусор удаляется, а всё ещё используемые данные перемещаются в новые тома.

Опции:

| <!-- -->                   | <!-- -->                                                                |
|----------------------------|------------------------------------------------------------------------ |
| `--volume_untouched 86400` | Дефрагментировать только тома, в которые уже не писали это число секунд |
| `--defrag_percent 50`      | Дефрагментировать только тома, в которых этот % данных удалён           |
| `--defrag_block_count 16`  | Читать это количество блоков пула за один раз                           |
| `--defrag_iodepth 16`      | Перемещать одновременно до этого числа файлов                           |
| `--trace`                  | Печатать детальную статистику дефрагментации                            |
| `--dry-run`                | Не производить никаких изменений, только описать выполняемые действия   |
| `--recalc-stats`           | Пересчитать и сохранить статистику всех томов                           |
| `--include-empty`          | Дефрагментировать старые и пустые тома; обязательно перезапустите NFS-сервера после использования этой опции |
| `--no-rm`                  | Перемещать, но не удалять данные                                        |

## Общие опции

| <!-- -->           | <!-- -->                                                |
|--------------------|---------------------------------------------------------|
| `--fs <NAME>`      | использовать VitastorFS с метаданными в образе \<NAME>  |
| `--block`          | использовать псевдо-ФС для доступа к блочным образам    |
| `--pool <POOL>`    | использовать пул \<POOL> для новых файлов (обязательно, если пул в кластере не один) |
| `--subdir <DIR>`   | экспортировать подкаталог \<DIR>, а не корень (только для псевдо-ФС) |
| `--nfspath <PATH>` | установить путь NFS-экспорта в \<PATH> (по умолчанию /) |
| `--pidfile <FILE>` | записать ID процесса в заданный файл                    |
| `--logfile <FILE>` | записывать логи в заданный файл                         |
| `--enforce 1`      | проверять права доступа на стороне сервера (по умолчанию нет) |
| `--foreground 1`   | не уходить в фон после запуска                          |
