Сколько клиентов посадить на один сервер: честный предел мультиарендности
«Сколько клиентов влезет на один сервер?» — вопрос, на который нет числа-ответа, только методика. SaaS-платформа с тысячей аккаунтов, агентство с полусотней клиентских сайтов и хостер с сотней аренд задают формально один вопрос, но у каждого свой ответ, потому что предел определяет не мощность железа, а то, как именно клиенты его используют. Ниже — как считать этот предел по паттернам нагрузки, а не по интуиции, и какими техническими средствами держать соседей друг от друга подальше.
Содержание
- Почему деление ресурсов поровну — плохая методика
- Два паттерна нагрузки: ровный гул и синхронные всплески
- Методика расчёта: от среднего и пикового потребления к числу клиентов
- Шумный сосед: где риск мультиарендности бьёт больнее всего
- Контейнеризация и cgroups: техническая изоляция вместо честного слова
- Оверкоммит внутри мультиарендного сервера: та же экономика, свои границы
- Признаки, что пора разделять сервер на несколько
Почему деление ресурсов поровну — плохая методика
Первый инстинкт при расчёте — взять ресурсы сервера и разделить на число клиентов. 32 ГБ памяти, 50 клиентов — по 640 МБ на каждого, готово. Эта арифметика ломается о простой факт: клиенты не используют ресурсы одновременно и не используют их поровну.
Возьмём крайний пример. Пятьдесят сайтов-визиток с посещаемостью в десятки визитов в сутки почти ничего не потребляют: процесс простаивает, память занята под кеш и код, CPU почти всегда на нуле. Тот же сервер с пятьюдесятью интернет-магазинами с активными продажами — совсем другая история: каждый держит пул воркеров, бьёт в базу, генерирует изображения на лету. Формально ресурсов на клиента поровну, а по факту первый сценарий комфортно живёт на скромной машине, второй — упирается в потолок при доле от этого числа клиентов.
Деление поровну игнорирует главное: реальная нагрузка описывается не средним значением, а распределением. У клиента есть базовое потребление (что он ест почти всегда) и пиковое (что он ест в худший момент — вирусный пост, распродажа, батч-задача по расписанию). Сервер должен пережить не сумму средних, а вероятную сумму пиков — и это обычно в разы меньше, чем «пиковое потребление одного × число клиентов», потому что пики разных клиентов редко совпадают во времени. На этом эффекте — статистическом мультиплексировании — держится вся экономика мультиарендности, и его чаще всего либо недооценивают, либо переоценивают, из-за чего сервер либо пустует, либо падает в первый же общий пиковый час.
Два паттерна нагрузки: ровный гул и синхронные всплески
Прежде чем считать число клиентов, нужно понять, к какому из двух базовых паттернов относится ваш портфель — а чаще всего это смесь обоих в разных пропорциях.
Ровная низкая нагрузка, несинхронные пики. Типичный случай — портфель разнородных клиентов без общего триггера активности: у одного пик в обед, у другого ночью (другой часовой пояс), у третьего раз в месяц при выгрузке отчёта. Пики размазаны по времени, и сервер почти никогда не видит их одновременно. Здесь можно закладывать заметный оверселлинг по CPU и памяти — большинство слотов простаивает в любой момент времени, и это позволяет посадить кратно больше клиентов, чем «пиковое потребление одного × их число».
Синхронные пики. Опасный случай — когда у клиентов общий триггер: SaaS для интернет-магазинов в «чёрную пятницу», сервис для бухгалтеров к концу квартала, платформа для школ в начале учебного года. Все бьют пик одновременно, статистическое мультиплексирование не работает — сервер должен выдержать сумму пиков, а не сумму средних. Если вы посчитали ёмкость по первому паттерну, а портфель на самом деле второго типа, сервер ляжет ровно тогда, когда клиентам критичнее всего, чтобы он работал.
Для оценки паттерна полезны две метрики за пару недель наблюдения: коэффициент неравномерности (пиковое потребление клиента к среднему — 2-3× означает ровную нагрузку, 20-50× — острые всплески) и коэффициент синхронности (насколько пики разных клиентов совпадают по времени). Оба ориентировочные, точных порогов «плохо/хорошо» не существует — важно не абсолютное число, а то, что вы его вообще посчитали, а не угадываете.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверМетодика расчёта: от среднего и пикового потребления к числу клиентов
Рабочая последовательность оценки предела для конкретного сервера:
- Профилируйте типового клиента, а не абстрактного. Возьмите реальные метрики за представительный период (минимум 1-2 недели, с учётом пиковых дней, если они предсказуемы): среднее потребление CPU и памяти, 95-й перцентиль, абсолютный максимум. Если клиенты разнородны — разбейте их на 2-3 класса («лёгкий», «средний», «тяжёлый») вместо одного усреднённого профиля, иначе тяжёлые клиенты незаметно съедят запас, рассчитанный под лёгких.
- Оцените базовое потребление сервера — то, что расходуется вне зависимости от активности клиентов: ОС, системные службы, панель управления, изоляция (об этом — ниже), логирование, мониторинг. На небольших серверах это заметная доля — 1-2 ГБ памяти и ощутимый процент CPU не редкость.
- Заложите резерв на пиковую нагрузку, а не только на среднюю. Практическое правило: сумма пиковых 95-перцентилей по всем клиентам не должна превышать 70-80% физической ёмкости сервера — оставшийся запас нужен на аномалии, которые не попали в исторические 95%, на рост клиентов и на плавную, а не обвальную деградацию. Это ориентир, не закон: для критичных сервисов запас разумно держать больше, для тестовых сред — меньше.
- Пересчитывайте регулярно. Портфель клиентов меняется: приходят более тяжёлые аккаунты, старые растут. Предел, посчитанный на старте, устаревает за месяцы — закладывайте пересчёт раз в квартал или при заметном изменении состава клиентов.
Пример прикидки (числа условные, у вас будут свои): сервер на 16 ядер / 64 ГБ, базовое потребление ОС и служб — 4 ГБ и полядра, остаётся ~60 ГБ. Портфель — 200 клиентов класса «лёгкий» (95-перцентиль ~150 МБ, пики не синхронны) и 20 клиентов класса «тяжёлый» (95-перцентиль ~1.5 ГБ, риск синхронных пиков в рабочие часы). Сумма 95-перцентилей: 200×0.15 + 20×1.5 = 60 ГБ — это уже 100% оставшегося ресурса, без запаса. Вывод: либо сокращать число тяжёлых клиентов на сервере, либо выносить их на отдельную машину, оставляя этот сервер под лёгкий равномерный трафик, где оверселлинг работает честно.
Шумный сосед: где риск мультиарендности бьёт больнее всего
Даже идеально посчитанный предел не спасает, если один клиент технически может забрать себе больше ресурсов, чем ему причитается, и никакой лимит его не останавливает. Это классический «шумный сосед» — не обязательно злонамеренный: чаще это плохо написанный запрос без индекса, бесконтрольный импорт файла клиентом, забытая задача в cron, которая раз в сутки грузит CPU на полную. На общем сервере без изоляции такой инцидент у одного клиента ощущают все остальные — задержки, таймауты, недовольные обращения в поддержку от аккаунтов, которые вообще ни при чём. Логика диагностики такого сценария (steal time, iostat, аномалии в сети) подробно разобрана в статье шумный сосед на гипервизоре: как обнаружить и что делать применительно к арендатору VPS — она же применима и внутри вашего мультитенантного сервера, только соседи здесь не чужие виртуалки, а ваши собственные клиенты.
Ключевое отличие мультиарендного приложения от простого шеринга сервера в том, что у вас есть рычаг, которого нет у арендатора VPS по отношению к соседям на гипервизоре: вы контролируете инфраструктуру целиком и можете технически ограничить каждого клиента персональной квотой, а не полагаться на его добросовестность. Это превращает «шумного соседа» из неизбежного риска в управляемую вероятность.
Контейнеризация и cgroups: техническая изоляция вместо честного слова
Разделение по отдельным пользовательским аккаунтам ОС или виртуальным хостам nginx ограничивает пространство имён (файлы, домены), но не ограничивает потребление ресурсов — процесс одного клиента без явного лимита может забрать себе всю доступную память или весь CPU, и ничего в системе его не остановит. Реальная изоляция мультиарендного сервера строится на контейнерах (Docker, Podman) или прямом использовании cgroups v2, где для каждого клиента (или тарифного класса клиентов) задаются жёсткие границы.
Базовый набор лимитов на клиента через cgroups v2 (или эквивалентные флаги Docker):
# Прямой cgroups v2, пример для одного клиента
echo "50000 100000" > /sys/fs/cgroup/client-a/cpu.max # 50% одного ядра
echo "2G" > /sys/fs/cgroup/client-a/memory.max # жёсткий потолок памяти
echo "1800M" > /sys/fs/cgroup/client-a/memory.high # мягкий порог, троттлинг раньше OOM
echo "512" > /sys/fs/cgroup/client-a/pids.max # предел числа процессов/потоков
# Эквивалент для контейнера в Docker
docker run -d \
--cpus="0.5" \
--memory="2g" \
--memory-reservation="1800m" \
--pids-limit=512 \
--name client-a-app client-image:latest
Три момента, которые здесь важны на практике:
memory.maxиmemory.high— не одно и то же.memory.max— жёсткий потолок: превысил — OOM killer убивает процесс внутри группы.memory.high— мягкий порог: превысил — ядро начинает активно троттлить и вытеснять кеш группы, замедляя её, но не убивая. Разумная практика — ставитьmemory.highзаметно нижеmemory.max(условно на 80-90% от него), чтобы клиент сначала тормозил при аномалии, а не сразу падал.- CPU-лимит режет пиковую производительность клиента, а не только защищает соседей. Слишком тесный
cpu.maxпревращает обычный всплеск легитимного трафика клиента в самодиагностируемую проблему («сервер не грузится, хотя ресурсов на хосте полно») — лимит выставлен, просто он слишком узкий. Изоляция — это компромисс, а не бесплатная страховка. - Диск и число процессов (pids) — не менее реальные векторы шумного соседа, чем CPU и память.
pids.maxзащищает от fork-бомбы или утечки процессов у одного клиента, которая иначе может исчерпать общий лимит процессов на хосте и обрушить вообще всех. Про механику этого лимита на уровне ядра — в статье как cgroups ограничивают контейнер и что происходит при упоре в лимит.
Для managed-хостинга и SaaS с десятками-сотнями клиентов вместо ручной раздачи cgroup на каждого удобнее оркестратор (Kubernetes с ResourceQuota и LimitRange на namespace, Nomad, или собственная обвязка над Docker), который применяет лимиты по шаблону тарифного класса, а не вручную для каждого аккаунта.
Оверкоммит внутри мультиарендного сервера: та же экономика, свои границы
Раздавая лимиты клиентам, вы почти неизбежно приходите к тому же вопросу, что стоит перед хостинг-провайдером на уровне гипервизора: раздавать ли клиентам в сумме больше ресурсов, чем физически есть на сервере, в расчёте на то, что не все упрутся в лимит одновременно. Логика и риски здесь почти буквально те же, что при оверкоммите на уровне виртуализации, — подробно они разобраны в статье оверкоммит CPU и памяти: где предел безопасности: CPU-оверкоммит обычно деградирует плавно (клиенты просто получают меньше процессорного времени в момент пересечения пиков), а оверкоммит памяти рискует каскадным отказом — если сумма memory.max всех групп больше физической RAM и несколько клиентов одновременно приблизились к своему лимиту, хост уходит в своп или в системный OOM, который может зацепить не того клиента, что вызвал проблему, а случайного соседа.
Практический вывод: CPU можно оверселлить клиентам заметно смелее (в разумных пределах, отслеживаемых по факту), а память — либо не оверселлить вообще (сумма memory.max ≤ физической RAM за вычетом резерва ОС), либо оверселливать очень осторожно и только для классов клиентов с надёжно предсказуемым, не растущим потреблением.
Признаки, что пора разделять сервер на несколько
Даже с грамотными лимитами и трезвой методикой расчёта у любого сервера есть предел, за которым дальнейшее уплотнение клиентов создаёт больше риска, чем экономии. Сигналы, что этот предел близко:
| Признак | Что он означает |
|---|---|
| Сумма 95-перцентилей потребления клиентов регулярно выше 80-85% ёмкости | Запас на аномалии исчерпан, любой нетипичный пик грозит деградацией у всех |
| Инциденты «шумного соседа» повторяются, несмотря на выставленные лимиты | Лимиты либо слишком широкие, либо сами клиенты выросли из текущего тарифного класса |
| Клиенты из разных классов риска делят один сервер (например, требующие изоляции по контракту вместе с обычными) | Технический предел уже не главный аргумент — есть договорные/комплаенс-требования на раздельную инфраструктуру |
| Время восстановления после сбоя сервера растёт вместе с числом клиентов на нём | Один физический инцидент (диск, сеть, само железо) кладёт слишком большую долю бизнеса разом — стоит подумать о горизонтальном разнесении, а не только о лимитах |
| Обновления и обслуживание (патчи ядра, миграции БД) требуют окна простоя, которое стало неприемлемо большим из-за числа затронутых клиентов | Один сервер стал единой точкой отказа для слишком многих клиентов одновременно |
Когда один или несколько признаков совпадают, разумный следующий шаг — не судорожно ужимать лимиты ещё сильнее, а спланировать разнесение части клиентов на дополнительный сервер. Практический план такого переноса, включая инвентаризацию скрытых зависимостей между клиентскими проектами на общем сервере, разобран в статье разделение общего сервера на клиентские: план работ.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли обойтись без контейнеров и просто следить за нагрузкой вручную?
На горстке клиентов — да, мониторинг и ручное вмешательство при инцидентах работают. С ростом числа клиентов ручной режим не масштабируется: инциденты у разных клиентов начинают происходить чаще, чем вы успеваете реагировать, и в какой-то момент технический лимит на уровне cgroups становится дешевле человеческого времени на разбор жалоб.
Что лучше — один тяжёлый сервер под всех клиентов или несколько серверов поменьше?
Зависит от паттерна синхронности пиков. Если пики клиентов не совпадают, один крупный сервер эффективнее по деньгам за счёт статистического мультиплексирования. Если пики синхронны (общий триггер активности у всех клиентов), несколько серверов меньшего размера снижают риск, что общий пик уложит вообще всех разом — и упрощают горизонтальное масштабирование под конкретный сегмент клиентов.
Как определить лимиты для нового клиента, по которому ещё нет истории потребления?
Начните с лимита тарифного класса, к которому клиент похож по декларируемым параметрам (ожидаемый трафик, тип нагрузки), с запасом в сторону меньшего лимита, и скорректируйте по факту через 1-2 недели наблюдений — это дешевле, чем сразу выдавать щедрый лимит и потом его урезать, вызывая недовольство клиента.
Нужно ли клиентам сообщать о технических лимитах на их аккаунт?
Если лимиты соответствуют заявленному тарифу — обычно не требуется детализировать механику (cgroups, cpu.max и т.д.), достаточно описать лимит в понятных клиенту величинах (число одновременных соединений, объём обрабатываемых файлов). Если клиент систематически упирается в лимит — это сигнал предложить более высокий тарифный класс, а не молча душить его квотой.
Стоит ли ставить более жёсткие лимиты клиентам на бесплатном/пробном тарифе?
Да, и это стандартная практика — пробный аккаунт исторически чаще становится источником аномальной нагрузки (тестирование, парсинг, иногда откровенное злоупотребление), чем платящий клиент с историей. Более узкий cpu.max и memory.max для этого класса — разумная защита остальных соседей, а не излишняя строгость.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →