Тестирование собственного NAS. Какие тесты нужны?
К сожалению любая разработка, даже если она ведётся просто по фану, рано или поздно сталкивается с необходимостью формализовать процессы и подходы. С этой проблемой столкнулись и мы. Сравнение производительности уже трёх прототипов вылилось в проблемы, громадные полотна обсуждений, споров, попыток унифицировать тесты и конфигурации стендов. А где унификация тестов, там и их автоматизация.
Какие тесты нам интересно выполнять
Скорость доступа к файлам по сети. Подход — подрубаем одно или несколько устройств к NAS по стабильной сети (желательно гигабитный эзернет), и начинаем писать/читать.
Скорость чтения/записи на сами диски. То есть мы убираем сеть и проверяем только диски.
CPU. Какие операции нужно производить на CPU?
Строго говоря, проанализировав список различных тестов, мы пришли к выводу, что гонять бенчмарки особого смысла нет. По крайней мере в первое время.
Правильнее было бы провести тесты скорости работы целевых сценариев использования NAS и параллельно собирать статистику по загрузке IO, сети и CPU. Ну и провести базовые тесты работы UI у OMV. Условно, дымное тестирование.
Так что первый этап задачи — составить список целевых сценариев!
Сценарии использования NAS
Сценарий «хранить свои данные» слишком пространен. Есть несколько подходов к тому, как мы загружаем данные, делаем ли какую-то обработку и как к этим данным обращаемся.
Базово, сначала обратимся к тому, как именно мы получаем доступ к файлам на NAS. OMV предлагает следующий набор сервисов:
FTP — один из самых очевидных сценариев использования NAS (доступен через использование плагина openmediavault-ftp).
NFS — менее очевидный сценарий, но при использовании исключительно внутри локальной сети вполне годится.
RSync — сценарий понятный и нужный, но не очень ясно, какие требования нужно предъявлять к его производительности. Решили оставить на второй этап.
SMB/CIFS — отличное решение для большинства пользователей. Конечно добавляем в список на тестирование.
SSH — работать с файлами с помощью SCP или WinSCP не так удобно, но зато конфигурация требуется минимальная. Добавляем в список тестов.
Для первого этапа тестирования хватить. На второй этап мы перенесли RSync. Помимо этого напрашивается применение в виде бекапера для флешек. За основу попробуем взять плагин «openmediavault-usbbackup 6.0.2–1».
Нужно уважить истинных параноиков и проверить средства шифрования файлов. В набор плагинов OMV входит «openmediavault-luksencryption 6.0», интегрирующий утилиту LUKS, который мы и решили взять для наших тестов.
Тестирование прямой скорости чтения/записи интересует нас для сравнения различных вариантов архитектуры устройства и для упрощения диагностики проблем. Для этих целей мы планируем использовать утилиту fio.
Ну и на сладкое было бы интересно, как установленные сервисы повлияют на возможность производить бекапы и восстанавливаться из них.
Как я настроил OMV и тестовую среду
Для разработки тестов я не стал использовать наши реальные прототипы, а для большей гибкости решил настроить себе локальное тестовое окружение.
Для этого я создал виртуалку в VirtualBox 7.0.6 (не стал делать это в Докере, так как не очень отдавал себе отчёт, как получится в нём настроить сеть и диски). Поставил образ openmediavault версии 6.0.24–1 (Shaitan) с официального сайта.
К виртуалке с OMV примонтировал 3 диска: один на 50 Гигов, на котором у меня живёт основная система, и 2 диска по 10 Гигов, которые объединил RAID1.
Кроме этого создал пользователя vkovalev и несколько директорий.
На хосте у меня стоит Windows 11, а выполнять тесты мы будем на линукс. Так что нам понадобится ещё одна виртуалка. В качестве ОС я выбрал Debian.
Для организации сети я решил использовать Nat Network в Virtual Box. Такой подход даёт доступ с виртуалок в интернет (а мне это нужно для установки пакетов), и при этом обе виртуалки всегда находятся в рамках одной изолированной подсети и доступны друг другу. Они не светят порты наружу, и я спокойно могу работать из аэропортов, кофеен, вокзалов, отелей через открытые сети, и не бояться, что кто то будет пытаться напакостить. Да, некоторые сервисы хочется выставить наружу, но это решается пробросом портов на хостовый интерфейс. Для начала мне достаточно иметь доступ к веб морде OMV и ssh у обоих машин.
Здесь 192.168.56.1 — это виртуальный интерфейс на хосте, который также не виден извне.
Настройка FTP
FTP сервер настраивал через интерфейс OMV. Никаких специфичных конфигов, просто поставил флажок Enable, сохранил настройки и ребутнулся — FTP сервер запущен.
В этом можно убедиться, взглянув на дашборд:
Далее нужно расшарить директории в FTP и выдать права тестовому пользователю на хотя бы на одну директорию. Директории в FTP мы добавляем через Services→FTP→Shares:
Права доступа можно настроить через User Management→Users→Shared folder privileges:
После чего сделать простой тест с debian-виртуалки:
vkovalev@debian:~$ ftp 10.0.2.5
Connected to 10.0.2.5.
220 ProFTPD Server ready.
Name (10.0.2.5:vkovalev):
331 Password required for vkovalev
Password:
230-Welcome user vkovalev@10.0.2.15 to 127.0.1.1 FTP server.
230-The local time is: Tue Apr 25 06:47:29 2023
230 User vkovalev logged in
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful
150 Opening ASCII mode data connection for file list
drwxrwsrwx 2 root users 4096 Apr 21 09:57 VK_Share
226 Transfer complete
Странно, но директории Music, которую я определённо добавлял, нигде нету. Ну да с этим разберёмся чуть позже. Кажется нужно будет курить мануалы и спецификации FTP ещё не один вечер.
Под капотом у OMV бежит proftpd, а значит с информацией в интернете проблем не будет.
Настройка NFS
Ну, тут всё ещё проще. Протокол не новый, простой как дверь и через OMV в конфиге предлагает одинокую галочку Enable, которую мы и выставили:
после чего пошли шарить директории в Services→NFS→Shares и… почувствовали в первый раз на себе смысл фразы «блеск и нищета опенсорса»:
Как пробелы прокрались в путь имени — загадка. Тем не менее удалить их не сложно:
После чего всё удалось расшарить директории без проблем:
Вот только дашборт показывал, что сервер не поднялся. Получить вменяемых логов из диагностики для nfs-server мне не удалось, ребут не помог — пришлось идти в консоль:
root@openmediavault:~# systemctl status nfs-server
● nfs-server.service - NFS server and services
Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Tue 2023-04-25 13:07:45 EDT; 5min ago
Process: 4671 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=1/FAILURE)
Process: 4672 ExecStopPost=/usr/sbin/exportfs -au (code=exited, status=0/SUCCESS)
Process: 4673 ExecStopPost=/usr/sbin/exportfs -f (code=exited, status=0/SUCCESS)
CPU: 2ms
Apr 25 13:07:45 openmediavault systemd[1]: Starting NFS server and services...
Apr 25 13:07:45 openmediavault exportfs[4671]: exportfs: duplicated export entries:
Apr 25 13:07:45 openmediavault exportfs[4671]: exportfs: 10.0.2.*:/export/Music
Apr 25 13:07:45 openmediavault exportfs[4671]: exportfs: 10.0.2.*:/export/Music
Apr 25 13:07:45 openmediavault systemd[1]: nfs-server.service: Control process exited, code=exited, status=1/FAILURE
Apr 25 13:07:45 openmediavault systemd[1]: nfs-server.service: Failed with result 'exit-code'.
Apr 25 13:07:45 openmediavault systemd[1]: Stopped NFS server and services.
Ну, собственно, проблема ясна. OMV от чего то создал дублирующую запись в конфиге nfs, но в GUI её не отобразил:
Поломанный конфиг выглядел так:
root@openmediavault:~# cat /etc/exports
# This file is auto-generated by openmediavault (https://www.openmediavault.org)
# WARNING: Do not edit this file, your changes will get lost.
# /etc/exports: the access control list for filesystems which may be exported
# to NFS clients. See exports(5).
/export/Music 10.0.2.*(fsid=c4ccafbb-eeda-487f-8d4d-f79f4444c2d5,rw,subtree_check,insecure) 10.0.2.*(fsid=6c36c502-43ef-4c35-b513-35893b5be2a4,rw,subtree_check,insecure)
# NFSv4 - pseudo filesystem root
/export 10.0.2.*(ro,fsid=0,root_squash,no_subtree_check,hide)
После нехитрого фикса:
root@openmediavault:~# cat /etc/exports
This file is auto-generated by openmediavault (https://www.openmediavault.org)
WARNING: Do not edit this file, your changes will get lost.
/etc/exports: the access control list for filesystems which may be exported
to NFS clients. See exports(5).
/export/Music 10.0.2.(fsid=c4ccafbb-eeda-487f-8d4d-f79f4444c2d5,rw,subtree_check,insecure) 10.0.2.(fsid=6c36c502-43ef-4c35-b513-35893b5be2a4,rw,subtree_check,insecure)
/export/Music 10.0.2.*(fsid=c4ccafbb-eeda-487f-8d4d-f79f4444c2d5,rw,subtree_check,insecure)
NFSv4 - pseudo filesystem root
/export 10.0.2.*(ro,fsid=0,root_squash,no_subtree_check,hide)
и ребута сервис поднялся:
и я без проблем смог примонтировать директорию на тестовой виртуалке:
vkovalev@debian:~$ sudo mount -t nfs 10.0.2.5:/Music /home/vkovalev/nfs_music/
vkovalev@debian:~$ ls -l /home/vkovalev/nfs_music/
total 4
-rw-r--r-- 1 root users 433 Apr 25 16:39 yesterday.txt
Hidden text
Проблему с пробелом мы смогли воспроизвести, а вот проблему с поломанным конфигом для NFS воспроизвести так и не вышло. В любом случае сходим на форум OMV и попробуем разобраться.
Настройка SMB/CIFS
Следующий по порядку пункт — это SMB-CIFS. Главным преимуществом этого сценария является удобство и гибкость. Расшаренные директории появятся во вкладке «Сеть» в Проводнике у пользователей Windows. К тому же протокол позволяет гибко настроить права доступа разным пользователям, которые опять же подхватываются компьютерами на базе Windows без лишних телодвижений (в теории). Но так как на нашем тестовом хосте стоит debian, некоторое количество лишних телодвижений совершить придётся.
На стороне OMV включаем сервис:
и добавляем тестовую директорию в список расшаренных с максимальным доступом и минимальными конфигурациями:
кроме того нужно убедиться, что у пользователя есть доступ к выбранной директории:
и что сервис запустился (снова на дашборде):
Ставим smbclient и проверяем подключение:
vkovalev@debian:~$ smbclient --list=10.0.2.5 --user=vkovalev
Enter WORKGROUP\vkovalev's password:
Sharename Type Comment
--------- ---- -------
VK_Share Disk
smb_share Disk
IPC$ IPC IPC Service (openmediavault server)
vkovalev@debian:~$ smbclient //10.0.2.5/smb_share --user=vkovalev
Enter WORKGROUP\vkovalev's password:
Try "help" to get a list of possible commands.
smb: \> mkdir test_smb
smb: \> ls
. D 0 Wed Apr 26 16:14:57 2023
.. D 0 Wed Apr 26 01:43:51 2023
test_smb D 0 Wed Apr 26 16:14:57 2023
10209556 blocks of size 1024. 10193088 blocks available
Настройка SSH
SSH у нас и так включен. Сложностей никаких не было. Стоит отметить, что если пользователь создавался через интерфейс OMV, ему будет запрещено подключаться по ssh по-умолчанию. Требуется явно добавить пользователя в группу ssh:
после чего можно работать с файлами через ssh.
Какие тесты нас интересуют?
В первый этап тестирования мы включили максимально упрощённый набор сценариев, которые, по факту, представляют собой обмен файлами между NAS и другим устройством по сети. И мы хотим не столько убедиться в том, что этот обмен вообще работает, сколько собрать статистику по производительности.То есть нас интересует, насколько быстро будут выполняться операции пользователя. А значит нужно составить список интересующих нас операций. Начнём с простого:
Скачать небольшой файл с NAS;
Загрузить небольшой файл на NAS;
Время выполнения каждой операции запоминается. В идеале тест нужно повторить хотя бы сотню раз для получения надёжных статистических данных.
К чуть более «сложным» сценариям имеет смысл отнести загрузку/скачивание файлов побольше и нескольких файлов за раз.
В качестве инструментов для реализации этих тестов решили взять родимый и хорошо знакомый pytest. Причин несколько:
Инструмент знакомый и понятный (честно говоря, тут можно остановить перечисление, но для имитации профессионального подхода мы сочинили ещё несколько причин);
Легко реализовать многократное выполнение тестов через модуль pytest-repeat;
Легко реализовать централизованный сбор статистики с помощью фикстур. Причём как сбор информации о выполнении конкретного сценария, так и сбор статистики по загрузке CPU, сети, памяти, а также получение логов с непосредственно NAS. Обожаю фикстуры!
Pytest будет перехватывать все вылетающие исключения, и нам не понадобится разруливать их вручную;
Плагины от pytest позволяют выставлять, например, таймауты для тестов. А это крайне полезно для работы с сетью. Обязательно что то будет зависеть, и вылавливание подобных косяков растянется надолго. Но это не заблокирует наши тесты.
Ну и не стоит забывать, что мы ставим целью для себя не точнейшее измерение производительности как таковой, а оценку деградации производительности относительно. А значит для нас важнее обеспечить стабильное и неизменное тестовое окружение, и мы можем просто использовать модуль time для измерения времени, не прибегая к тяжёлой артиллерии.
Я решил накинуть ещё несколько требований к тестам:
Каждый отдельный тест должен быть независимым и самодостаточным. А значит тест на скачивание файла не должен надеяться, что этот файл кто то заботливо положил на NAS.
Тесты «прибираются» после себя.
Мы собираем статистику централизованно. Более того, в случае, если тестовый прогон прервался, при его следующем запуске статистика из предыдущего запуска сохраниться.
Мы должны проверять успешность выполнения операций.
Собранную телеметрию с NAS хочется уметь легко сопоставить с выполнением конкретного теста.
Централизованный сбор статистики
OMV из коробки собирает статистику по загрузке системы:
Все интересующие нас параметры здесь представлены. А значит нужно понять, как OMV собирает эти данные, как их получить нашим тестам и можно ли тюнить для своих нужд.
Покопались и выяснили, что статистика собирается сервисом collectd. Собираемые параметры настраиваются через добавление плагинов. Так же обстоят дела и с настройкой выходного формата данных. А значит следует разобраться, какие же плагины включены в OMV:
vkovalev@openmediavault:/$ systemctl status collectd
● collectd.service - Statistics collection and monitoring daemon
Loaded: loaded (/lib/systemd/system/collectd.service; enabled; vendor preset: enabled)
…
CGroup: /system.slice/rrdcached.service
└─657 /usr/bin/rrdcached -B -F -f 3600 -w 900 -b /var/lib/rrdcached/db/ -j /var/lib/rrdcached/journal/ -p /run/rrdcached.pid -l unix:/run/rrdcached.sock
…
Jun 21 11:56:13 openmediavault collectd[636]: plugin_load: plugin "interface" successfully loaded.
Jun 21 11:56:13 openmediavault collectd[636]: plugin_load: plugin "load" successfully loaded.
Jun 21 11:56:13 openmediavault collectd[636]: plugin_load: plugin "memory" successfully loaded.
Jun 21 11:56:13 openmediavault collectd[636]: plugin_load: plugin "rrdcached" successfully loaded.
Jun 21 11:56:13 openmediavault collectd[636]: plugin_load: plugin "syslog" successfully loaded.
Jun 21 11:56:13 openmediavault collectd[636]: plugin_load: plugin "unixsock" successfully loaded.
Jun 21 11:56:13 openmediavault collectd[636]: plugin_load: plugin "uptime" successfully loaded.
Из этого списка нас в первую очередь интересует плагин rrdcached. В данном конфиге за сохранение и ротацию статистики отвечает именно он. Из строки запуска демона так же можно узнать, где базы данных хранятся: /var/lib/rrdcached/db/.
Выглядит хранилище так:
vkovalev@openmediavault:/var/lib/rrdcached/db/localhost$ ls -l ./**
./cpu-0:
total 1184
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-idle.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-interrupt.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-nice.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-softirq.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-steal.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-system.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-user.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 cpu-wait.rrd
./df-root:
total 444
-rw-r--r-- 1 root root 148648 Jun 26 2023 df_complex-free.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 df_complex-reserved.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 df_complex-used.rrd
./df-srv-dev-disk-by-uuid-19986e30-460f-46f1-bc3b-93f4969261bc:
total 444
-rw-r--r-- 1 root root 148648 Jun 26 2023 df_complex-free.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 df_complex-reserved.rrd
-rw-r--r-- 1 root root 148648 Jun 26 2023 df_complex-used.rrd
…
Проще всего будет не копировать rrd файлы, а распечатать их текстом с помощью rrdtool fetch в текстовом формате, а затем перекладывать в нашу sqlite базу (о которой скажу ниже). Причина тут в том, что я плохо знаком с rrd базами и не понимаю, насколько велика вероятность утащить файл в процессе записи и в результате получить поломанную базу в артифактах. А так мы будем использовать стандартные средства для работы с rrd на удалённом хосте, а локально уже переложим только интересующие нас записи в хранилище статистики. Пожалуй даже не обязательно это делать для каждого теста отдельно. Мы будем дампить в конце тестового прогона. Выглядит дамп примерно так:
vkovalev@openmediavault:/var/lib/rrdcached/db/localhost$ rrdtool fetch cpu-0/cpu-system.rrd LAST --start 1687846410
value
1687846420: 5.4898133849e-01
1687846430: 2.1173014151e-01
1687846440: 4.7654764799e-01
1687846450: 3.8620159875e-01
1687846460: 1.3724487935e-01
1687846470: 4.7653935253e-01
1687846480: 3.2346618324e-01
1687846490: 1.0000089193e-01
1687846500: 4.2420992930e+00
1687846510: 2.6206537216e+00
1687846520: 1.3724560427e-01
…
Что удобно — можно взять только данные за интересующий нас период, легко сопоставить с конкретным тестом, так как у каждой записи есть таймстемп. Вопрос — как всю эту информацию мы будем использовать? На самом деле хотелось бы оставить данное решение на попозже, а пока все собранные данные просто хранить. Для этих целей я бы обошёлся без экзотики и сложил собранные данные в sqlite базу. Так как один тестовый сервер мы можем использовать для проверки разных конфигураций NAS, в этой базе следует хранить не только статистику и результаты тестов, но и версию конфига. Накидал вот такую схему базы данных:
Всё предельно просто. OperationTime — это время выполнения операции копирования/скачивания определённого файла по определённому протоколу. NAS_Configuration — это описание сетапа в свободной форме, без попыток загнать всё в один формат. Остальные таблицы — показатели нагрузки системы на определённый момент времени.
Запись в OperationTime будем делать после каждого прогнанного теста. Статистику будем заносить в конце прогона, и пусть лежит там до лучших времён. Конфигурацию устройства же будем записывать в конфигурационном файле, о чём ниже.
Конфигурация
Ну и напоследок нужно решить проблему гибкой конфигурации. Лучше сделать это сразу и не хардкодить значения. Как хранить конфиги — дело вкуса. Рассуждения на эту тему можно почитать, например, тут. А мы без лишних объяснений просто будем использовать встроенный в python модуль configparser и ini файл. Для удобства сделаем версию конфига «по-умолчанию», чтобы тесты хоть как-то запускались без лишних танцев с бубном.
Подитог
В статье постарался описать, как именно мы обычно размышляем, планируем и проектируем тестовые системы. Сначала нужно исследовать объект тестирования, а также выделить сценарии, которые хотелось бы проверять и автоматизировать. Затем выполнить часть операций вручную, и уже после можно начинать проектировать тестовую систему. На мой взгляд важно держать себя в руках и не бояться:
Оставить некоторые операции не автоматизированными.
Отложить решение сложных проблем на потом.
Собирать гигабайты статистики и логов, не углубляясь в оптимизацию.
Переписать всё заново, когда позже станет ясно, что тесты спроектированы неправильно.
Вооружившись этими принципами мы продолжим разрабатывать нашу тестовую систему в следующих статьях.