Обзоров VPS на Хабре хватает, но почти все сделаны Windows-утилитами и сводятся к тому, какой диск показал «отличный результат». Мне же нужна была батарея, которую можно прогнать по SSH на любой машине, и понимание, что конкретно означает каждое число.
Второй пункт оказался неожиданно объёмным. Я трижды получал красивые результаты, которые не имели отношения к тому, что я думал измерить: скорость оперативки вместо диска, кэш гипервизора вместо носителя, конфиг лимитера вместо производительности. Каждый раз цифры выглядели совершенно правдоподобно, и я бы их спокойно опубликовал.
Поэтому в этой статье: сначала стенд и методика, потом грабли по ходу замера, потом результаты. Ну и длинный список оговорок в конце.
Подопытные
Все характеристики сняты с самих машин (lscpu, free, lsblk, systemd-detect-virt, /etc/os-release).
Провайдер | CPU | Гипервизор | Ядер | RAM, ГБ | Диск, ГБ | Тип диска¹ | ОС |
|---|---|---|---|---|---|---|---|
SmartApe | Intel Xeon Processor (Cascadelake) | kvm | 4 | 1.9 | 40 | NVMe | Ubuntu 26.04 LTS |
IHC.host | Intel Xeon Processor (Cascadelake) | kvm | 4 | 7.8 | 75 | NVMe | Ubuntu 24.04.4 LTS |
Cloud4U | Intel(R) Xeon(R) Gold 6248 CPU @ 2.50GHz | vmware | 4 | 7.8 | 32 | NVMe | Ubuntu 22.04.2 LTS |
RUVDS | Intel(R) Xeon(R) Gold 6152 CPU @ 2.10GHz | hyperv | 4 | 3.8 | 40 | NVMe | Ubuntu 24.04 LTS |
Reg.ru | Intel Xeon Processor (Icelake) | kvm | 4 | 7.8 | 80 | NVMe | Ubuntu 24.04.3 LTS |
¹Тип диска – единственная строка, которая не измерена, а процитирована по заявлению провайдера. Вернусь к этому в разделе с оговорками, там же объясню, почему проверить это изнутри ВМ нельзя.
Методика
Три полных прохода батареи на каждый хост – не три повтора одного теста подряд, а три круга. Так повторы одной метрики разнесены во времени и меньше ловят локальный шум соседей по гипервизору. Пауза 20 с после каждого теста, итог по метрике – медиана трёх проходов. Три точки – это не оценка с погрешностью, так что последний знак в таблицах читайте как ориентир, а не как точность. Хосты обрабатывались последовательно.
Версии инструментов – штатные из репозитория каждой ОС, намеренно не выравнивались: цель была измерить конфигурацию из коробки. fio 3.28 / 3.36 / 3.41, OpenSSL 3.0.2 / 3.0.13 / 3.5.5. Для fio и sysbench разница версий на результат практически не влияет, для openssl – влияет, см. раздел с оговорками.
Диск
Профили – те же четыре, что в CrystalDiskMark: по факту они давно стали стандартом, и результаты легко сопоставить с любыми чужими замерами:
# тестовый файл – ОБЯЗАТЕЛЬНО на дисковом разделе TESTFILE=/var/tmp/fio_test # SEQ1M Q8T1 – потолок в идеальных условиях fio --name=seq1m_q8t1_read --filename=$TESTFILE --size=1G \ --rw=read --bs=1M --iodepth=8 --numjobs=1 \ --ioengine=libaio --direct=1 --runtime=30 --time_based \ --group_reporting # SEQ1M Q1T1 – копирование одного большого файла fio --name=seq1m_q1t1_read --filename=$TESTFILE --size=1G \ --rw=read --bs=1M --iodepth=1 --numjobs=1 \ --ioengine=libaio --direct=1 --runtime=30 --time_based \ --group_reporting # RND4K Q32T1 – отзывчивость под нагрузкой (БД, много мелких файлов) fio --name=rnd4k_q32t1_read --filename=$TESTFILE --size=1G \ --rw=randread --bs=4k --iodepth=32 --numjobs=1 \ --ioengine=libaio --direct=1 --runtime=30 --time_based \ --group_reporting # RND4K Q1T1 – то же, но по одной операции за раз fio --name=rnd4k_q1t1_read --filename=$TESTFILE --size=1G \ --rw=randread --bs=4k --iodepth=1 --numjobs=1 \ --ioengine=libaio --direct=1 --runtime=30 --time_based \ --group_reporting
Для записи – --rw=write и --rw=randwrite соответственно. Плюс отдельная контрольная серия ровно теми же командами, но с --size=6G – зачем, объясняю дальше.
CPU, память, крипто, архиватор
sysbench cpu --cpu-max-prime=20000 --threads=1 --time=30 run sysbench cpu --cpu-max-prime=20000 --threads=4 --time=30 run sysbench memory --memory-block-size=1M --memory-total-size=10G \ --memory-oper=read run sysbench memory --memory-block-size=1M --memory-total-size=10G \ --memory-oper=write run openssl speed -seconds 10 -evp aes-256-cbc openssl speed -seconds 10 sha256 7z b
К слову openssl speed sha256 -seconds 10 падает с Unknown algorithm -seconds. В OpenSSL 3.x опции обязаны идти до имени алгоритма. Правильно будет openssl speed -seconds 10 sha256.
Три грабли
Раздел важный, потому что от него зависит, можно ли верить таблицам ниже. Каждая из ошибок не ломает тест и не выдаёт ничего похожего на сбой – она просто подменяет то, что вы измеряете, и возвращает вполне правдоподобное число. Заметить подмену по самому результату нельзя, только по методике – что я и сделал.
Грабля №1: /tmp – это не диск
Классическое место для тестового файла – /tmp. На SmartApe (Ubuntu 26.04) /tmp смонтирован как tmpfs размером 981 МБ, то есть лежит в оперативной памяти.
В предварительном прогоне я получил у SmartApe 2.5 ГБ/с – файл на 256 МБ помещался в tmpfs целиком, и fio измерил скорость RAM. Цифра абсолютно правдоподобная для NVMe. Я бы её опубликовал.
Проверка по всем пяти хостам:
Хост | /tmp | /var/tmp |
|---|---|---|
SmartApe | tmpfs, 1 ГБ | ext4, 35 ГБ |
IHC.host | ext4, 65 ГБ | ext4, 65 ГБ |
Cloud4U | ext4, 11 ГБ | ext4, 11 ГБ |
RUVDS | ext4, 35 ГБ | ext4, 35 ГБ |
Reg.ru | ext4, 74 ГБ | ext4, 74 ГБ |
Один хост из пяти. Причём именно тот, у которого ОС новее всех.
Тестовый файл переехал в /var/tmp (дисковый раздел на всех пяти), а в скрипт добавлена явная проверка – на tmpfs/ramfs дисковые тесты теперь отказываются стартовать с ошибкой, а не меряют память:
FSTYPE=$(stat -f -c %T "$(dirname "$TESTFILE")") case "$FSTYPE" in tmpfs|ramfs) echo "ОТКАЗ: $(dirname "$TESTFILE") – это $FSTYPE, тут вы измерите RAM" >&2 exit 1 ;; esac
Кто повторяет такие замеры – проверяйте stat -f -c %T /tmp до публикации, а не после.
Грабля №2: --direct=1 не отключает кэш гипервизора
Следите за руками.
--direct=1 в fio отключает страничный кэш внутри гостевой ОС. Кэширование на стороне хоста он не обходит, и изнутри ВМ отключить его невозможно в принципе. А тестовый файл на 1 ГБ целиком помещается в RAM хоста. Механизм такой: первое чтение идёт с носителя, а дальше файл целиком оседает в памяти физического хоста, и все последующие тесты в батарее читают уже оттуда. Вы думаете, что меряете диск, а меряете RAM чужого сервера.
Само по себе внутри одного прогона это не поймать: цифры выглядят естественно. Ловит только контроль на файле, который заметно крупнее – если результат на большом файле резко падает, значит на маленьком вы читали кэш. Поэтому основную батарею я оставил на 1 ГБ (чтобы результаты были сопоставимы между хостами), но добавил контрольную серию теми же командами на файле 6 ГБ.
Провайдер | SEQ1M Q8T1 чт., МБ/с | SEQ1M Q1T1 чт., МБ/с | RND4K Q32T1 чт., IOPS | RND4K Q1T1 чт., IOPS |
|---|---|---|---|---|
SmartApe | 5 387.2 | 1 379.4 | 107 062 | 6 440 |
IHC.host | 2 947.1 | 1 013.3 | 152 516 | 8 095 |
Cloud4U | 3 074.8 | 1 060.9 | 40 302 | 7 903 |
RUVDS | 49.3 (29.9x) | 49.2 (8.8x) | 6 010 (7.9x) | 1 297 |
Reg.ru | 11 243.1 | 1 478.5 | 40 132 | 7 575 |
В скобках – во сколько раз результат на файле 1 ГБ выше контрольного.
Две вещи, без которых таблицу можно прочитать неправильно.
Контроль снят только по чтению – колонки записи в результатах не проверены ничем.
У четырёх хостов из пяти расхождения нет (всё в диапазоне 0.7–1.02x), но это не значит, что цифры проверены. Совпадение исключает кэш меньше 6 ГБ и ничего не говорит про больший, а сколько памяти у хоста, изнутри ВМ не узнать. Тест асимметричен: падение результата – улика, а совпадение не оправдание.
У RUVDS расхождение кратное: последовательное чтение падает с 1 474.8 до 49.3 МБ/с (в 30 раз), случайное Q32 – с 47 510 до 6 010 IOPS. Красивые 1 474.8 МБ/с NVMe на большом файле оказались 49 МБ/с. Причём 49.3 при очереди 8 и 49.2 при очереди 1 – совпадение до 0.2% при восьмикратной разнице очереди, то есть это не скорость носителя, а полка лимитера, в которую упираешься после исчерпания бёрст-кредита.
Отдельно про Reg.ru, и тут честно – я не знаю. Контроль расхождения не выявил, но 10-11 ГБ/с последовательного чтения для рядового VPS-тарифа выглядят оптимистично, и объяснить их я не могу ни одним механизмом целиком. Кэш? За 30 секунд контрольного теста прочитано около 337 ГБ, то есть примерно 56 проходов по файлу в 6 ГБ, – на пятьдесят шестом проходе упреждающее чтение уже ни при чём, это похоже на резидентность. Но тогда rnd4k Q1 на той же машине должен летать, а он даёт 6 046 IOPS, то есть 132 мкс на операцию, – для чтения из оперативки хоста это непозволительно долго.
Две цифры указывают в разные стороны, и изнутри ВМ я их не развожу. Поэтому корректная формулировка такая: для последовательных колонок Reg.ru я не могу определить, что именно измерил. Это верхняя граница виртуального диска вместе со всем, что под ним кэширует, а не скорость носителя. Контроль на 6 ГБ тут не сработал – не потому, что цифры хорошие, а потому, что 6 ГБ для этого хоста оказалось мало.
Грабля №3: слишком ровные цифры – это лимитер
Казалось бы, если три прохода дали почти одинаковый результат – значит, стабильная площадка, ставим плюсик. Но неправдоподобная стабильность обычно означает, что вы упёрлись не в носитель, а в жёсткий QoS-лимит на стороне хранилища. У трёх хостов из пяти так и оказалось.
Хост | Похоже на лимит | Что за этим стоит |
|---|---|---|
IHC.host | 500 МиБ/с на запись | последовательная запись = ровно 526.0 МБ/с во всех шести замерах (Q8 и Q1, три прохода). 526.0 МБ/с – это 501.6 МиБ/с |
Reg.ru | 40 000 IOPS | rnd4k Q32 = 40 132.5–40 132.7 IOPS, разброс между проходами 0.001%. Контроль на 6 ГБ даёт 40 132 – ровно то же самое |
Cloud4U | 40 000 IOPS | rnd4k Q32: чтение 40 329, запись 40 327 – расхождение 0.005% между операциями совершенно разной природы. Контроль на 6 ГБ даёт 40 302, та же полка |
Про Cloud4U стоит сказать отдельно, потому что тут признак другой, чем у Reg.ru. У Reg.ru улика – разброс между проходами: 0.001% на трёх повторах. У Cloud4U разброс в такой детализации я не смотрел, зато совпали чтение и запись. Это разные пути в стеке хранилища: чтение обязано сходить за данными, запись обслуживается write-back кэшем, и на живом носителе они дают разные числа – что видно по остальным хостам выборки (у SmartApe 103 851 против 54 693, почти вдвое). Совпадение до 0.005% означает, что обе операции упираются не в носитель, а в общий для них счётчик.
И отдельное наблюдение, которое я не могу объяснить, но обязан отметить: полка в районе 40 000 IOPS обнаружилась сразу у двоих из трёх – у Reg.ru (kvm) и у Cloud4U (vmware). Разные провайдеры, разные гипервизоры, разные ОС, а число одно. Похоже, 40k – это просто распространённая коммерческая ступень QoS, а не свойство какого-то конкретного железа. Если так, то встретить её вы можете где угодно, и это ещё один аргумент за то, чтобы проверять свои цифры на совпадения, а не радоваться их стабильности.
Результаты
Диск, файл 1 ГБ
Провайдер | Тип¹ | SEQ1M Q8T1 чт. | SEQ1M Q8T1 зап. | SEQ1M Q1T1 чт. | SEQ1M Q1T1 зап. |
|---|---|---|---|---|---|
SmartApe | NVMe | 5 133.0 | 4 269.0 | 1 403.8 | 1 886.4 |
IHC.host | NVMe | 2 768.9 | 526.0 | 1 032.4 | 526.0 |
Cloud4U | NVMe | 2 222.3 | 738.1 | 817.2 | 555.2 |
RUVDS | NVMe | 1 474.8 | 1 420.4 | 434.9 | 798.2 |
Reg.ru | NVMe | 10 229.4 | 7 705.9 | 1 421.5 | 3 163.5 |
Значения – МБ/с. По RUVDS достоверна не отдельная цифра, а пара «бёрст ~1.4 ГБ/с → полка ~50 МБ/с после его исчерпания» – см. граблю №2.
Провайдер | Тип¹ | RND4K Q32T1 чт. | RND4K Q32T1 зап. | RND4K Q1T1 чт. | RND4K Q1T1 зап. |
|---|---|---|---|---|---|
SmartApe | NVMe | 103 851 | 54 693 | 5 064 | 11 721 |
IHC.host | NVMe | 126 076 | 127 760 | 6 416 | 18 476 |
Cloud4U | NVMe | 40 329 | 40 327 | 5 513 | 14 241 |
RUVDS | NVMe | 47 510 | 38 822 | 1 230 | 1 479 |
Reg.ru | NVMe | 40 133 | 40 129 | 6 046 | 14 609 |
Значения – IOPS.
Про колонки записи. У всех пяти хостов запись при очереди 1 быстрее чтения – обычный признак write-back кэша: чтение обязано сходить за данными, а запись считается завершённой, как только её подтвердил кэш. Так что записи в таблицах – это скорее скорость подтверждения, чем гарантированная скорость на носителе.
Кроме уже разобранных лимитеров, тут стоит отметить одну связку. У IHC.host странно смотрится связка «126 тысяч IOPS на случайных операциях» и «526 МБ/с на последовательной записи». Первое – отличный результат, лучший в тесте на Q32-чтении (и 152 516 IOPS в контрольном замере на 6 ГБ). Второе – полка лимитера. Разные метрики упираются в разные ограничения, и это в целом нормально, просто не переносите одну на другую.
CPU и память
Провайдер | sysbench CPU 1 поток | sysbench CPU все ядра | Память чт., МиБ/с | Память зап., МиБ/с |
|---|---|---|---|---|
SmartApe | 341 | 1 353 | 19 321.0 | 15 151.1 |
IHC.host | 363 | 1 449 | 18 951.5 | 15 428.9 |
Cloud4U | 418 | 1 661 | 20 998.0 | 18 180.8 |
RUVDS | 408 | 1 606 | 20 577.8 | 17 274.6 |
Reg.ru | 911 | 3 642 | 21 708.4 | 20 046.3 |
CPU – событий/с, больше лучше.
По sysbench Reg.ru (Icelake) даёт 911 событий/с в один поток против 341–418 у остальных и 3 642 на всех ядрах против 1 353–1 661; масштабирование у всех пяти линейное, ×4 к однопоточному.
Записывать это в «быстрый процессор» я бы не стал: другие счётные тесты отрыва не подтверждают. Относительно второй машины в каждом тесте Reg.ru впереди на 3% по 7-Zip (16 176 против 15 666 у RUVDS), на 14% по AES и на 3% по чтению из памяти – против 118% по sysbench. При этом 7-Zip и sysbench cpu оба целочисленные и оба грузят все ядра, так что расхождение в разы не спишешь ни на архитектуру (Icelake против Cascadelake – это проценты IPC, не разы), ни на соседей по гипервизору – те просадили бы и 7-Zip. Steal time я не снимал ни на одном хосте, поэтому назвать причину уверенно не могу; но аномалия тут скорее у метрики, чем у машины. По прикладной нагрузке – 7-Zip – все пятеро укладываются в 22%.
Остальное совпадает: разница между «Xeon Gold 6248 @ 2.50GHz» и «Xeon Processor (Cascadelake)» в названии не отражает ничего интересного, а по памяти разброс 18 951–21 708 МиБ/с – все пятеро в одной весовой категории.
Крипто и архиватор
Провайдер | AES-256-CBC, МБ/с² | SHA-256, МБ/с² | 7-Zip, MIPS |
|---|---|---|---|
SmartApe | 824.3 | 340.1 | 14 171 |
IHC.host | 758.9 | 345.7 | 13 235 |
Cloud4U | 874.2 | 400.8 | 14 895 |
RUVDS | 841.5 | 397.3 | 15 666 |
Reg.ru | 996.4 | 1 050.2 | 16 176 |
На SHA-256 у Reg.ru отрыв выглядит совсем неприличным – 1 050 против 340–401. Но, полагаю, часть отрыва может давать не процессор, а версия OpenSSL. Их я намеренно не выравнивал, поэтому корректная интерпретация колонки – «производительность связки CPU + штатный OpenSSL этой ОС», а не «производительность CPU». Если вы соберёте одинаковый OpenSSL на всех пяти, разрыв уменьшится; насколько – вопрос нового исследования.
Аномалии и нестабильность
То, что не попало в медианы, но должно попасть в статью.
Хост | Метрика | Что произошло |
|---|---|---|
SmartApe | seq1m_q8t1_write | разброс между проходами ×1.5 (4 269, 4 365, 2 901) |
RUVDS | rnd4k_q32t1_write | разброс между проходами ×1.8 (38 822, 43 702, 24 126) |
Одна из двух строк – у RUVDS. Вместе с кратным расхождением на контрольном замере это складывается в довольно последовательную картину: у этой конфигурации производительность заметно зависит от того, что творится вокруг и сколько вы уже успели прочитать.
Что можно утверждать, а что нет
Дальше идёт моя интерпретация. Выборка по одной машине на провайдера, снята в один заход, поэтому это утверждения про пять конкретных виртуалок. Но, тарифы у них разные. У SmartApe 1.9 ГБ RAM против 7.8 у трёх других, диски от 32 до 80 ГБ, цены я не нормировал. Так что ниже не привычный для восприятия «топ», а что может показать конкретная виртуалка на конкретном тарифе.
IHC.host – случайные операции. 152 516 IOPS на Q32 в контроле и лучший Q1 в выборке (8 095, то есть 124 мкс). Это самый прочный дисковый результат статьи: он и высокий, и не рассыпался на большом файле. Но есть потолок в 526 МБ/с на последовательной записи, и нагруженная запись в него упрётся. Оговорюсь, что 126 076 IOPS из основной таблицы – это те же 492 МиБ/с, подозрительно близко к потолку записи, так что часть Q32-результата может быть той же полкой, только в других единицах. Контрольные 152 516 (596 МиБ/с) её пробивают, значит на чтении лимит либо выше, либо другой.
Cloud4U – второй в выборке по Q1 (7 903 IOPS, 127 мкс), идёт вплотную за лидером. По последовательному чтению среди проверенных тоже второй (3 074.8 МБ/с на контроле). По счётной части в верхней половине: второй AES (874 МБ/с), третий 7-Zip (14 895, от лидера 9%). Но главное, единственная машина без строк в разделе аномалий. Потолок 40k на глубокой очереди у него есть, но это единственный хост, про который я могу точно сказать, где этот потолок проходит: 40 329 на чтении, 40 327 на записи, 40 302 в контроле.
SmartApe – лучшее последовательное чтение из проверенных (5 387 МБ/с) и второй Q32 (107 062). Плюс единственный хост, у которого чтение и запись на Q32 расходятся вдвое (103 851 против 54 693) – по логике грабли №3 это признак живого носителя, а не общего счётчика, и полки я у него не нашёл ни одной. Из минусов – разброс ×1.5 на последовательной записи, худший Q1 из четвёрки (155 мкс) и tmpfs на /tmp меньше гигабайта, о который можно споткнуться далеко за пределами бенчмарков.
Reg.ru – отличные память и 7-Zip, правда, с отрывом в 3%, то есть в пределах шума. Вообще по счётной нагрузке разброс между всеми пятью – 22% по 7-Zip, и на фоне дисковых расхождений в разы это не повод для выбора. Отдельно стоит SHA-256: 1 050 против 340–401 у остальных, но это связка «CPU + штатный OpenSSL», а не свойство машины, так что переносить эту цифру на выбор хостера я бы не стал. Также потолок 40k на глубокой очереди и последовательные числа, но ориентироваться на них при выборе я бы тоже не стал, выше уже объяснял почему.
RUVDS – по счётной части претензий нет: второй 7-Zip (15 666 MIPS). По диску – 771 мкс на операцию при Q1 и полка ~50 МБ/с, в которую упирается и Q8, и Q1 (49.3 и 49.2 – совпадение до 0.2% при восьмикратной разнице очереди). Плюс обе строки раздела аномалий с разбросом ×1.5–1.8. Что именно даёт верхние цифры – бёрст-кредит или кэш хоста, – я не развёл: за 30 секунд теста на 1 474.8 МБ/с прочитано около 44 ГБ, и кредита такого объёма при полке 50 МБ/с не бывает, так что на кэш это похоже больше. Практический вывод одинаков в обоих случаях: эту машину надо мерить своей нагрузкой, а не бенчмарком, промежуточных состояний тут не видно.
И то, ради чего всё писалось
Дисковых чисел в этой статье сорок. Как минимум три из тех, что я собирался публиковать, оказались неправдой: 2.5 ГБ/с у SmartApe были скоростью RAM, 1 474.8 МБ/с у RUVDS – кэшем или бёрстом, но не носителем, «стабильные» 40 132 IOPS у Reg.ru – не диском, а конфигом лимитера. Все три выглядели совершенно нормально, и ни одну из них нельзя было опознать по самому результату – только по методике.
Оговорки
Тип носителя не измерен, а процитирован. Столбец «Тип диска» заполнен по заявлению провайдера. Изнутри гостевой ОС тип носителя не верифицируется: ни одного nvme*-устройства гость не видит ни на одном хосте, а флаг ROTA в виртуалках недостоверен – у части хостов он равен 1 (как у вращающегося диска), у части 0, притом что заявленный тип носителя у всех пяти одинаковый. То есть флаг не различает даже одинаковые конфигурации. Проверить можно самим:
lsblk -d -o NAME,ROTA,MODEL ls /dev/nvme* 2>/dev/null || echo "nvme-устройств не видно"
Меряется виртуальный диск, а не носитель. Все диски виртуальные (virtio / QEMU / VMware / Hyper-V). Результаты отражают производительность виртуального диска так, как её видит гостевая ОС, включая накладные расходы виртуализации.
--direct=1 не отключает кэш гипервизора. Флаг обходит кэш только внутри гостя; на стороне хоста изнутри ВМ его не отключить. Контроль на большем файле необходим, но недостаточен.
Маленький вывод
Скорее всего мой маленький эксперимент столкнётся с критикой – но лучше дайте советов на будущее. Полагаю, это не последний мой тест и ваши замечания будут крайне полезны.
Также, если у вас есть машины у этих же или других провайдеров – прогоните команды из раздела «Методика» и киньте цифры в комментарии, особенно контроль на 6 ГБ. Мне сильно интереснее собрать выборку больше одной машины на хостера, чем защищать текущую таблицу.
И главное, ради чего всё писалось: перед публикацией любых дисковых замеров с VPS сделайте три вещи – проверьте stat -f -c %T на каталоге с тестовым файлом, повторите тест на файле, заметно превышающем вашу собственную RAM (и помните, что даже это не гарантирует выход за пределы кэша хоста – его объём вам неизвестен), и посмотрите на разброс между проходами. Работы немного, зато вы хотя бы будете знать, чего ваши цифры не доказывают.

