Всем привет. Данная статья не более чем эксперимент и не призывает постоянно собирать новое ядро для приложений. Тем более, что сейчас есть тренд на запуск баз данных в контейнерах т.к. это действительно производительнее и нет лишнего оверхеда в сравнении использования виртуализации. Конечно же будет поле манипуляций — это выводы на основе одного бенчмарка. В рамках статьи будет проверка работы clickhouse запускаемый в qemu‑kvm, firecracker, containerd.
Признаюсь, я часто хотел ускорить работу приложений, изменяя системные параметры ОС, вместо изменения параметров работы приложений. Далее приходит осознание того, что в 99% случаев оптимизировать систему в случае явных проблем с базой данных не имеет смысла, надо разбираться с работой clickhouse, текущей нагрузкой, которая смогла сломать все (классика — частые мелкие вставки, select запросы на террабайты данных или join внутри join*8 как в фильме «Начало»). Но все таки, можно ли ускорить операционную систему чтобы clickhouse работал быстрее?
Начнем с выбора методологии запуска бенчмарка. На первый взгляд решение о проверке кажется простым делом. Устанавливаем clickhouse на железе, в контейнере, в виртуалке, в другом VMM — сравниваем результаты и все. Да, первый этап тестов будет выглядеть именно так, но далее мы уйдем от железа и будем делать переподписку по процессорам и одновременно уничтожать железо.
Зачем это делать, если и так понятно, что контейнеры будут работать быстрее? Все так. Многие компании запускают базы данных в контейнерах, делают отказоустойчивую инфраструктуру с популярным оркестратором kubernetes и показывают насколько стало легче поднимать новые инстансы и ручные действия минимальны, например в авито. Это статья не про оркестрацию, а про конечные приложения и в современное время у нас есть выбор — что использовать для конкретных задач.
На момент тестирования используется следующее ПО
Хостовая ОС Ubuntu 24.04.1 LTS
ядро 6.8.0–49-generic
libvirtd (libvirt) 10.0.0
QEMU emulator version 8.2.2 (Debian 1:8.2.2+ds-0ubuntu1.4)
containerd containerd.io 1.7.23
Docker version 27.3.1, build ce12 230 (Cgroup Version: 2)
Firecracker v1.10.1
clickhouse‑server=24.8.7.41
Аппаратные ресурсы:
Intel® Xeon® CPU E5–2666 v3 @ 2.90GHz
4 модуля памяти по 16Gb DDR4 M393A2G40DB0-CPB
Про контейнеры
Начнем с тестов в контейнере, сравним работу runtime и постараемся найти разницу. Есть отличный обзор сравнения работы баз данных в разных runtime — есть свои особенности. Спойлер — «победил» runc.
Важно знать, что приложение должно уметь работать в контейнере. Например возьмем утилиты 7z, sysbench и запустим в контейнере — сама утилита увидит хостовые ресурсы, но не те, которые мы передали и конечно же получим худший результат в сравнении виртуальных машин с такими же ресурсами сработает троттлинг процессора.
Тоже самое относится к базам данных. Например старые версии clickhouse аллоцировали все ресурсы хоста и если запускать нагрузки, то получаем троттлинг процессора и прибитие по oom с стороны системы. В новых версиях стало получше (с ресурсами по оперативной памяти проблем не наблюдал), но к этому еще вернемся.
Про виртуализацию
Для запуска виртуальных машин выбран qemu‑kvm и firecracker. Если про qemu‑kvm практически все знают. То про firecracker можно почитать на официальном ресурсе главное это позиционирование данной технологии, как легковесная виртуализация. Выбрал т.к. далее в эксперименте, будет собрано ядро с отключением защиты от cve и других ненужных обвязок в ядре (драйверы, максимально поддерживаемое количество процов уменьшено до 20).
Тесты
Запускаем тест, ниже таблица, в которой указаны ограничения по ресурсам, полученный результат в тестах и последняя колонка — это запуск на самом железе. Во всех случаях используется одинаковое ядро и одинаковые настройки приложения т. е. надеемся на то, что определение сработает правильно, чтобы не дублировать таблицы, сразу добавляю строку firecracker_mod, firecracker_mod_v2 — запуск машин с модифицированным ядром (отключенные модули ядра, в v2 отключено больше).
Тестовые данные — открытые от яндекс метрики в конце статьи будет ссылка на github в котором указана методика тестирования и конфиги для сборки ядер.
Всего запросов за 10 минут
Всего запросов за 10 минут | ||||
runtime |
2cpu/8gb/queries |
8cpu/32gb/queries |
20cpu/62gb/queries |
sum_3_instances |
Qemu‑kvm |
10 567 |
37 744 |
38 134 |
48 751 |
firecracker |
10 172 |
35 332 |
36 053 |
44 727 |
firecracker_mod |
10 819 |
37 044 |
37 130 |
46 496 |
firecracker_mod_v2 |
11 176 |
37 326 |
37 759 |
46 760 |
containerd |
5289 |
21 656 |
42 862 |
52 198 |
Последняя колонка (sum_3_instances) — это запущеные 3 инстанса с ресурсами 8 cpu, 16 gb ram — история про переподписку\оверкомит и как будет происходить распределение нагрузки. Посчитано суммарное значение по 3м инстансам.
На уровне железа тесты запускал, но не стал добавлять в графики, получил значения 392,305 — среднее значение запросов в секунду и 42 828 по общему количеству запросов т. е. Примерно такое же как при запуске в контейнерах.
На диаграммах явно видно что в контейнерах на ограниченных ресурсах clickhouse показывает худшие значения, но в случае аллокации всех ресурсов, показывает наилучший результат, практически как на железе.
Обратим внимание, что при старте clickhouse в контейнере, видим в логах такое сообщение
<Information> Application: Available RAM: 8.00 GiB; logical cores: 20; used cores: 2.
Честно пытался добавить в бенчмарк запрос ‑max_threads=2 по количеству процессоров, но результаты были такие же. На практике от версии к версии ограничения max_threads работали правильно, на данный момент что то пошло не так. Можно посмотреть в issues связанной с работой cgroup, то можно неплохо скоротать вечер.
Отдельно про firecracker — на графиках видно что при использовании дефолтных настроек ядра показал худшую производительность в сравнении с qemu‑kvm, в случае использовании модифицированного ядра догоняет qemu‑kvm. Тут хотелось показать, что есть возможность получить дополнительную производительность за счет модификации настроек ядра.
Вывод прост.
Всегда стоит проверять как работает ваше приложение в контейнерах. На практике этот момент часто упускают и как итог — проводим дебаг на проде, это нравится многим, но не всегда нравится бизнесу.
Про модификации ядра — это отдельный момент. Можно дальше продолжить копать и получить наилучшую производительность по отношению к стандартному ядру. Уверен, что многие понимают риски таких операций — получить проблему, которую будет еще тяжелее решить — часто хватает достаточно использовать стандартные инструменты для модификации значений
Всем известно про kata‑containers и возможность запускать виртуалки в кубере, используя разные гипервизоры. Кому интересно, посмотрите на сравнительную таблицу и проводите эксперименты. Только при очередном обновлении kubernetes, необходимо помнить про используемые runtime и уметь «обратную совместимость» с новым api.
Команды для запуска, конфиг ядер выложил на github, если есть желание и время можете повторить эксперимент на своем сервере. Спасибо.