Статический сайт может незаметно пережить краткую просадку: браузер возьмёт файлы из кеша, а CDN отдаст их с ближайшего узла. API работает иначе. Каждый экран приложения вызывает несколько запросов, а медленный ответ задерживает всю цепочку. Например, во время всплеска новые соединения заполняют очередь, p99 растёт с 180 мс до 2 с, затем балансировщик возвращает 502 при ошибке соединения с backend-сервисом или 504 по тайм-ауту.
Причина может скрываться не в коде, а в маршруте, CPU steal, лимите дескрипторов или сетевом шейпинге. Поэтому VPS для backend выбирают по измеряемому профилю нагрузки, включая длительный пик, а не только по числу vCPU и объёму RAM.
Почему Cloud VPS становится узким местом для API и backend
У классического сайта значительную часть трафика составляют кешируемые файлы. У API выше доля коротких динамических запросов, TLS-соединений и обращений к базе либо внешним сервисам. Тысячи небольших ответов создают больше пакетов, системных вызовов и переключений контекста, чем несколько крупных загрузок того же объёма.
Keep-alive уменьшает число TCP- и TLS-рукопожатий, но сохраняет открытые сокеты. Каждый из них расходует дескриптор и память на стороне прокси или приложения. Если тариф использует общие процессорные и сетевые ресурсы хоста, профиль задержки может меняться даже при прежнем RPS. Поэтому среднего времени ответа недостаточно без данных о верхнем хвосте распределения и состоянии ресурсов.
Основные метрики, которые нужно контролировать
RTT показывает время прохождения пакета до узла и обратно, но не включает обработку HTTP-запроса. p95 в 250 мс означает, что 95% измеренных запросов завершились не дольше 250 мс. p99 лучше отражает верхний хвост распределения и задержки, затрагивающие небольшую долю запросов. Эти перцентили нужно сопоставлять с RPS, долей ответов 5xx, тайм-аутами и числом активных соединений.
Для установившегося потока связь между нагрузкой и конкурентностью удобно оценивать приближённо: число запросов в обработке равно RPS, умноженному на среднее время ответа в секундах. При 1000 RPS и 100 мс получится около 100 запросов одновременно. Idle keep-alive-соединения в расчёт не входят, хотя продолжают занимать сокеты.
Снимите базовые показатели в обычное время и во время пика:
ss -s
ss -tin state established
curl -sS -o /dev/null -w 'tcp_done=%{time_connect} tls_done=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' https://api.example.com/health
В выводе ss -ti поле rtt берётся из TCP_INFO для живого соединения. Метрика с названием tcp_rtt в системе мониторинга может рассчитываться иначе, поэтому проверьте документацию экспортера.
Latency: из чего складывается задержка на VPS
Полное время ответа включает DNS, сетевой RTT, установку TCP и TLS, ожидание свободного воркера, работу приложения, запросы к БД и внешним API. Новый HTTPS-сеанс требует дополнительных обменов пакетами, тогда как повторный запрос по keep-alive использует готовое соединение. Сравнивать их одной цифрой нельзя.
География задаёт минимально возможный RTT, а пиринги и транзит определяют фактический маршрут. В пределах одного города RTT иногда укладывается в 1–5 мс, между близкими европейскими регионами часто составляет 10–30 мс, а межконтинентальный путь может занять 80–200 мс и больше. Это ориентиры, а не гарантия: измеряйте из сетей, где находятся пользователи.
На самой VM задержку увеличивают CPU steal, очередь дисковых операций, нехватка RAM и паузы приложения. Если растёт только сетевой RTT, изучайте маршрут и потери. Если RTT стабилен, а TTFB и p99 ухудшаются вместе с %st, iowait или временем запросов к БД, причина ближе к серверу. Потери на промежуточном хопе mtr не доказывают проблему: маршрутизатор может ограничивать ICMP, продолжая нормально пересылать транзитный трафик.
ping -c 20 api.example.com
mtr -rwzc 100 api.example.com
Как выбрать локацию и канал для VPS-сервера
Тестируйте несколько площадок из клиентских сетей, а не с домашнего компьютера разработчика. Смотрите на медиану, p95 RTT, джиттер и потери на конечном узле утром, вечером и в выходные. Looking glass помогает проверить маршрут до заказа, но не заменяет тест самой VM: у продукта может быть другой адресный диапазон или сетевой сегмент.
Anycast направляет трафик к доступной точке присутствия, а CDN может кешировать GET-запросы, завершать TLS и фильтровать атаки на краю сети. Необработанные на пограничном узле динамические запросы пересылаются к исходному серверу, поэтому прокси иногда увеличивает задержку. Для БД в отдельной VM проверьте приватную сеть и RTT между узлами. Если приложение близко к пользователям, но далеко от базы, узкое место лишь перемещается.
Concurrent connections: сколько соединений реально держит VPS
Число соединений нельзя вывести из объёма RAM одной формулой. Лимит зависит от настроек приложения и прокси, файловых дескрипторов, очередей ядра, памяти на сокеты и размера conntrack. Idle-соединение дешевле запроса, который выполняет код и ждёт БД, поэтому 20 000 keep-alive-сокетов могут быть легче 500 тяжёлых запросов.
fs.file-max задаёт общесистемный предел открытых файлов, а RLIMIT_NOFILE, который systemd настраивает через LimitNOFILE, ограничивает число дескрипторов каждого процесса сервиса. Значение ulimit в интерактивной оболочке не подтверждает лимит процесса, запущенного через systemd. Сверяйте настройки самого юнита и фактические пределы работающего процесса.
systemctl show api.service -p LimitNOFILE
pid=$(systemctl show api.service -p MainPID --value)
grep 'Max open files' "/proc/$pid/limits"
find "/proc/$pid/fd" -maxdepth 1 -type l | wc -l
net.core.somaxconn ограничивает очередь полностью установленных соединений, ожидающих accept(). net.ipv4.tcp_max_syn_backlog относится к незавершённым рукопожатиям в состоянии SYN_RECV. Реальный предел также зависит от backlog, который запросило приложение. Увеличенная очередь помогает пережить короткий всплеск, но не исправляет медленный обработчик.
Таблица conntrack нужна не каждому сетевому пути. Она появляется при работе соответствующих правил netfilter, NAT или межсетевого экрана. В некоторых контейнерных тарифах её размер контролирует хост. Сравнивайте текущее число записей с максимумом, если эти параметры доступны.
sysctl net.core.somaxconn net.ipv4.tcp_max_syn_backlog \
fs.file-max net.ipv4.ip_local_port_range
sysctl net.netfilter.nf_conntrack_count \
net.netfilter.nf_conntrack_max
Диапазон исходящих портов в Linux обычно равен 32768–60999, то есть содержит 28 232 порта. Он ограничивает множество исходящих соединений к одному адресу и порту, а не входящих клиентов API. Пулы соединений к БД и внешним сервисам снижают риск исчерпания портов. За NAT может действовать отдельный предел, невидимый внутри VM.
Тюнинг sysctl и ulimit под высокую конкурентность
Начните с лимита приложения и systemd. Если процесс приближается к LimitNOFILE, а памяти достаточно, поднимите предел через override и перезапустите сервис. Значение 65 536 часто используют как исходную точку, но его нужно сверить с числом воркеров, прокси и памятью.
# Файл: /etc/systemd/system/api.service.d/limits.conf
[Service]
LimitNOFILE=65536
После изменения обновите конфигурацию systemd, перезапустите сервис и проверьте предел работающего процесса.
systemctl daemon-reload
systemctl restart api.service
systemctl show api.service -p LimitNOFILE
Для очередей используйте значения, которые выдерживает приложение. Например, 8192 имеет смысл лишь тогда, когда тест показывает краткий всплеск SYN или accept queue, а сервис успевает её разобрать.
# Файл: /etc/sysctl.d/90-api-network.conf
net.core.somaxconn = 8192
net.ipv4.tcp_max_syn_backlog = 8192
Примените файл в тестовой среде, повторите нагрузку и следите за памятью, повторными передачами TCP, ListenOverflows и ListenDrops. Не увеличивайте nf_conntrack_max вслепую: записи занимают память, а заполнение таблицы может указывать на атаку, слишком долгие тайм-ауты или архитектурную проблему.
sysctl --system
nstat -az TcpExtListenOverflows TcpExtListenDrops TcpRetransSegs
Сетевые лимиты Сloud VPS: что скрывается в тарифе
Порт 1 Гбит/с задаёт теоретический потолок около 125 МБ/с до учёта протокольных накладных расходов. Он не обещает такую скорость постоянно. Трафик VM может идти через общий аплинк. Провайдер также может применять шейпинг, месячную квоту трафика, fair use или отдельный лимит пакетов в секунду (PPS). Последний особенно заметен на API с небольшими ответами: полоса остаётся свободной, но растут потери и повторные передачи TCP.
Уточните, симметрична ли скорость, ограничен ли исходящий трафик и что происходит после превышения квоты. Общий интерфейс может добавлять конкуренцию на хосте, а выделенный не гарантирует полосу без обязательства провайдера. Блокировка исходящего SMTP нарушит отправку писем, фильтрация других портов может затронуть вебхуки и нестандартные интеграции.
Как проверить реальные лимиты перед продакшеном
iperf3 измеряет пропускную способность между подконтрольными узлами. Один и четыре параллельных потока выявляют разные ограничения, обратный режим проверяет другое направление. Согласуйте тест с провайдером и не считайте публичный iperf-сервер идеальным вариантом маршрута к пользователям.
iperf3 -c test.example.net -t 30
iperf3 -c test.example.net -P 4 -t 30
iperf3 -c test.example.net -R -t 30
HTTP-нагрузку создавайте с отдельной машины. wrk держит заданное число соединений, но не задаёт фиксированный RPS. Для постоянной или ступенчатой интенсивности используйте в k6 исполнители constant-arrival-rate или ramping-arrival-rate. Они задают частоту итераций, равную RPS только при одном запросе в итерации. Пороги p95, p99 и доли ошибок настройте в api.js. Добавьте прогрев и паузы между ступенями. Генератор не должен упираться в CPU, порты или канал раньше сервера.
wrk -t4 -c400 -d2m --latency https://api.example.com/health
k6 run --summary-trend-stats='avg,med,p(95),p(99),max' api.js
Во время теста собирайте CPU steal, softirq, память, дисковую задержку, отброшенные пакеты, сокеты, conntrack и дескрипторы. node_exporter публикует системные метрики по HTTP, а Prometheus их опрашивает. RPS, HTTP-коды и длительность запросов получайте из приложения, прокси или отдельной проверки.
Практические рекомендации по выбору VPS под API
Сначала определите профиль: целевой и пиковый RPS, p95/p99, размер ответа, долю новых TLS-соединений, число исходящих вызовов и требования к восстановлению. Затем проведите одинаковый тест на двух-трёх конфигурациях. На одной современной dedicated vCPU p99 может быть стабильнее, чем на нескольких shared vCPU при высоком steal, но точный результат зависит от провайдера и нагрузки.
RAM нужна не только воркерам: её используют файловый кеш, БД, прокси и буферы сокетов. NVMe важен для синхронного чтения, журналов или локальной БД. Для stateless API обычно проще добавить второй узел за балансировщиком, чем увеличивать одну VM. Состояние, сессии и задания нужно вынести во внешнее хранилище или спроектировать для нескольких экземпляров.
Сеть 1–10 Гбит/с оценивайте вместе с гарантированной полосой, PPS, трафиком и маршрутами. Проверьте приватную сеть, API управления, снимки и возможность увеличить ресурсы без долгого простоя. SLA тарифа распространяется на доступность покрываемой инфраструктуры и компенсации, но не гарантирует целевой p99 приложения.
Чек-лист выбора VPS под backend-нагрузку
Перед заказом зафиксируйте критерии, которые можно проверить повторным тестом.
1. CPU: модель процессора, shared или dedicated vCPU, CPU steal и p99 под нагрузкой.
2. RAM: рабочий набор, кеши, буферы, запас для пика и реакция на OOM.
3. Сеть: скорость порта, гарантированная полоса, PPS, квота, шейпинг и цена превышения.
4. Локация: p95 RTT из клиентских регионов, маршрут и задержка до БД и внешних сервисов.
5. Лимиты ОС: LimitNOFILE, backlog, исходящие порты и conntrack, если он нужен.
6. Хранилище: NVMe, IOPS и задержка на рабочем профиле чтения и записи.
7. Мониторинг: CPU steal, softirq, отброшенные пакеты, повторные передачи TCP, сокеты, p95/p99, 5xx и тайм-ауты.
8. Масштабирование: увеличение ресурсов, второй узел, балансировщик, приватная сеть и автоматизация.
9. Надёжность и цена: SLA, проверенные резервные копии, план переключения и месячная стоимость.
Правильно выбранный VPS-сервер не решит проблему с медленным SQL-запросом или внешним API, но снизит риск инфраструктурных ограничений. Перед продакшеном повторите рабочий тест и проверьте отказ узла. Если метрики не укладываются в SLO, сравните VPS другой локации или конфигурации.
Тестовый комментарий