Highload: метрики, компромиссы и жёсткая реальность
Введение
Каждый день ваше приложение обрабатывает тысячи, а может быть и миллионы запросов. 99% из них летают как ракеты, но именно оставшийся 1% — те самые медленные и проблемные запросы — определяет, будут ли пользователи жаловаться, а бизнес терять деньги.
Highload — это не про то, как сделать быстро 99% запросов. Это про то, как укротить самый медленный 1%, как принимать жёсткие решения о надёжности и согласованности данных и как масштабировать систему, когда простые решения уже не работают.
В этой главе мы снимем розовые очки и посмотрим на суровую реальность высоких нагрузок через призму метрик, компромиссов и архитектурных выборов.
Для кого этот урок: Этот материал будет особенно полезен инженерам уровня middle+ и tech leads, которые отвечают за . Если вы ещё не отслеживаете свой или никогда не запускали нагрузочные тесты, этот урок покажет, как эти инструменты помогают управлять системой на практике.
Что скрывается в хвосте вашего приложения?
P95: 200 мс — это лишь видимая часть айсберга. Настоящие проблемы прячутся в P99.9, где пользователи сталкиваются с реальными задержками и начинают жаловаться в соцсетях.
Быстрая диагностика за 4 шага:
Найдите худший эндпоинт по P99.9 в вашем мониторинге (например,
/api/orders).Снимите трассировку (Jaeger/Zipkin) для запросов из этого «хвоста» и разложите время: сеть, , приложение, база данных.
Найдите аномалию — например, запрос без индекса к пользователю с 10 тысячами заказов.
Примените решение: кэш заголовков в Redis, пагинация, ленивая загрузка деталей → P99.9 падает с 3 секунд до 350 мс.
Если не знаете, как это сделать, я разбираю подход пошагово в курсе Распределенная трассировка: от основ до production.
1. Метрики без самообмана
«Средняя температура» всегда лжёт. Мы смотрим на P99.9, и реальный SLA, чтобы не прятать проблемы в хвосте.
1.1 Время ответа и длинный хвост
Latency vs Duration: в чём разница?
— это полный путь запроса от клиента до сервера и обратно. Оно включает:
- DNS-резолвинг
- TLS-handshake
- Балансировщик нагрузки
- Очереди
- Время обработки на сервере (duration)
- Работа с базой данных
- Сетевые задержки
Время обработки (duration) — только время работы вашего кода на сервере. Это лишь часть общего времени ответа.
Откуда берётся «длинный хвост»?
— это запросы, которые выполняются значительно медленнее основной массы. Основные причины:
- : в JVM пауза 80–150 мс каждые N минут → P99 сразу становится > 200 мс
- Блокировки (locks): lock на таблицу при инсерте уменьшает пропускную способность и удлиняет хвост до секунд
- : потоки ждут освобождения CPU, памяти или I/O
- Переполнение очередей: запросы накапливаются и ждут обработки
Практический план атаки на «хвост»
- Снимите трассировку (Jaeger/Zipkin) конкретного запроса с P99.9. Найдите, где он провёл время.
- Идентифицируйте узкое место: БД, очередь, lock, GC, сеть.
- Примените целевое решение:
- Переписать критическую секцию
- Добавить только для чтения
- Поставить для защиты очереди
1.2 Пропускная способность и точка насыщения
- Закон Литтла:
L = λW. Чем выше пропускная способность (λ), тем больше среднее время в системе (W) при фиксированной емкости. - Точка насыщения — колено графика «нагрузка → время ответа». После этого время ответа растёт экспоненциально, процент ошибок стреляет в космос.
- Практика:
- Нагрузочный тест
k6/JMeter: ramp-up 5 минут → плато → стресс. - Снимаем время ответа и процент ошибок на каждом уровне нагрузки.
- Реальный график показывает, что на 70% «максимального» время ответа ещё нормальное, а на 80% уже 1.5 секунды.
- Нагрузочный тест
Вы знаете, сколько трафика выдержит ваша система до падения? Если нет — вы живёте в надежде.
1.3 Доступность и SLA по-взрослому
- SLA Amazon S3 (многорегион): 99,99% доступности в месяц. Прерывания менее 5 минут — это «обычный день», более 5 минут — нарушение SLA.
- Что считать недоступностью:
- HTTP 5xx — всегда.
- 429/503 из-за лимитов — нарушение SLA, если вы не сообщили клиентам заранее.
- Таймауты клиента — считаются, если сервер не ответил в оговорённый срок.
- Действия: определите для своего сервиса. Пример: «запрос завершился за < 400 мс и вернул 2xx/3xx». Всё остальное — недоступность. Сколько недоступных запросов вы готовы терпеть в день? В неделю?
1.4 Процент ошибок как ранняя тревога
- Рост процента ошибок = будущий инцидент. Смотрите на корреляцию со временем ответа.
- Тепловая карта «эндпоинт vs статус-код» покажет, где проблемы.
- Установите алерт:
процент ошибок > 0.3%в течение 5 минут → инцидент. Не ждите жалоб.
Ключевые выводы раздела
Что запомнить:
- Управлять — значит измерять. Ваша главная метрика — не среднее время ответа, а P99.9. Именно там прячутся проблемы, которые замечают пользователи.
- Найдите точку насыщения. Нагрузочное тестирование должно показать момент, когда время ответа начинает расти катастрофически. Это ваш реальный предел.
- SLA — это обязательство. Определите свои индикаторы уровня сервиса (SLI) и измеряйте их постоянно. «Запрос завершился за < 400 мс и вернул 2xx» — вот реальный критерий доступности.
- Процент ошибок — ранний сигнал. Рост ошибок предсказывает инциденты. Настройте алерты и реагируйте до того, как пользователи начнут жаловаться.
Уверены ли вы в консистентности своей БД?
Если вы никогда не прогоняли Jepsen-аналог или хотя бы Chaos Monkey по БД, вы не знаете, как она поведёт себя при split-brain. — не теория, это сценарии реального выживания.
- Запускайте хаос-тест: рвите сеть между узлами и смотрите, что происходит с acknowledged записями.
- Фиксируйте договорённости: что важнее — availability или свежесть данных для каждого бизнес-сценария.
- Документируйте поведение: насколько устаревают данные и через сколько система приходит в консистентное состояние.
2. Компромиссы: CAP, BASE и реальные кейсы
2.1 Реальные инциденты
- AWS S3, февраль 2017: human error → расползание метаданных → падение половины интернета. Почему? Метаданные не были распределены по зонам достаточным образом, а операции восстановления «закрыли» слишком много узлов (выбор A вместо C).
- Jepsen для MongoDB/Cassandra: пока база «обещала» , под хаотичными partition-тестами она теряла acknowledged записи. Это не баг, это компромисс.
2.2 CAP без мифов
- Partition tolerance — данность. Настоящий выбор: что делать, когда часть кластера недоступна.
- Tunable consistency:
- Cassandra:
CONSISTENCY QUORUM→ данные есть после записи, но при потере большинства узлов сервис отдаёт ошибки.CONSISTENCY ONE→ отдаёт старые данные, но сервис жив. - DynamoDB:
Eventually consistent readvsStrongly consistent read.
- Cassandra:
- Практика: определите для каждой операции, что важнее — отказоустойчивость или свежесть данных.
- Баланс: CP (отказаться от операций при проблемах).
- Лента активности: AP (покажем старые события, но сервис не упадёт).
2.3 BASE как основа для распределённых систем
- : сервис может «обрубать» часть функций, но должен отвечать (например, «только чтение»).
- Soft state: данные меняются асинхронно (реплики, очереди). Нужно проектировать бизнес-процессы с учётом eventual consistency.
- : планируйте , компенсационные операции, уведомления («ваш баланс обновится через 5 секунд»).
| Сценарий | Риск потери данных | Что выбираем | Пример |
|---|---|---|---|
| Финансовый перевод | Неприемлем | Strong consistency / CP | PostgreSQL + синхронная реплика, Spanner |
| Лайк в соцсети, метрики | Приемлем (можно пересчитать) | Eventual consistency / AP | Cassandra CONSISTENCY ONE, DynamoDB eventual |
| Корзина покупок | Частично приемлем | Session consistency | Redis master-only, чтение из мастера, sticky read |
2.4 Проверь себя
- Вопрос: если половина вашего кластера Redis/BerkeleyDB исчезнет, что произойдёт? Сколько секунд/минут пользователи будут видеть устаревшие данные? Потрогайте это руками через chaos testing.
- Jepsen lite: запустите тест на staging: писать/читать из БД, пока искусственно рвёте сеть между узлами. Видите ли вы потерю acknowledge? Если да — документируйте, что система выбрала availability.
Ключевые выводы раздела
Что запомнить:
- CAP — это не теория, а реальность. При разрыве сети вам придётся выбирать между консистентностью и доступностью. Решение зависит от бизнес-требований конкретной операции.
- Tunable consistency — ваш инструмент. В Cassandra, DynamoDB и подобных системах вы можете настраивать уровень консистентности для каждой операции. Платёжи требуют строгой консистентности, лайки — нет.
- BASE вместо ACID. Для распределённых систем модель BASE (Basically Available, Soft state, Eventual consistency) — это не компромисс, а осознанный выбор в пользу доступности.
- Идемпотентность обязательна. Если ваша система работает с eventual consistency, все операции должны быть идемпотентными. Повторное выполнение не должно ломать данные.
- Тестируйте хаос. Не ждите production-инцидента. Запускайте Chaos Monkey или Jepsen-подобные тесты на staging, чтобы увидеть реальное поведение системы при разрыве сети.
Может ли ваш монолит прожить следующий квартал?
Монолит с локальным state — главный тормоз. Если вы видите CPU 30% и считаете, что «проблем нет», значит, не тестировали рост нагрузки.
- Вы знаете, при каком RPS монолит осыпается? Замерьте .
- Есть ли план декомпозиции: что первым вынесете наружу (auth, search, billing)?
- Готовы ли миграции данных, если завтра надо удвоить трафик?
3. Стратегии масштабирования (Scale Cube + cost)
3.1 Ось X — клонирование stateless
- Дёшево и весело, пока вынесено наружу.
- Стоимость:
N * cost(instance)+ балансировщик. Рост почти линейный и предсказуемый. - Грабли: , отсутствие общего кэша, ручное управление конфигурацией.
3.2 Ось Y — функциональная декомпозиция
- Разделяем домены (auth, billing, search). Выигрываем в автономности команд.
- Стоимость:
(N * cost(instance)) * 1.5+ затраты на оркестрацию/observability. Ожидайте +30–50% накладных расходов. - Грабли: размазанный state, транзакции через несколько сервисов, взрослая потребность в message bus.
3.3 Ось Z — шардирование данных
- Когда база не помещается в один кластер. Дорого и навсегда.
- Стоимость:
(N * cost(instance)) * 2.5+ выделенная команда данных. В 2–3 раза дороже из-за разработки и сопровождения. - Необходимость: сортировать трафик по ключам, решать , делать глобальные индексы.
- Примеры: sharded PostgreSQL (Citus), Spanner/Pearl, Vitess.
3.4 Состояние как сервис
- Отдельно думайте про компоненты с состоянием: базы, очереди, кэши. Масштабирование API и БД — разные виды спорта.
- Пример: масштабирование Kafka — это не «добавить брокер», это пересчёт partition, баланс потребителей, лимиты ISR.
Ключевые выводы раздела
Что запомнить:
- Scale Cube даёт три оси масштабирования. Ось X (клонирование) — самая простая и дешёвая. Ось Y (функциональная декомпозиция) добавляет гибкость команд, но усложняет координацию. Ось Z (шардирование) — последнее средство, когда данные не помещаются в один узел.
- Считайте стоимость. Каждая ось масштабирования увеличивает не только производительность, но и сложность, и затраты. Ось X: линейный рост. Ось Y: +30–50% накладных расходов. Ось Z: в 2–3 раза дороже.
- Stateless vs Stateful — разные игры. Масштабирование stateless API тривиально — добавил инстансы, готово. Stateful компоненты (БД, очереди, кэши) требуют глубокого понимания их внутреннего устройства.
- Тестируйте отказоустойчивость регулярно. Отказ Availability Zone или региона не должен быть сюрпризом. Проводите chaos-тесты на staging: выключайте зоны и измеряйте, как быстро система восстанавливается.
Проверка на прочность: тестировали ли вы отказ AWS AZ?
Если у вас нет сценария «потеряли Availability Zone/Region», вы НЕ готовы к highload. Вы обязаны знать, как поведёт себя система при падении половины инфраструктуры. Проверьте сейчас: выключите одну AZ (на staging) и посмотрите, как отреагирует система.
Чёткий план для AWS/GCP:
- 17:00 — скрипт либо ASG policy выключает все инстансы в
us-east-1a(илиeurope-west1-b). - Метрика успеха #1: автоскейлинг разворачивает новые инстансы в соседних зонах за 2 минуты или меньше.
- Метрика успеха #2: процент ошибок во время эвакуации < 5%, P95 времени ответа < 1 секунды.
- Метрика успеха #3: через 10 минут весь трафик обслуживается без ручного вмешательства. Если нужно нажимать кнопки — ваша архитектура ещё сырая.
Итоговое резюме
Highload — это не про магию и не про «добавить сервер». Это про дисциплину измерений, честность с самим собой и осознанные компромиссы.
Три главных вывода этого урока:
-
Измеряйте правильно. P99.9, точка насыщения, SLI — это не абстракции для слайдов, а инструменты принятия решений. Без метрик вы не управляете системой, вы просто надеетесь.
-
Принимайте компромиссы осознанно. CAP и BASE показывают, что идеального решения нет. Для каждой операции выбирайте между консистентностью и доступностью исходя из бизнес-требований, а не личных предпочтений.
-
Масштабируйтесь с умом. Scale Cube даёт три оси, но каждая имеет свою цену. Начните с простого (ось X), переходите к сложному только когда это действительно нужно (ось Y и Z), и всегда считайте стоимость.
Что делать дальше:
Следующий урок покажет, как строить stateless-архитектуру, балансировать нагрузку и делать zero-downtime деплои. Но без практики из этой главы — настройки метрик, нагрузочного теста и хотя бы одного chaos-эксперимента — следующий материал останется теорией.
Практика: что сделать до следующего урока
1.Метрики
- —Настройте вывод P99.9 и процента ошибок по ключевым endpoint'ам
- —Сравните P95 vs P99.9 и объясните бизнесу разницу
2.Нагрузочный тест
- —Запустите сценарий ramp-up + плато
- —Зафиксируйте точку насыщения и запас прочности (на сколько процентов трафика хватит сейчас)
3.CAP-анализ
- —Выберите критичный сервис и опишите, что он делает при split-brain
- —Проведите chaos-тест на staging (рвём сеть, смотрим поведение)
- —⚠️ Безопасность: проводите только в изолированном стенде без доступа к проду, идеально — клон в отдельном VPC
4.Стратегия масштабирования
- —Оцените текущие bottleneck'и по Scale Cube (ось X/Y/Z)
- —Составьте roadmap: какие оси тронете в ближайшие 3 месяца
5.Доклад для команды
- —Соберите отчёт «метрики → проблемы → план действий»
- —Подготовьтесь обсуждать, сколько стоят дополнительные «девятки»