Девочка, балансирующая на NVME-over-TCP 2.0

Девочка, балансирующая на NVME-over-TCP 2.0


Привет всем! Рад вас снова видеть, и я счастлив, что вам так понравилась моя предыдущая статья под названием «А все ли врут? Продолжаем издеваться над NVME».

Напомню, что в этой статье я объяснил, как правильно подключить ваш NVME диск удалённо по сети. Не «как расшарить папку на диске?» и не «какой стороной впихивать NVME в компьютер?» а именно «Как подключить ваш NVME диск по сети».

Что вам это даёт? Вы можете подключить NVME диск на одном компьютере в другой компьютер прямо по сети. По самому обыкновенному медному кабелю. И вам не нужно будет устанавливать какие-то левые программы и настраивать что-то сомнительное. Вся система — часть стандартного набора драйверов Linux.

Более того, при наличии сети на 10Gbps вы сможете в полной мере насладиться полной скоростью NVME устройства. Вам будет казаться, что устройство работает как будто на вашем компьютере и с максимальной скоростью. Главное, чтобы сеть позволяла.

Всё это кажется магией, но на самом деле это возможно. И, конечно, у многих из вас это вызвало массу вопросов. Что же, у меня есть ответы. Всё, что вы хотели узнать об NVME-over-TCP, но боялись спросить.

Давайте под кат.

Итак, давайте напомним себе, с чем мы работаем. Нам нужен Linux посвежее. Кажется, ядро 5.8 должно работать. Ядро 5.10 (Debian 11) более-менее работает. А если вы энтузиаст с 5.16, то можно даже и не париться, смело пользуйтесь NVME-over-TCP.

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

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

Начнём с серверных NVME для испытаний. Таких утипутичек я взял четыре штуки.

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

То, что как я надеялся, будет простым методом втыкания SSD в PCIE шину, на поверку вышло странноватым Raid-контроллером, который просто зеркалировал все мои диски. Хорошо, что плата стоила всего лишь 20 долларов, и её можно было демонстративно сжечь за неоправданные ожидания.

Поехали дальше. Диски у нас есть. Осталось добыть что-то, во что их можно впихнуть.

Тестировать — так тестировать, решил я и обзавёлся этими тремя коробками.

В одной из коробок был Dell PowerEdge R620

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

Дисковым сервером у нас будет Dell PowerEdge R730. Те же 48 ядер, 64 гига оперативной памяти, и куча разношёрстных SAS-SSD дисков. В дополнение к нашим NVME, которые мы в него и запихнём.

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

HP A5820x справился с нагрузкой на ура.

Теперь тестовый стенд у нас готов. Заземлились, и с богом.

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

Итак, собираем, устанавливаем, настраиваем. Ставим Debian 11 с ядром 5.10, включаем всё. Работает из коробки.

Запускаем и проверяем состояние дисков на сервере:

Node             SN                   Model                                    Namespace Usage                      Format           FW Rev  
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1     21211U801053         WDC CL SN720 SDAQNTW-512G-2000           1         512.11  GB / 512.11  GB    512   B +  0 B   10109122
/dev/nvme1n1     21211U801229         WDC CL SN720 SDAQNTW-512G-2000           1         512.11  GB / 512.11  GB    512   B +  0 B   10109122
/dev/nvme2n1     21211U801257         WDC CL SN720 SDAQNTW-512G-2000           1         512.11  GB / 512.11  GB    512   B +  0 B   10109122
/dev/nvme3n1     21211U801038         WDC CL SN720 SDAQNTW-512G-2000           1         512.11  GB / 512.11  GB    512   B +  0 B   10109122

Отлично. Наши 4 NVME диска определились и работают как полагается.

В дополнение, просто для того, чтобы сравнить производительность, давайте воспользуемся встроенным PERC r710 контроллером SAS и создадим Raid-5 массив на обыкновенных SAS SSD.

Теперь мы будем следовать инструкции из предыдущей статьи и смонтируем наши NVME диски на клиенте. После чего мы воспользуемся той же процедурой и смонтируем SSD диски на том же клиенте по NVME протоколу.

А что, нам кто-то может запретить это сделать? Нет. Никто не посмеет. Мы можем смонтировать любые block устройства по NVME. Да что там, пока я извращался над системой, я смонтировал LLVM диск, который был расположен на USB2.0 флешке.

И да, это сработало! Никто не запрещает вам монтировать любой block девайс по NVME. Можете монтировать даже HDD.

Давайте ещё раз посмотрим на то, что такое NVME. Ведь это не жёсткие диски. NVM означает Non Volotile Memory. На русский это переводится как «энергонезависимая память». Любая память, которая не будет зависеть от наличия батареек или конденсаторов.

NVME означает NVM Express. Изначально NVM Express был просто протоколом передачи данных от процессора к жёсткому диску. И разрабатывался он специально для NVM жёстких дисков, которые подключались в систему через PCIE.

Старые системы передачи данных, такие как IDE, SATA и SAS просто не могли передавать такое количество информации. Более того, старые протоколы передачи данных были рассчитаны на то, что диски имеют только одну очередь для ввода/вывода данных.

Со временем NVME начал перерастать во что-то более интересное. Просто протокол передачи данных начал разделяться на подсистемы и набор транспортных протоколов. Сам протокол был отвязан от шины PCIE и создатели смогли запихнуть его на другие носители, такие как Fabrics или TCP/IP.

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

В отличие от стандартных SATA устройств, в NVME у вас в распоряжении имеется не одна, а 64 тысячи очередей передачи данных. Вы можете создать 32 тысячи каналов ввода и 32 тысячи каналов вывода информации. Или если вы будете много читать с диска, то можно переконфигурироваться на 8к каналов ввода и 52к каналов вывода. Пожалуйста. Сколько душе угодно.

То есть, вы запросто можете впихнуть любое блочное устройство в протокол NVME. И конечно, ускорения производительности вы не уведите. Жёсткий диск как крутился на скорости 5400 оборотов в секунду, так и продолжит крутиться.

Но, с другой стороны, клиент будет видеть nvme диски только как устройства для ввода-вывода информации. Напомню, что в текущей версии протокола (1.4) жёсткие диски не поддерживаются. Они будут работать по этому протоколу, но NVME может «задушить» жёсткий диск количеством передаваемых инструкций. Копировать данные можно, но если вы пытаетесь делать «быстрый» доступ к диску — забудьте. В данной версии SATA будет быстрее NVME.

Подробнее об экосистеме читайте здесь.

Итак, у нас есть два сервера. На сервере данных у нас есть NVME диски и SAS-SSD Raid-5 массив. На клиенте те же диски подключены через NVME.

Давайте проведём первый тест.

dd if=/dev/zero of=/tmp/test1.img bs=1G count=1 oflag=dsync

Запускаем, проверяем и видим, что творится что-то невообразимо безобразное. Это просто позор.

Ну как сказать. С одной стороны, конечно, позор, а с другой стороны, у нас есть определённые данные, которые выглядят не так плохо.

Для начала, на локальном NVME мы получили скорость записи в 617 мегабайт в секунду. Хотя в рейде смогли выжать все 785. Если посмотреть на спецификации самого жёсткого диска SN720, то мы увидим, что он способен выжимать до 3000 мегабайт на последовательном прочтении. А писать наша модель должна на скорости 2500 в секунду. 617 — это очень далеко от такого показателя.

Ладно, давайте остановимся на этой таблице на секундочку и посмотрим на показатели remote. Это — данные с удалённого сервера, который сидит и пишет на диск через нашу 10-гигабитную сеть. Интересно, в таком синтетическом тесте мы выжали 60% от скорости записи на реальный диск. Неплохо. Но не впечатляет совсем. Давайте найдём утилиту получше.

Пока мы здесь и стенд у нас под рукой, проверим вот что. Включим ioping. Вот время в микросекундах, которое требуется для того, чтобы достучаться до диска. Тут результаты уже немного более интересные. Передача данных от процессора к nvme диску занимает 181 микросекунду. А вот передача данных через сеть добавляет к этому всего лишь 270 микросекунд. Приятно видеть такие показатели. Передача данных через raid массив намного медленнее, а проброс её через сеть занимает всё те же 300 микросекунд.

Кстати, вот полная статистика ioping (Минимум, среднее, максимум, отклонение)

Так, ладно, теперь разберёмся с нашей системой тестирования. Давайте найдём что-нибудь получше dd.

Пробуем

fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=test --filename=test.fio --bs=4k --iodepth=64 --size=4G --readwrite=randrw --rwmixread=75

Хм. Чудеса.

Тут при наших параметрах мы видим, что в рандомной записи 4х гигабайт данных, NVME побеждает всех и вся. Но при этом, удалённо он работает как кусок… Гхм. Никак. Полная фигня короче.

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

Но, эмпирическим путём я выяснил следующее. Если fio передать параметр numjobs и выставить его, например, в 4, то тесты пойдут веселей.

Вот, например, статистика локальных тестов nvme диска, при numjobs=4

Run status group 0 (all jobs):
   READ: bw=1043MiB/s (1093MB/s), 130MiB/s-130MiB/s (136MB/s-137MB/s), io=23.0GiB (25.8GB), run=23554-23564msec
  WRITE: bw=348MiB/s (365MB/s), 43.4MiB/s-43.7MiB/s (45.5MB/s-45.8MB/s), io=8199MiB (8597MB), run=23554-23564msec

Больше именно с fio у меня выжать не получилось. Естественно, потому что это не последовательная запись данных на диск, а рандомный паттерн. Что, в принципе, неплохо.

Но, интересное начинается именно тогда, когда мы переключаемся на удалённый сервер и запускаем fio с numjobs=4 по сети.

Run status group 0 (all jobs):
   READ: bw=950MiB/s (996MB/s), 119MiB/s-123MiB/s (124MB/s-129MB/s), io=2399MiB (2516MB), run=2427-2525msec
  WRITE: bw=317MiB/s (333MB/s), 39.6MiB/s-41.4MiB/s (41.5MB/s-43.4MB/s), io=801MiB (840MB), run=2427-2525msec

БУМ!

А теперь внимание! Скорость записи на диск по сети всего лишь на 10% меньше скорости записи напрямую через PCIE интерфейс.

Однако.

Вот это результат!

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

# cpu-info
Packages:
    0: Intel Xeon E5-2690 v3
Microarchitectures:
    24x Haswell

Увеличение количества потоков банально распределяет нагрузку по разным ядрам, и всё работает куда быстрее.

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

Так что ещё раз, если у вас есть какой-то дельный совет про то, как протестировать это всё с FIO, то дайте знать.

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

nvme list выдавал странные результаты, вместо того, чтобы показывать вот это:

Node                  SN                   Model                                    Namespace Usage                      Format           FW Rev  
--------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
nvme1n2               4765c43fe7fa83e5     Linux                                    5144      419.43  MB / 419.43  MB    512   B +  0 B   5.10.0-1
nvme0n2               b574d76af59e7acf     Linux                                    5143      419.43  MB / 419.43  MB    512   B +  0 B   5.10.0-1

Мне в ответ приходило вот это:

Node                  SN                   Model                                    Namespace Usage                      Format           FW Rev  
--------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
nvme1n2               4765c43fe7fa83e5     Linux                                       -1      419.43  MB / 419.43  MB       0   B +  0 B   5.10.0-1
nvme0n2               b574d76af59e7acf     Linux                                       -1      419.43  MB / 419.43  MB       0   B +  0 B   5.10.0-1

Более того, попытки отключить и подключить диски заново не давали никаких результатов. Функция nvme disconnect-all работала отлично и возвращала нули, но по факту, диски из странного неймспейса -1 продолжали висеть в памяти.

В то же время dmesg | grep nvme показывал постоянные сегфолты.

Единственным способом исправить ситуацию была полная перезагрузка сервера.

И тут, пытаясь понять, почему это происходило — я призадумался. После нескольких попыток найти проблему, я понял, что всё сводилось к нестабильному сетевому порту. Иногда соединение между серверами пропадало, а вместе с ним, вешалась половина системы NVME на обоих серверах.

В попытках это исправить, я начал лазить по nvme github. И сначала выяснил, что мой nvme-cli был бешено отсталым от жизни. Пока я пользовался версией 1.12, в гитхабе числилась 2.0 rc2.

# nvme --version
nvme version 1.12

Хорошо, я скачал и скомпилировал nvme-cli с github.com/linux-nvme/nvme-cli. Так, чисто для информации, если следовать их инструкции, вы сможете скомпилировать бинарники. Но из-за каких-то упавших скриптов из питона — попытка установить их в систему проваливается с треском. Поэтому вместо того, чтобы устанавливать эту утилиту, я просто ограничился использованием бинарника.

# ./nvme --version
nvme version 2.0

Ок, при использовании новой версии утилиты, странные диски с пространством имён -1 пропадали из списка. Но, их всё равно было видно в lsblk.

После этого я полез в исходники ядра Linux и обнаружил, что nvme не забыт и работа над ним ведётся.

Мой модуль версии 5.10 числился за сборкой от Июня 2021 года. Старовато будет, подумал я. Моё ядро 5.10 на целых 6 версий отличается от самого последнего 5.16.

«Ну что же?» — подумал я… И занялся компилированием ядра на сервере, на самую последнюю версию.

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

Итак, после нескольких часов компиляции (потому что моя тупая башка забыла про make -j 48, и я собирал ядро линукса на 48-и процессорной системе в один поток…) проверяем.

# uname -a
Linux dev-vm-1 5.16.8 #2 SMP PREEMPT Wed Feb 9 15:54:42 PST 2022 x86_64 GNU/Linux

Мы на самой последней версии.

Запускаем и смотрим, что же у нас получается.

Для начала — nvme работает как прежде. Он просто работает. И ничего не упало. Ок, хорошо. Серверы Dell славятся хорошей поддержкой Linux. И то приятно.

Пойдём тестировать.

Создаём соединение между дисками.
Запускаем watch ‘dmesg | grep nvme’
Выдёргиваем провода из свитча на ходу и…

[  506.695802] nvme nvme2: creating 48 I/O queues.
[  506.707593] nvme nvme2: mapped 48/0/0 default/read/poll queues.
[  506.732979] nvme nvme2: new ctrl: NQN "05zbcqmysyej9dzgse9yveh9yg", addr 10.22.1.202:5143
[  506.740016] nvme nvme3: creating 48 I/O queues.
[  506.751832] nvme nvme3: mapped 48/0/0 default/read/poll queues.
[  506.773902] nvme nvme3: new ctrl: NQN "05zbcra03ybrvjpw1a7kh7b1mg", addr 10.22.1.202:5144
[  705.041167] nvme nvme3: queue 0: timeout request 0x0 type 4
[  705.041180] nvme nvme3: starting error recovery
[  705.041195] nvme nvme2: queue 0: timeout request 0x0 type 4
[  705.041200] nvme nvme2: starting error recovery
[  705.042836] nvme nvme3: failed nvme_keep_alive_end_io error=10
[  705.042903] nvme nvme2: failed nvme_keep_alive_end_io error=10
[  705.057243] nvme nvme3: Reconnecting in 10 seconds...
[  705.057246] nvme nvme2: Reconnecting in 10 seconds...
[  718.320953] nvme nvme3: failed to connect socket: -110
[  718.320972] nvme nvme2: failed to connect socket: -110
[  718.320975] nvme nvme3: Failed reconnect attempt 1
[  718.320980] nvme nvme3: Reconnecting in 10 seconds...
[  718.320995] nvme nvme2: Failed reconnect attempt 1
[  718.320999] nvme nvme2: Reconnecting in 10 seconds...
[  728.338579] nvme nvme2: creating 48 I/O queues.
[  728.338716] nvme nvme3: creating 48 I/O queues.
[  728.373946] nvme nvme3: mapped 48/0/0 default/read/poll queues.
[  728.373987] nvme nvme2: mapped 48/0/0 default/read/poll queues.
[  728.376019] nvme nvme2: Successfully reconnected (2 attempt)
[  728.376019] nvme nvme3: Successfully reconnected (2 attempt)

Работает!

Мы только что на ходу «выдернули» диск из системы и вставили его обратно. И ничего не упало!

Проверяем ./nvme list

# ./nvme list
Node                  SN                   Model                                    Namespace Usage                      Format           FW Rev  
--------------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
nvme1n2               4765c43fe7fa83e5     Linux                                    5144      419.43  MB / 419.43  MB    512   B +  0 B   5.10.0-1
nvme0n2               b574d76af59e7acf     Linux                                    5143      419.43  MB / 419.43  MB    512   B +  0 B   5.10.0-1

Ура! Никаких больше дисков-фантомов! Всё работает как полагается.

Итак, дети, чего мы добились?

Бывалый сисадмин смотрит на то, как я балансирую на nmve стеке.

Ну, добились мы многого. У нас есть абсолютно новый стек технологий. Он позволяет подключать block устройства по сети (и не только) через всё, что попадётся под руку. Более того, у нас появляется единый протокол для передачи данных между блочными устройствами.

И, если вы не боитесь Linux, то вы можете уже сейчас начинать экспериментировать. Мне эта технология нравится и я в неё верю.

Обязательно пишите ваши параметры к fio. Я запущу их на серверах и дам знать.

 

Источник

Читайте также