Throughput, latency и tail latency
Throughput — объём завершённой полезной работы за время: например, requests/s при явно заданном успехе. Latency — время одного запроса от выбранного начала до конца. Они связаны с конкурентностью и очередями, но не являются взаимозаменяемыми метриками. Tail latency — высокие квантили распределения, такие как p95/p99/p99.9; именно там часто живёт опыт части пользователей и риск превышения SLO.
Зачем это на интервью
Вопрос проверяет, способны ли вы установить измеримую цель вместо «сделаем быстро». В сервисе можно поднять средний RPS, создавая очередь и ухудшая p99, или улучшить server latency, не заметив client-side retry и error rate. На уровне E4 нужно выбрать корректные границы измерения и объяснить p99; на E5 — учитывать очереди, fan-out, saturation, load generation и SLO/error budget.
Минимум для E4
- Ясно определять единицу полезной работы, success/error policy, начало и конец замера.
- Различать среднее, median и percentile; p99 — значение, ниже которого находится примерно 99% наблюдений в выбранном окне и способе агрегации.
- Понимать, что рост concurrency после насыщения обычно растит queueing delay и tail latency.
- Отдельно собирать rate, errors, duration и saturation; низкая средняя latency не доказывает здоровье сервиса.
- Не усреднять percentiles разных инстансов: для fleet percentile нужны histogram/сырые распределения с согласованными buckets.
Углубление для E5/Senior
Очередь — источник нелинейности
В простой стабильной системе Little’s Law связывает среднее число объектов в системе , arrival rate и среднее время в системе :
Это не формула для расчёта p99 и не лицензия игнорировать условия: система должна быть стабильна, единицы измерения согласованы, а включает ожидающих и обслуживаемых. Однако она полезна как sanity check: если одновременно растут in-flight requests и latency при близком к пределу throughput, вероятна очередь. При utilisation, близкой к 100%, небольшая вариация service time вызывает непропорциональный рост ожидания.
Backpressure ограничивает admission или concurrency до того, как очередь съест память и deadline. Возможные механизмы: bounded queue, semaphore, connection pool, rate limit, load shedding и timeout. Каждый имеет контракт: что отклоняется, кто повторяет, есть ли приоритеты, как клиент отличает временную перегрузку от ошибки. Бесконечная очередь не повышает capacity — она переносит отказ во времени и делает его менее предсказуемым.
Хвосты, fan-out и coordinated omission
Если запрос ждёт несколько зависимостей, вероятность хотя бы одной медленной ветви растёт. Поэтому end-to-end p99 нельзя вывести из среднего dependency latency; нужны трассировки, per-dependency histogram и budget на каждый hop. Retries способны улучшить успех отдельных запросов, но под saturation увеличивают нагрузку и хвост; retry budget, jitter и deadline должны быть общими для цепочки.
Нагрузочный генератор, который отправляет следующий запрос только после ответа, пропускает интервалы, в которых реальный клиент продолжал бы приходить. Это coordinated omission: замер занижает хвосты в период паузы. Для open-loop/arrival-rate сценария фиксируйте целевой arrival process, concurrency, timeout, payload, warm-up и backpressure. Не публикуйте p99 с малым числом запросов: для редких квантилей нужна достаточная выборка и окно.
Метрики и SLO
Для latency полезны histogram buckets, совместимые между сервисами, и exemplars/trace IDs для редких хвостов. Summary с локальными quantiles нельзя безопасно агрегировать между instance. SLO должен говорить о конкретном индикаторе: например, доля успешных POST /checkout, завершённых сервером за 300 ms, за 30 дней. Ошибки, отмены по deadline и деградация могут быть отдельными или объединёнными событиями — это фиксируют явно, иначе команда «улучшит» разные числа.
Throughput измеряйте как completed work, а не только accepted requests. При перегрузке accepted RPS может выглядеть высоким, когда success RPS падает. Сравнивайте также CPU, run queue, throttling, pool saturation, queue depth и downstream limits: планирование CPU объясняет лишь одну из возможных очередей.
Ключевые понятия
| Понятие | Суть | Не путать с |
|---|---|---|
| Throughput | Завершённая полезная работа за секунду | Числом открытых соединений |
| Service time | Время фактической обработки | Полным временем с ожиданием в очереди |
| Queueing delay | Ожидание до обслуживания | Работой CPU/БД над запросом |
| p99 | Высокий квантиль распределения в заданном окне | Средним 99% запросов |
| Saturation | Использование ограничивающего ресурса или рост очереди | Просто высоким RPS |
| Backpressure | Управляемое ограничение потока работы | Бесконечной буферизацией |
Типовые вопросы
- Можно ли усреднить p99 двух pod?
- Нет. Percentile не аддитивен. Нужны объединяемые histogram buckets или сырые наблюдения; среднее из p99 может скрыть перегруженный pod.
- Почему средняя latency нормальна, а пользователи жалуются?
- Распределение может иметь длинный хвост: большинство быстры, часть ждёт очередь, GC, lock, I/O или медленную зависимость. Смотреть p95/p99, errors и trace хвостовых запросов.
- Как увеличить throughput без ухудшения p99?
- Найти bottleneck, уменьшить service time или добавить capacity, ограничить concurrency на ресурсе и проверить нагрузочным тестом. Большее число workers после saturation обычно не подходит.
- Почему timeout не лечит перегрузку сам по себе?
- Timeout останавливает ожидание клиента, но работа может продолжаться, а retries добавят нагрузку. Нужны cancellation, bounded queues и политика admission.
- Что такое coordinated omission?
- Когда генератор прекращает посылать запросы во время медленного ответа, он не измеряет ожидавшие в этот период запросы и занижает tail latency.
- Почему fan-out делает p99 опаснее?
- Ответ ждёт максимум нескольких независимых задержек; шанс встретить хотя бы одну хвостовую ветвь растёт с числом зависимостей.
Практика
- Нарисуйте границы SLI. Для HTTP-метода выберите start/end, success policy, label cardinality и buckets histogram.
- Критерии готовности: есть одна фраза SLI, пример metric name/labels, исключены user ID и URL с параметрами, определено обращение с cancelled/error запросами.
- Найдите knee point. Нагрузите сервис фиксированными payload и timeout, последовательно повышая arrival rate до отказа.
- Критерии готовности: для каждого шага записаны success throughput, error rate, p50/p95/p99, in-flight/queue depth и saturation; warm-up и длительность шага указаны, а предел назван по данным.
- Добавьте backpressure. В учебный handler добавьте bounded semaphore и понятный ответ при исчерпании; сравните с неограниченной очередью.
- Критерии готовности: есть тест на отмену контекста, метрика rejected requests, измерение p99 и памяти под overload, а политика retry/documentation не обещает бесконечные повторы.
Частые ошибки и ловушки
- Называть среднее latency «скоростью сервиса» и не публиковать распределение.
- Складывать или усреднять p99 инстансов вместо агрегации histograms.
- Менять одновременно payload, connection reuse, rate и concurrency в benchmark, теряя причинность.
- Мерить только closed-loop нагрузку и делать вывод об отсутствии хвостов.
- Поднимать лимиты очередей, не проверив memory, deadline и downstream saturation.
- Забывать, что allocation/GC и cache coherence — лишь некоторые источники очередей.
Связанные темы
Модуль Foundations · Наблюдаемость · Планирование CPU · Скорость аллокаций и GC · Профилирование производительности · System Design
Источники
- Google SRE Book, главы Service Level Objectives и Addressing Cascading Failures.
- Google Cloud, The Tail at Scale (Jeff Dean, Luiz André Barroso).
- Marc Brooker, The Tail at Scale и материалы о очередях и backpressure.
- Prometheus documentation: Histograms and summaries.
- John D. C. Little, A Proof for the Queuing Formula: L = λW.