Сообщество / Гайды

Обсуждение — KVM или OpenVZ: тип виртуализации

Источник:
KVM или OpenVZ: тип виртуализации VPS

За словом «VPS» скрываются две очень разные технологии. KVM даёт вам настоящую виртуальную машину со своим ядром, OpenVZ — изолированный контейнер на общем ядре хоста. От выбора зависит, сможете ли вы поставить Docker, свою ОС и получить гарантированные ресурсы.

Подробнее →
masha_spb
Middle
Сообщения: 129
Репутация: 98
Дата регистрации:
11.08.2026
АВТОР ТЕМЫ31 окт. 2026 г., 13:00 (GMT+3)
Мне в статье ближе всего не список «можно/нельзя», а мысль про ресурсы. Именно там разговор с человеком обычно начинается не с той стороны.

Типичная ситуация: просят «свой ассистент по документам, чтобы недорого». Человек открывает самый дешёвый тариф, видит 4 ГБ памяти и считает, что модель влезет. Тип виртуализации он не смотрит, потому что не понимает, при чём он тут. А при том, что такая задача упирается сразу в оба ограничения, которые в статье разведены по разным разделам.

Первое — упаковка. Open WebUI и похожие интерфейсы чаще всего ставят через Docker, а статья прямо пишет, что на OpenVZ он работает «не всегда или с костылями». Значит, решение собирается не из трёх команд, а из обходных путей, и каждое обновление снова превращается в лотерею.

Второе — память. Локальная модель на процессоре загружает веса в RAM и держит их там, пока отвечает. Если цифра в free -h условная из-за переподписки, то это не «чуть медленнее», а риск, что процесс убьют посреди ответа. Простой бот такую нестабильность переживёт, а модель на несколько гигабайт — вряд ли.

Поэтому я бы читала нишу OpenVZ из статьи шире, чем «статичный сайт и простой бот». Подходит задача, которая не держит много памяти, не требует своих модулей ядра и спокойно перезапускается. Сюда же относится лёгкий клиент к внешнему API: сама модель живёт у провайдера, а на сервере только тонкая прослойка. Тут, правда, отдельный вопрос, готовы ли вы отправлять документы наружу. Свой сервер этот вопрос сам по себе не закрывает.

А вот если модель крутится локально, то это уже ровно та строка из статьи «KVM нужен для ИИ», и спорить тут не о чем.

Одно место я бы уточнила. Про KVM сказано «гарантированные ресурсы», и с памятью это в целом звучит честно. Но процессорное время на KVM тоже можно продать с запасом, это вопрос политики хостера, а не технологии. Тип виртуализации systemd-detect-virt покажет, а вот насколько у вас тесно с соседями — нет. Для этого полезнее посмотреть на поле st (steal) в top, пока у вас идёт реальная нагрузка, а не в тишине. Если оно заметно растёт как раз тогда, когда модель генерирует ответ, медленная генерация может быть связана не с моделью и не с настройками. Возможно, процессор просто достаётся вам не целиком.

Статья от этого хуже не становится. Просто «KVM» — это ответ на вопрос «что я смогу запустить», а «сколько у меня на самом деле есть» — уже следующий вопрос, и его стоит проверять отдельно.
1
gleb_tomsk
Junior
Сообщения: 90
Репутация: 72
Дата регистрации:
21.08.2026
31 окт. 2026 г., 14:05 (GMT+3)

masha_spb писал:
Человек открывает самый дешёвый тариф, видит 4 ГБ памяти и считает, что модель влезет.


Добавлю, почему эти 4 ГБ кончаются ещё на этапе счёта, даже на KVM с честной памятью. Сам регулярно попадаюсь: сложу веса, обрадуюсь, а остальное вспомню, когда процесс уже упал))

Конкретных замеров здесь нет, только условная прикидка. Что лежит в RAM, пока модель отвечает:
— веса. В 4-битной квантизации это грубо полбайта на параметр плюс служебные таблицы. Модель на 7B выходит около 4 ГБ, на 3B примерно 2 ГБ;
— KV-кэш. Он растёт вместе с контекстом, а у ассистента по документам контекст длинный по определению: туда же подкладываются куски файлов. Сколько он займёт, зависит от архитектуры модели и движка, но это не копейки;
— сам движок, интерфейс в контейнере и система.

Получается, что 7B на четырёх гигабайтах не влезает даже при идеальной виртуализации. 3B влезть может, но запас тогда съедает контекст. OpenVZ с переподпиской добавляет ещё одну неизвестную: непонятно, сколько из показанной памяти реально есть в момент пика.

Я бы начинал разговор с человеком с вопроса «какой длины документы и сколько их нужно держать в одном ответе». Из ответа хотя бы грубо понятно, сколько памяти понадобится, и уже под эту цифру выбирать тип виртуализации и размер тарифа.
1
A
alisa_sd
Junior
Сообщения: 24
Репутация: 19
Дата регистрации:
16.09.2026
31 окт. 2026 г., 15:02 (GMT+3)

gleb_tomsk писал:
сложу веса, обрадуюсь, а остальное вспомню, когда процесс уже упал


Это я с картинками, только вместо RAM видеопамять. Дома 12 ГБ, чекпоинт SDXL около 6,5, думаю: полно места. Потом VAE на большом кадре, пара LoRA, апскейл, и ComfyUI пишет out of memory. Теперь мои 12 ГБ в голове значат «восемь, если не наглеть». А на CPU-сервере память меня даже не волнует: там первой кончится терпение.
1
N
nina_test
Junior
Сообщения: 4
Репутация: 2
Дата регистрации:
31.10.2026
31 окт. 2026 г., 15:03 (GMT+3)

alisa_sd писал:
Теперь мои 12 ГБ в голове значат «восемь, если не наглеть».


Я бы проверяла не первый кадр, а третий подряд. Первый прогон идёт на чистой памяти, а потом что-то может остаться загруженным: прошлый чекпоинт, кэш, LoRA, которую уже убрали из графа. Тогда «восемь» тихо превращаются в шесть. С моделью на сервере так же: один удачный ответ ничего не доказывает, падать любят на повторном запросе с длинным контекстом.
0
lexa92
Middle
Сообщения: 163
Репутация: 145
Дата регистрации:
09.08.2026
31 окт. 2026 г., 17:05 (GMT+3)

nina_test писал:
падать любят на повторном запросе с длинным контекстом.


После такого падения сначала стоит выяснить, кто завершил процесс. На KVM посмотрите journalctl -k и найдите строки Out of memory или Killed process. На OpenVZ ядро внутри контейнера часто молчит. Зато там может быть /proc/user_beancounters: ненулевой failcnt у памяти означает упор в лимит контейнера, а не ошибку движка. Это стоит проверить до того, как менять квантизацию.
0
n1kita
Middle
Сообщения: 101
Репутация: 55
Дата регистрации:
19.08.2026
01 нояб. 2026 г., 01:00 (GMT+3)
failcnt накопительный, считает с момента старта контейнера. Запиши значение до прогона и после, иначе спишешь на модель старый упор недельной давности.
0
M
misha_1c
Junior
Сообщения: 15
Репутация: 12
Дата регистрации:
27.09.2026
01 нояб. 2026 г., 07:00 (GMT+3)
Правильно про «до и после». В информационной базе 1С с журналом регистрации то же самое. Открываешь утром, видишь сотню ошибок блокировок и уже готов ругать вчерашнее обновление конфигурации, а половине из них три дня, просто никто не смотрел. Теперь перед тестовым прогоном записываю время и фильтрую журнал от этой отметки. Со счётчиком контейнера так же: цифра без точки отсчёта ничего не говорит.
1
N
nina_test
Junior
Сообщения: 4
Репутация: 2
Дата регистрации:
31.10.2026
01 нояб. 2026 г., 10:00 (GMT+3)

lexa92 писал:
сначала стоит выяснить, кто завершил процесс


Ещё до журнала я бы спросила сам контейнер. С restart: unless-stopped движок молча поднимается, и снаружи это выглядит как «ответ оборвался, ну бывает». Ответ дадут RestartCount и State.OOMKilled в docker inspect <имя_контейнера>. Если счётчик подрос после длинного запроса, это уже не глюк интерфейса.
1
A
alisa_sd
Junior
Сообщения: 24
Репутация: 19
Дата регистрации:
16.09.2026
01 нояб. 2026 г., 15:01 (GMT+3)

nina_test писал:
Я бы проверяла не первый кадр, а третий подряд.


Вчера так и сделала: три прогона одного графа, а сбоку открыт nvidia-smi. После первого кадра память к исходной цифре не вернулась, ComfyUI держит модели загруженными до следующего раза. Третий прошёл, но запас стал заметно тоньше. Теперь моё «восемь, если не наглеть» звучит иначе: «восемь, если перезапускать после смены чекпоинта».
0
gleb_tomsk
Junior
Сообщения: 90
Репутация: 72
Дата регистрации:
21.08.2026
01 нояб. 2026 г., 15:04 (GMT+3)

alisa_sd писал:
После первого кадра память к исходной цифре не вернулась, ComfyUI держит модели загруженными до следующего раза.


Блин, вот на этой строчке я когда-то сорок минут смотрел в монитор и искал утечку, которой не было))

Цифра в nvidia-smi говорит, сколько видеопамяти процесс занял у драйвера, а не сколько сейчас реально лежит в тензорах. PyTorch держит освободившиеся блоки в своём кэше, чтобы на следующем кадре не просить их у драйвера заново. Снаружи это выглядит как «память не вернулась», а внутри она свободна и ждёт следующего шага. Плюс ComfyUI сознательно держит чекпоинт загруженным, чтобы второй кадр не грузился с диска.

Поэтому «не вернулась к исходной» само по себе ещё не плохо. Плохо, когда от прогона к прогону растёт пик. Если третий кадр прошёл, а пик на нём примерно тот же, что на втором, это кэш, а не утечка. Если пик ползёт вверх, тогда да, что-то копится.

Есть ещё середина между «не наглеть» и «перезапускать каждый раз». У ComfyUI есть флаг --disable-smart-memory: он выгружает модели из видеопамяти в обычную RAM, а не держит их на карте. Встречал и ручную выгрузку моделей через кнопку в менеджере или запрос к API без перезапуска. Что из этого есть в твоей сборке, лучше проверь по её справке, я не знаю, какая у тебя версия. Цена понятная: при смене чекпоинта он снова поедет на карту, кадр стартует медленнее.

И это прямо то же, что у нас с текстовыми моделями на сервере, только память другая. Ollama, например, держит модель загруженной какое-то время после ответа (keep_alive), и если переключиться на вторую, первая может ещё висеть рядом. Человек смотрит free -h, видит, что памяти почти нет, и думает, что модель «жрёт больше заявленного». А это две модели одновременно.

Я бы твой эксперимент довёл так, раз уж nvidia-smi всё равно открыт:
— кадр на чекпоинте A, потом смена на B без перезапуска, записать пик;
— то же после перезапуска, только сразу B;
— сравнить два пика.
Разница между ними и есть цена «забыла перезапустить». Если она маленькая, твоё правило можно ослабить. Если большая, ну наконец-то у «восьми, если не наглеть» появится своё обоснование, а не ощущение))
0
masha_spb
Middle
Сообщения: 129
Репутация: 98
Дата регистрации:
11.08.2026
01 нояб. 2026 г., 18:13 (GMT+3)

gleb_tomsk писал:
Плохо, когда от прогона к прогону растёт пик.


В Ollama та же история называется keep_alive. После ответа модель по умолчанию остаётся в памяти ещё минут пять. Если в эти минуты посмотреть на сервер, легко решить, что память утекает. Сначала стоит открыть ollama ps: там видно, что загружено и до какого времени. Если чат по очереди дёргает две модели, полезнее укоротить keep_alive, чем искать утечку.
0
N
nina_test
Junior
Сообщения: 4
Репутация: 2
Дата регистрации:
31.10.2026
02 нояб. 2026 г., 10:01 (GMT+3)
Алиса, а если сменить чекпоинт туда и обратно, A→B→A? Если на втором A пик выше, чем на первом, значит, что-то от B осталось на карте.
0
lexa92
Middle
Сообщения: 163
Репутация: 145
Дата регистрации:
09.08.2026
02 нояб. 2026 г., 15:00 (GMT+3)

nina_test писал:
Ответ дадут RestartCount и State.OOMKilled


Одна оговорка к вашим двум проверкам, они пересекаются. OOMKilled говорит только про обычную память контейнера: ядро упёрлось в лимит cgroup и убило процесс. Нехватка видеопамяти идёт другим путём. PyTorch бросает исключение CUDA out of memory, процесс завершается с ошибкой, docker его поднимает. RestartCount растёт, а OOMKilled остаётся false. По одному этому флагу легко решить, что с памятью всё в порядке.

Поэтому при подросшем счётчике и false я бы смотрел docker logs --since с отметкой времени перед прогоном и искал строку про CUDA. Отметка нужна по той же причине, что и со счётчиком failcnt.

В A→B→A я бы сравнивал не пик во время генерации, а простой. Загрузили A, дождались конца кадра, сняли nvidia-smi --query-gpu=memory.used --format=csv. То же после второго A. Пик зависит от размера кадра и от того, что кэш аллокатора успел отдать. Простой при одной и той же загруженной модели шумит меньше, и разница между первым и вторым A там честнее.
0
C
che32
Junior
Сообщения: 35
Репутация: 34
Дата регистрации:
05.09.2026
02 нояб. 2026 г., 17:03 (GMT+3)

lexa92 писал:
смотрел docker logs --since с отметкой времени перед прогоном


Дома самое трудное тут не команда, а сама отметка. В офисе прогон запускаешь сам и время знаешь. У меня трое пользователей, и баг-репорт звучит так: «пап, оно опять замолчало». Когда? «Ну днём». На каком вопросе? «Да на обычном».

В субботу младший сидел с рефератом, ответ оборвался на середине, он нажал ещё раз, и всё прошло. Мне рассказал уже за ужином. Начни я смотреть только OOMKilled, увидел бы false и пошёл бы искать проблему в роутере, хотя Keenetic там ни при чём.

Поэтому договорились по-простому. Замолчало — сразу пишешь в семейный чат одно слово: «сломалось». Ничего объяснять не надо. Время сообщения и будет отметкой для --since, а полчаса запаса в обе стороны перекроют разницу между «нажал» и «написал». Жена сначала посмеялась, а теперь сама пишет, причём раньше детей)

Счётчик рестартов я бы тоже записывал вечером в одно и то же время. Утром сравнил две цифры и сразу видно, был ли за день хоть один тихий подъём, даже если никто ничего не написал.
0
gleb_tomsk
Junior
Сообщения: 90
Репутация: 72
Дата регистрации:
21.08.2026
02 нояб. 2026 г., 19:04 (GMT+3)

che32 писал:
Счётчик рестартов я бы тоже записывал вечером в одно и то же время.


Слово «сломалось» в семейный чат — гениально, без шуток)) Это лучший интерфейс для баг-репортов, который я видел. А вот вечерняя цифра скажет только «подъём был». Когда именно — нет. Если за день случилось два рестарта, уже не понять, какой из них реферат, а какой просто кто-то спросил рецепт борща.

При этом докер время запоминает сам. Это только чтение, ничего не трогает:

docker inspect -f '{{.RestartCount}} {{.State.StartedAt}} {{.State.ExitCode}}' <имя_контейнера>


StartedAt — момент последнего старта, то есть последнего тихого подъёма. ExitCode — с чем завершился предыдущий запуск. 137 обычно значит, что процесс получил SIGKILL. Так выглядит и убийство по лимиту cgroup, и обычный docker kill. Единица или другой ненулевой код чаще значит, что программа упала сама, например на том исключении CUDA, про которое писал lexa92. Это подсказка, куда смотреть, а не диагноз. Подтверждение всё равно ищи в docker logs --since.

Вот это мне и нравится. Представь: в чате «сломалось» в 14:12, а StartedAt показывает 14:11:47. Полчаса запаса в обе стороны уже не нужны, реферат пойман почти по секундам. Блин, я когда-то сорок минут листал логи за целый день, а надо было сначала спросить время у самого контейнера.

Подвох один: inspect помнит только последний старт. Для истории есть docker events:

docker events --since 24h --until "$(date -Iseconds)" --filter container=<имя_контейнера> --filter event=die


--until нужен, чтобы команда вывела прошлое и вернула управление, а не висела в ожидании новых событий. Только демон держит небольшую историю событий в памяти и после перезапуска докера или хоста её теряет. Поэтому для дома я бы не надеялся на events, а дописывал строку из inspect в файл по cron, скажем раз в пятнадцать минут. Утром видно, между какими двумя строками сменился StartedAt. Это та же твоя вечерняя запись, только автоматическая и с точностью до интервала.

Маша, а теперь твой keep_alive, и он тут встаёт поперёк. Если у che32 внутри Ollama, то «замолчало» может вообще не быть падением. Модель пять минут никому не нужна, выгружается, младший задаёт вопрос, а первый ответ ждёт, пока веса снова поднимутся с диска. На медленном диске и большой модели это заметная пауза. Ребёнок решает, что всё зависло, жмёт ещё раз — и второй раз идёт уже быстро. Со стороны точь-в-точь «оборвалось, нажал снова, прошло».

В таблице это третий случай, и он самый коварный. «Сломалось» в чате есть, StartedAt не сдвинулся, в логах чисто. Без этой развилки можно неделю искать проблему, которой нет, и снова подозревать бедный Keenetic. Отличить помогает как раз ollama ps в момент жалобы: модель только что загрузилась или висит давно? Ещё в логе сервера видно, когда шла загрузка.

И вопрос к тебе, потому что от ответа зависит совет. На домашней машине с одной моделью есть смысл ставить keep_alive в -1, то есть держать её загруженной всегда? Платить придётся тем, что память занята постоянно, даже ночью. Если рядом крутится что-то ещё, тот же ComfyUI у Алисы, это уже конкуренция за ту же карту. Мне кажется, для семейного сервера холодный старт раздражает сильнее, чем постоянно занятые гигабайты. Но ты с Ollama возишься больше меня, поэтому интересно, где ты проводишь черту.
0