Чому мій NVMe повільніше за SSD?

Чому мій NVMe повільніше за SSD?
У цій статті ми розглянемо деякі нюанси підсистеми введення-виведення та їх вплив на продуктивність.

Кілька тижнів тому я зіткнувся з питанням, чому NVMe на одному сервері повільніше, ніж SATA на іншому. Подивився в характеристики серверів і зрозумів, що це було питання з каверзою: NVMe був з сегмента користувача, а SSD - з серверного.

Очевидно, що порівнювати продукти з різних сегментів у різному оточенні некоректно, але це не є вичерпною технічною відповіддю. Вивчимо основи, проведемо експерименти та дамо відповідь на поставлене запитання.

Що таке fsync і де він використовується

Для прискорення роботи з накопичувачами дані буферизуються, тобто зберігаються в енергозалежній пам'яті до тих пір, поки не надасться зручний випадок для збереження вмісту буфера на накопичувач. Критерії «зручного випадку» визначаються операційною системою та характеристиками накопичувача. У разі зникнення живлення всі дані в буфері будуть втрачені.

Існує ряд завдань, у яких необхідно бути впевненим, що зміни файлу записані на накопичувач, а чи не лежать у проміжному буфері. Цю впевненість можна отримати під час використання POSIX-сумісного системного виклику fsync. Виклик fsync ініціює примусовий запис із буфера на накопичувач.

Продемонструємо вплив буферів штучним прикладом як короткої програми мовою C.

#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

int main(void) {
    /* Открываем файл answer.txt на запись, если его нет -- создаём */
    int fd = open("answer.txt", O_WRONLY | O_CREAT);
    /* Записываем первый набор данных */
    write(fd, "Answer to the Ultimate Question of Life, The Universe, and Everything: ", 71);
    /* Делаем вид, что проводим вычисления в течение 10 секунд */
    sleep(10);
    /* Записываем результат вычислений */
    write(fd, "42n", 3); 

    return 0;
}

Коментарі добре пояснюють послідовність дій у програмі. Текст «відповідь на головне питання життя, Всесвіту та всього такого» буде буферизований операційною системою, і якщо перезавантажити сервер натисканням на кнопку Reset під час «обчислень», то файл виявиться порожнім. У прикладі втрата тексту не є проблемою, тому fsync не потрібен. Бази даних такого оптимізму не поділяють.

Бази даних - це складні програми, які одночасно працюють з безліччю файлів, тому хочуть бути впевненими, що записані ними дані будуть збережені на накопичувачі, так як від цього залежить консистентність даних усередині БД. Бази даних спроектовані записувати всі завершені транзакції та бути готовими до відключення живлення будь-якої миті. Така поведінка зобов'язує використовувати fsync постійно у великій кількості.

На що впливає часте використання fsync

При звичайному введенні-виводі операційна система намагається оптимізувати спілкування з дисками, тому що в ієрархії пам'яті зовнішні накопичувачі найповільніші. Тому операційна система намагається за одне звернення до накопичувача записати якнайбільше даних.

Продемонструємо вплив використання fsync на конкретному прикладі. Як випробувані у нас такі твердотільні накопичувачі:

  • Intel® DC SSD S4500 480 GB, підключений за SATA 3.2, 6 Гбіт/с;
  • Samsung 970 EVO Plus 500GB, підключений за PCIe 3.0 x4, ~31 Гбіт/с.

Тести проводяться на Intel Xeon W-2255 під керуванням ОС Ubuntu 20.04. Для тестування дисків використається sysbench 1.0.18. На дисках створено один розділ, форматований як ext4. Підготовка до тесту полягає у створенні файлів об'ємом 100 ГБ:

sysbench --test=fileio --file-total-size=100G prepare

Запуск тестів:

# Без fsync
sysbench --num-threads=16 --test=fileio --file-test-mode=rndrw --file-fsync-freq=0 run

# С fsync после каждой записи
sysbench --num-threads=16 --test=fileio --file-test-mode=rndrw --file-fsync-freq=1 run

Результати тестів представлені у таблиці.

Тест
Intel® S4500
Samsung 970 EVO+

Читання без fsync, МіБ/с
5734.89
9028.86

Запис без fsync, МіБ/с
3823.26
6019.24

Читання з fsync, міб/с
37.76
3.27

Запис із fsync, МіБ/с
25.17
2.18

Неважко помітити, що NVMe із клієнтського сегмента впевнено лідирує, коли операційна система сама вирішує, як працювати з дисками, і програє, коли використовується fsync. Звідси виникає два питання:

  1. Чому у тесті без fsync швидкість читання перевищує фізичну пропускну спроможність каналу?
  2. Чому SSD із серверного сегмента краще обробляє велику кількість запитів fsync?

Відповідь на перше запитання проста: sysbench генерує файли, заповнені нулями. Таким чином, тест проводився над 100 гігабайтами нулів. Так як дані дуже одноманітні і передбачувані, в хід вступають різні оптимізації ОС, вони значно прискорюють виконання.

Якщо ставити під сумнів усі результати sysbench, можна скористатися fio.

# Без fsync
fio --name=test1 --blocksize=16k --rw=randrw --iodepth=16 --runtime=60 --rwmixread=60 --fsync=0 --filename=/dev/sdb

# С fsync после каждой записи
fio --name=test1 --blocksize=16k --rw=randrw --iodepth=16 --runtime=60 --rwmixread=60 --fsync=1 --filename=/dev/sdb

Тест
Intel® S4500
Samsung 970 EVO+

Читання без fsync, МіБ/с
45.5
178

Запис без fsync, МіБ/с
30.4
119

Читання з fsync, міб/с
32.6
20.9

Запис із fsync, МіБ/с
21.7
13.9

Тенденція до просідання продуктивності у NVMe при використанні fsync добре помітна. Можна переходити до відповіді друге питання.

Оптимізація чи блеф

Раніше ми говорили, що дані зберігаються в буфері, але не уточнювали в якому саме, тому що це не було принципово. Ми і зараз не заглиблюватимемося в тонкощі операційних систем і виділимо два загальні види буферів:

  • програмний;
  • апаратний.

Під програмним буфером маються на увазі буфери, які є в операційній системі, а під апаратним - енергозалежна пам'ять контролера диска. Системний виклик fsync посилає накопичувачу команду записати дані з його буфера в основне сховище, але не може проконтролювати коректність виконання команди.

Оскільки SSD показує кращі результати, можна зробити два припущення:

  • диск спроектований під навантаження такого плану;
  • диск «блефує» та ігнорує команду.

Нечесну поведінку накопичувача можна побачити, якщо провести тест із зникненням харчування. Перевірити це можна скриптом diskchecker.pl, який був створений в 2005 році.

Даний скрипт вимагає дві фізичні машини – «сервер» та «клієнт». Клієнт записує на диск, що тестується, невеликий обсяг даних, викликає fsync і відправляє серверу інформацію про те, що було записано.

# Запускается на сервере
./diskchecker.pl -l [port]

# Запускается на клиенте
./diskchecker.pl -s <server[:port]> create <file> <size_in_MB>

Після запуску скрипта необхідно знеструмити клієнта і не повертати живлення протягом декількох хвилин. Важливо саме відключити електрики, що тестується, а не просто виконати жорстке вимикання. Через деякий час сервер можна підключати і завантажувати в ОС. Після завантаження ОС необхідно знову запустити diskchecker.pl, але з аргументом перевірити.

./diskchecker.pl -s <server[:port]> verify <file>

Наприкінці перевірки ви побачите кількість помилок. Якщо їх 0, то це означає, що диск витримав випробування. Для виключення успішного для диска збігу причин досвід можна повторити кілька разів.

Наш S4500 не показав помилок при втраті живлення, тобто можна стверджувати, що він готовий до навантажень із великою кількістю викликів fsync.

Висновок

При виборі дисків або готових конфігурацій слід пам'ятати про специфіку завдань, які потрібно вирішити. На перший погляд здається очевидним, що NVMe, тобто SSD з PCIe-інтерфейсом, швидше за «класичний» SATA SSD. Однак, як ми зрозуміли сьогодні, у специфічних умовах та з певними завданнями це може бути не так.

А як ви тестуєте комплектуючі серверів при оренді у IaaS-провайдера?
Чекаємо на вас у коментарях.

Чому мій NVMe повільніше за SSD?

Джерело: habr.com

Додати коментар або відгук