
Представьте гиперноду облака. Гипернода - это физический сервер с запущенным гипервизором, на котором работают виртуальные машины клиентов. Под дисками этих машин лежит программно определяемое хранилище (SDS) Ceph: распределенная система, где данные размазаны по многим серверам с копиями, без отдельного дискового массива. Меняем на ноде одну переменную — операционную систему. Виртуальные машины не пересобираем, кластер хранения не трогаем, диски и сеть те же. Ни одной новой железки, ни строчки нового кода в приложении. После переключения дисковая подсистема ВМ ведет себя ощутимо иначе.
VK Cloud активно использует Операционную Систему РЕД ОС от РЕД СОФТ в публичном облаке на гипернодах и в том числе в VK Secure Cloud. На ее примере покажу, как поднять производительность гипервизора, просто обновив легаси и не трогая железо. Вместе с дистрибутивом на ноду приезжает свежий стек целиком: ядро, эмулятор, клиент хранилища, системные библиотеки. Каждый слой подтягивает свой кусок. Ниже разберу механику по слоям с командами, которые можно выполнить на своей системе.
Под какие требования замена ОС критична, помимо ИТ
Часть обязательных мер ИБ закрывается на уровне ОС: защита от несанкционированного доступа, разграничение прав, регистрация событий. Для дополнительных требований есть сертифицированная редакция РЕД ОС, которая дает их встроенными, а VK Secure Cloud добавляет аттестацию всей инфраструктуры в купе..
Краткие вводные и загадка производительности стека
Вернемся к гиперноде облака. Поменяли одну переменную - ОС на гиперноде, а дисковая подсистема виртуальных машин выдает заметно больше операций ввода-вывода на смешанной нагрузке. Приложение и хранилище не трогали. Откуда взялась дельта?
Первая реакция инженера правильная: это подозрительно. Ответ лежит не в приложении и не в железе, а в слое между ними — в системных пакетах и библиотеках, которые обновляются вместе с операционной системой.

Но сначала про главную ловушку, в которую попадают при апгрейде легаси.
Ядро — это не вся ОС
Типичная попытка оживить старый CentOS выглядит так: ядро устарело, накатываем свежее ядро отдельным репозиторием, остальное не трогаем. После этого система формально на новом ядре и кажется современной. На обновленной ноде это проверяется одной командой:
uname -r
Ядро действительно новое. А теперь смотрим, что под ним:
rpm -q qemu-kvm libvirt
Выясняется, что эмулятор и управляющий демон остались от старого дистрибутива. Ядро умеет современные механизмы ввода-вывода, эмулятор про них не знает и не вызывает. Свежий мотор прикрутили, коробка передач осталась от прежней модели. Половину возможностей ядра гипервизор просто не использует.
Конкретный пример - движок io_uring. Это интерфейс ядра Linux для асинхронного ввода-вывода, который Jens Axboe добавил в 2019 году (ядро 5.1) как быструю замену старому механизму AIO. Вызывать его эмулятор QEMU научился с версии 5.0. Нужны обе половины одновременно. Если ядро 5.10, а эмулятор остался старым, диск ВМ ходит через старые механизмы - потоковую модель или legacy native - и io_uring не задействуется в принципе. Подмена одного ядра этот разрыв не лечит.
РЕД ОС 7.3 под кодовым именем МУРОМ собрана на пакетной базе RPM-формата и архитектурно близка семейству RHEL, так что переезд с CentOS не ломает привычек. Ядро Linux 5.10 на старте, в актуальных релизах РЕД ОС 7.3 по умолчанию идет LTS-ядро 6.1. LTS (long-term support) - ядро с длинным сроком поддержки и обновлений безопасности. Главное: вместе с ядром обновляется и пользовательское окружение. Дистрибутив - это согласованный набор пакетов и ядра, собранный и протестированный вместе. Когда переходишь на РЕД ОС, меняешь весь набор разом, а не одну деталь. Отсюда и эффект.
ABI и динамическая линковка
Почему ускорился код, который никто не переписывал? Здесь самое контринтуитивное место, и его стоит проговорить - именно без него прирост выглядит какой-то магией.
Начнем с того, как программа берет чужой код. Эмулятору нужны типовые операции: работа с памятью, сетью, шифрованием, обращение к хранилищу. Он не носит этот код внутри себя, а берет из системных библиотек. Две из них сейчас важны: glibc отвечает за память, потоки и блокировки, librbd - за работу с хранилищем Ceph.
Связать программу с библиотекой можно двумя способами:
При статической линковке код библиотеки вшивается в программу при сборке, и обновить его можно только пересборкой. Так почти ничего в системе не работает.
При динамической линковке программа хранит только ссылку, а сам код подтягивает из системы в момент запуска - файлы вида
libc.soиlibrbd.so. Так линкуется почти весь системный стек, включая эмулятор.
Вывод прямой: эмулятор не носит библиотеки внутри, он берет их из системы. Обновили систему - эмулятор взял новые библиотеки, сам ни на байт не изменившись.
Вот и ответ на загадку. Между версиями библиотеки переписывают внутренности: убирают лишние блокировки, добавляют векторные инструкции процессора, меняют алгоритмы кэширования. Снаружи вызов остается прежним, внутри код стал быстрее. Это и есть совместимость по ABI (Application Binary Interface): старый вызов работает с новой, более быстрой реализацией. Приложение в ВМ не менялось, вызовы те же самые, но под ними теперь новый код glibc и librbd. Ускорение пришло без единой строчки правок в самом приложении. Подменой только ядра этого не получить: библиотеки живут в пользовательском окружении, а не в ядре.
Что приехало с дистрибутивом
Давайте пройдемся по каждому слою отдельно: что это за модуль, где была проблема на старом стеке и что изменилось. Версии приведу как порог технологии, проверять состав нужно на своей системе.
Слой 1. io_uring в эмуляторе
Что это. Эмулятор (QEMU) - программа на гиперноде, которая изображает для виртуальной машины настоящий компьютер, включая диск. Каждое обращение ВМ к диску он превращает в запрос к ядру хоста. io_uring - это способ, которым эмулятор отдает эти операции ядру Linux. От него зависит, сколько запросов ВМ успевает обработать и с какой задержкой.
Где была проблема. Эмулятор прежнего поколения умел только синхронные движки: на каждую операцию с диском - отдельный поток и блокировка на системном вызове. Тысячи операций в секунду, и переключения между пользовательским пространством и режимом ядра сами начинают съедать время. Тормозил не диск - тормозили бесконечные обращения к ядру.

Что сделали. io_uring заводит между программой и ядром два общих списка прямо в памяти: очередь заявок и очередь готовых ответов. Заявки складываются пачкой, ответы забираются пачкой, переключений контекста становится в разы меньше. На уровне libvirt движок включается в описании диска ВМ:
xml
<iothreads>4</iothreads> ... <disk type='network' device='disk'> <driver name='qemu' type='raw' cache='none' io='io_uring' iothread='1' queues='4'/> <source protocol='rbd' name='pool/vm-disk'/> </disk>
Проверка на ноде. rpm -q qemu-kvm и uname -r. Если эмулятор 5.0 и новее, а ядро 5.1 и новее - io_uring доступен. По публичному докладу по io_uring в KVM, это дает порядка двукратного роста числа операций и вдвое меньшую задержку относительно старого пути, с выходом на 80–90% производительности bare metal.

Почему так быстрее. Снимаются блокировки на системных вызовах и падает задержка на смешанном вводе-выводе, особенно на RBD-дисках Ceph. Механизм требует одновременно современного ядра и актуального эмулятора - на устаревшем окружении его просто нет.
Слой 2. IOThreads и multi-queue
Что это. Модель потоков, обслуживающих диски виртуальной машины. Она определяет, идет ли ввод-вывод параллельно или через одно узкое горлышко. Virtio-blk - виртуальный дисковый контроллер, который ВМ видит вместо физического. У него есть очереди запросов, и важно, сколько их.
Где была проблема. В управляющем слое прежнего поколения все диски ВМ обслуживал один поток эмулятора, а очереди virtio-blk не параллелились. Все ядра виртуалки толкались за один внутренний замок: добавляешь ВМ ядер, а быстрее она не становится, свободные ядра сервера простаивают.

Что сделали. Современный управляющий слой из коробки назначает отдельный IOThread на каждый диск, а virtio-blk multi-queue раскидывает очереди по числу виртуальных процессоров. Включается парой <iothreads> на домене и параметрами queues и iothread в описании диска (фрагмент выше).

Почему быстрее. Ввод-вывод разных дисков и очередей идет одновременно и масштабируется по ядрам. На многоядерных ВМ это убирает узкое горлышко, которое не лечится ни быстрым диском, ни io_uring в одиночку.
Слой 3. Клиент Ceph
Что это. Клиент Ceph (librbd) - библиотека, через которую виртуальная машина обращается к блочным устройствам хранилища. RBD (RADOS Block Device) - виртуальный диск поверх распределенного хранилища, физически размазанный по многим OSD (object storage daemon, по одному на физический диск) на разных серверах, с копиями. Поколение клиента напрямую влияет на число операций в секунду.
Где была проблема. Каждая операция с диском уходит по сети сразу на несколько узлов хранилища. Устаревший клиент общался по сети менее экономно и примитивнее кэшировал.

Что сделали. Актуальный клиент использует протокол messenger v2 (переработанный сетевой протокол, появился в Ceph Nautilus, умеет шифровать канал), переработанный writeback-кэш и неизменяемый кэш объектов на стороне клиента. Шифрование и контрольные суммы считают встроенные блоки процессора. Серверы хранилища не трогали. Проверить, что кластер общается по v2:
text
ceph mon dump
У мониторов в выводе должны быть адреса с пометкой v2:

Почему так быстрее. На том же кластере более новый клиент снимает больше операций в секунду на смешанной нагрузке без изменений в железе и без перенастройки кластера. Публичные замеры команды Ceph это подтверждают: в конфигурации из 30 OSD librbd выдавал свыше 122 тысяч операций в секунду, а старая сборка из CentOS Stream 8 отставала от новой, переработанной на boost::asio. На большом NVMe-кластере релиз Reef показал порядка 4,4 миллиона операций случайного чтения в секунду при задержке меньше полумиллисекунды.
Слой 4. Системные библиотеки
Что это. Базовые библиотеки (glibc и смежные): блокировки, работа с памятью, элементарные операции. Через них проходит почти любой код на ноде, включая горячий путь клиента Ceph - сериализацию, подсчет контрольных сумм, шифрование.
Где была проблема и что сделали. Библиотеки прежнего поколения несли старые реализации блокировок и атомарных операций, а копирование памяти шло без современных векторных инструкций процессора. Векторные инструкции - это команды класса SIMD (single instruction, multiple data), обрабатывающие сразу несколько чисел за одну операцию. Линия расширений x86 тянется с 1997 года (MMX), через SSE (1999) к AVX (Intel, 2011), AVX2 (2013) и AVX-512 для серверных Xeon (2017). Актуальные библиотеки переработали atomics и используют AVX2 и AVX-512 в операциях с памятью. Снаружи вызов тот же, внутри код быстрее.
Версию библиотеки видно так:
text
ldd --version | head -1
Почему быстрее. Ускорение фундамента само по себе дает проценты, но через библиотеку проходит каждый запрос Ceph-клиента - эти проценты набегают на всей нагрузке и складываются с остальными слоями.
Слой 5. Профиль и cgroups
Что это. Системные настройки, определяющие поведение планировщика, работу с памятью и распределение ресурсов между процессами на гиперноде. cgroups - механизм ядра, который делит процессорное время и ввод-вывод между виртуальными машинами на одной ноде.
Где была проблема и что сделали. Прежнее поколение жило на cgroups первой модели и универсальном профиле производительности, не заточенном под гиперноду с Ceph. РЕД ОС подтягивает cgroups v2 и через систему tuned (демон, применяющий готовые наборы настроек ядра под тип нагрузки) включает профиль гипервизора с другими настройками планировщика, параметрами записи грязных страниц и стоимостью миграции задач между ядрами. Проверка:
text
tuned-adm active stat -fc %T /sys/fs/cgroup
Первая команда покажет активный профиль, вторая выдаст cgroup2fs при втором поколении cgroups.
Почему быстрее. Под смешанную нагрузку с Ceph корректный профиль гипервизора добавляет проценты к задержке и пропускной способности, cgroups v2 ровнее делит ввод-вывод между ВМ при NUMA. По отдельности эффект небольшой, в сумме с остальными слоями - заметный. Сюда же ложится сетевой стек нового ядра: современные алгоритмы управления перегрузкой и драйверы снимают потолок на скоростях 25 и 100 гигабит, критичный для трафика хранилища.
Стек целиком
Сведу слои в одну таблицу. Слева прежнее поколение, справа актуальная ветка РЕД ОС. Сравниваю поведение и технологию, а не номера версий пакетов.
Компонент | Прежнее поколение | Актуальный стек РЕД ОС |
|---|---|---|
Ядро | устаревшее | современное LTS |
Эмулятор и движок диска | синхронные механизмы, io_uring недоступен | io_uring |
Потоки ввода-вывода | один на эмулятор | отдельный на каждый диск, multi-queue |
Клиент Ceph | прежний протокол обмена | messenger v2, новый кэш |
Системные библиотеки | базовая реализация | векторные инструкции |
Профиль и cgroups | дефолты, cgroups v1 | профиль гипервизора, cgroups v2 |
Каждая строка - функция актуального стека целиком. РЕД СОФТ согласует версии слоев между собой, тестирует их связку и сопровождает как один продукт, сертифицированный ФСТЭК.
Откуда прирост
Откуда вообще берется прирост, если приложение и кластер не трогали? Причин две:
Замеры на смешанной нагрузке, где мелкие операции чтения и записи идут вперемешку: именно на ней свежий стек отрывается сильнее всего, потому что узкое место там не диск, а путь запроса через эмулятор и клиент хранилища.
Особенность тестовой ноды: все слои обновились разом, и эффекты сложились. На другом профиле нагрузки или при частичном обновлении разрыв будет другим.
Проверить у себя несложно. Снимите базовую линию на старом стеке, обновите ноду целиком, повторите замер. Минимальный сценарий смешанной нагрузки в fio:
bash
fio --name=mixed --ioengine=libaio --rw=randrw --rwmixread=70 \ --bs=4k --iodepth=32 --numjobs=4 --runtime=120 --time_based
На выходе - число операций в секунду и задержка по перцентилям. Два прогона на одной и той же ноде, до обновления и после, дадут честный ответ без переноса чужих цифр на ваш кластер.
Прирост держится на переходе на современный гипервизорный стек целиком: ядро плюс эмулятор плюс клиент хранилища плюс библиотеки. Это воспроизводимая инженерия: на любом современном дистрибутиве на той же конфигурации вы получите сопоставимый результат. Отечественная ОС добавляет к этому другое - тот же стек собран и сертифицирован для контуров, где зарубежный дистрибутив не проходит по требованиям, плюс русскоязычная техподдержка и сообщество, которых у зарубежной сборки в РФ, по сути, нет. Вот тут история про легаси и обретает смысл: обновляясь, вы получаете и прирост, и сертифицированную базу разом.
Чем расплачивается легаси
Помимо потерянных процентов производительности, устаревший стек обходится еще в несколько вещей.

Безопасность. CentOS Linux 7 ушел в EOL 30 июня 2024 года. Обновлений безопасности для базового семейства больше нет. Каждая новая уязвимость в ядре, библиотеках или системных компонентах остается незакрытой, и счет таких дыр только растет. Для контура под регуляторикой это прямое нарушение требований к защите информации.
Потолок производительности. Старый userspace физически не умеет вызвать половину возможностей современного железа и ядра, и этот потолок не сдвинуть тюнингом. Пока эмулятор, клиент хранилища и библиотеки старые, io_uring, параллельные очереди и новый кэш Ceph недоступны.
Ремонт по частям не работает. Соблазн понятен: обновить только ядро или один пакет и жить дальше. Но гипервизор работает через весь userspace, и точечная замена дает ровно ту ловушку из начала статьи - свежий мотор на старой коробке. Чтобы получить эффект, нужен согласованный стек целиком.
Регуляторика. Легаси-дистрибутив, выпавший из поддержки, в реестре российского ПО не появится, а зарубежный дистрибутив туда и не входил. Для госзаказа и значимых объектов это закрытая дверь.
Два уровня в облаке
В облаке операционная система РЕД ОС живет на двух уровнях.
Уровень каталога — образ, который заказчик берет под свою ВМ. В каталоге VK Cloud лежат сертифицированные ФСТЭК сборки для импортозамещения рядом с Astra Linux и Альт. Развернуть серверную ВМ или рабочее место на РЕД ОС можно из личного кабинета за несколько шагов: выбрать образ, задать сайзинг, подключить сеть и правила доступа, настроить ключи входа, включить снапшоты для отката.
Уровень платформы — ОС под самим гипервизором. VK Cloud работает на стеке РЕД ОС 7.3 и выше, и именно сюда ложится весь разбор из первой части статьи: io_uring, IOThreads, новый клиент хранилища. Заказчик этот прирост не настраивает - он его получает по факту того, что платформа собрана на современном стеке.
Поверх этого строится сертифицированный контур: облачная платформа в сертифицированной редакции, объектное хранилище, РЕД ОС как ОС, российское оборудование из реестра Минпромторга и СКЗИ . Три якоря, которые держат такой контур: российская юрисдикция всех правообладателей, наличие компонентов в реестрах с сертификатами регуляторов и цепочка сборки и поставки обновлений целиком внутри РФ.
Что в итоге
Держать легаси дальше невыгодно, а уход на современный стек окупается. Прирост на хранилище — чистая инженерия: свежее ядро, свежий эмулятор, свежие библиотеки, согласованные и обновленные разом. Это работает на любом современном дистрибутиве. Отечественная ОС добавляет к производительности сертификацию и реестр — для контура под требованиями обновление окупается дважды: скоростью и регуляторикой. Когда выбор идет между мертвым CentOS, нереестровым зарубежным дистрибутивом и сертифицированной отечественной ОС с современным стеком, задача давно не про скорость.
