Highload на Go: System Design, Kubernetes и микросервисы под нагрузкой
Спроектируете Go-сервис, который в час пик отказывает лишним запросам за микросекунды, а остальным отвечает вовремя, и защитите каждое решение цифрами на system design интервью. Обычно сервис проверяют на ровном трафике, а ломается он под пиком: p99 уходит за таймаут клиента, мёртвая зависимость съедает горутины. Ставить ничего не нужно: брокер Kafka поднимается прямо в задании, манифесты применяются в настоящем кластере Kubernetes.
Чему вы научитесь
- Считать нагрузку до архитектуры: средний и пиковый RPS, перцентили p95 и p99 вместо среднего, SLO и бюджет ошибок, закон Литтла.
- Находить, куда уходит время Go-сервиса: бенчмарки testing.B, профили pprof, аллокации и escape analysis, GOGC и GOMEMLIMIT.
- Ставить кэш, который переживает промах: cache-aside и write-through, LRU и TTL, single flight против stampede, горячие ключи, инвалидация.
- Ограничивать и распределять трафик: token bucket, скользящие окна, распределённый лимитер, балансировка round robin, L7-балансировка, консистентное хеширование.
- Переживать чужие отказы: дедлайн на каждом хопе, ретраи с backoff и jitter, circuit breaker, bulkhead, load shedding, деградация по фича-флагам.
- Работать с очередями: семантики доставки, идемпотентные обработчики и ключи дедупликации, партиции и consumer group, DLQ и consumer lag на брокере Kafka.
- Держать базу под нагрузкой: размер пула соединений и PgBouncer, охота на N+1 по EXPLAIN, лаг реплик, ключ шарда и решардинг.
- Снижать цену сети между сервисами: REST и gRPC, версионирование API, сага вместо распределённой транзакции, дедлайны и хвосты латентности при fan-out.
- Писать конкурентный Go без утечек: worker pool, context и отмена, каналы с backpressure, mutex и atomic, errgroup и поиск утёкших горутин.
- Видеть систему целиком: метрики Prometheus, RED и USE, перцентили из гистограмм, структурные логи, трейсы, алерты по burn rate.
Какие запросы обслуживать, если мощности на всех не хватает?
Пул на 17 соединений, запрос к зависимости 20 мс: сервис тянет около 850 RPS. Поток в 1 200 RPS на 15 секунд это на 29% больше. Одна пятая потока приходится на checkout, остальное на рекомендации, клиент ждёт не дольше 2 с.
Три ответа сервиса в нашем прогоне. Очередь без лимита: с пятой секунды ни один ответ не укладывается в 2 с, вовремя получили 28% запросов. Отказ без разбора: 63% у checkout и 65% у рекомендаций. Резерв слотов под checkout: 99,4% у checkout, а ценой становятся 53% у рекомендаций.
В курсе вы строите эти механизмы сами: переборку на зависимость, ограниченную очередь, сброс нагрузки на входе и планировщик деградации по приоритету. Что отключать первым, решаете вы, а проверка смотрит, что критичный путь остался.
Что получает клиент, когда зависимость лежит
Зависимость молчит 10 секунд при 500 RPS, ответ в норме 20 мс, таймаут клиента 2 с. Без предохранителя все 5 000 запросов аварии получают ошибку, каждый после ожидания в 2 с, а в ожидании висит около тысячи горутин.
Предохранитель после пяти ошибок подряд отказывает сразу, за доли микросекунды. Но первые две секунды он не помогает: ошибки приходят только после таймаута, и пик в 1 002 горутины тот же. Затем ожидающих остаётся 0 или 1.
Цена другая. Зависимость ожила на 15-й секунде, а цепь закрылась на 17,08-й: 1 038 запросов получили отказ, хотя могли получить ответ. Автомат CLOSED, OPEN, HALF_OPEN вы пишете руками по тикам и считаете время в каждом состоянии по журналу переходов, поэтому видите цену каждого параметра.
Сквозной проект: лимитер, который переживает отказ Redis
Пик 13 890 RPS и 123 МБ состояния посчитаны в начале проекта. Подов несколько, поэтому счётчики лежат в Redis, а проверка и списание токена делает один Lua-скрипт: без него две реплики прочитают tokens=1 и обе пропустят запрос.
Когда Redis недоступен, лимитер не ждёт таймаут на каждом запросе: предохранитель отсекает вызовы, а каждый под считает по локальному token bucket. Лимит становится приблизительным, защита остаётся. Для платных квот выбрали бы fail-closed: решает то, что именно защищает лимитер.
Большая часть практики идёт в программах на Go и bash, которые моделируют механизм: token bucket, консистентное хеширование, такт HPA, разбор access-лога до p95. Очереди проходят на настоящем брокере Apache Kafka, а в Go-лабораторных код компилируется и запускается по-настоящему.
Для кого
Go-разработчикам, которые пишут фичи и хотят отвечать за поведение сервиса под пиком: очереди, таймауты, реплики, отказы зависимостей.
Тем, кто готовится к system design интервью: метод ответа, оценки на салфетке, разборы типовых задач и капстоун как готовый рассказ.
Бэкендерам с другим основным языком, которые могут написать небольшую программу на Go: практика здесь на Go и bash.
Шесть реплик посчитаны верно. Что в расчёте упущено
Четыре пода на 91% от requests при цели 70% дают ceil(5,2) = 6 реплик. Формула верна, вывод неполон: новая реплика заработает примерно через 65 секунд после всплеска, а всплеск в 30 секунд закончится раньше. От него защищает запас в цели, а не автоскейлер.
Остальные замечания: откуда взяты requests, ведь утилизация считается от них, и что будет при снижении, где окно scaleDown по умолчанию 300 секунд.
Манифесты вы пишете сами: requests и limits под нужный QoS-класс, HPA по двум метрикам, behavior для scaleDown. Проверка применяет их в настоящем кластере и читает результат через kubectl get, включая QoS-класс, который вычислил Kubernetes.
Что нужно знать
Go на уровне своей небольшой программы: package main, срезы, map, структуры, чтение stdin. Решения пишутся как полные программы на стандартной библиотеке.
Горутины и каналы хотя бы на уровне синтаксиса. Worker pool, context и select подробно разбираются в модуле про конкурентность.
Терминал и bash: решения по очередям пишутся в solution.sh, часть задач по логам решается через awk и sort.
Опыт с Kafka и Kubernetes не обязателен: перед лабораторными идёт теория, а подсказки в заданиях называют нужные флаги и поля манифеста.
Поддержка
Вы также можете задать любой вопрос по курсу у поддержки t.me/mentorix_support
Программа курса
Модулей: 13, уроков: 65. Задачи с кодом проверяются автоматически.
Введение в highload: нагрузка, метрики, SLO
- Highload начинается не с миллиона RPS
- Перцентили латентности: почему среднее врёт
- SLI, SLO, SLA и бюджет ошибок
- Закон Литтла и пределы пропускной способности
- Масштабирование: вертикальное, горизонтальное, stateless
Профилирование и оптимизация Go
- Сначала измерь: бенчмарки testing.B
- pprof: читаем CPU-, heap- и goroutine-профили
- Аллокации и escape analysis
- GC: GOGC, GOMEMLIMIT и sync.Pool
- Строки, []byte и горячий путь
Кэширование под нагрузкой
- Зачем кэш: hit rate и цена промаха
- Паттерны: cache-aside, read-through, write-through/behind
- Вытеснение: LRU, LFU и TTL
- Stampede, single flight и горячие ключи
- Инвалидация и согласованность кэша с БД
Rate limiting и балансировка нагрузки
- Зачем ограничивать: перегрузка, fairness и тарифы
- Token bucket и leaky bucket
- Окна и распределённый лимитер
- Алгоритмы балансировки: от round robin до L7
- Консистентное хеширование и виртуальные ноды
Устойчивость: таймауты, ретраи, circuit breaker
- Таймауты и бюджет запроса: дедлайн на каждом хопе
- Ретраи: идемпотентность, retry budget и цена повторов
- Exponential backoff, jitter и анатомия retry storm
- Circuit breaker: closed, open, half-open
- Bulkhead, backpressure и graceful degradation
Очереди и асинхронная обработка
- Зачем очередь: сглаживание пиков и развязка сервисов
- Семантики доставки: at-most-once, at-least-once, exactly-once
- Идемпотентность и ключи дедупликации
- Порядок сообщений, партиции и consumer group
- Ретраи, DLQ и consumer lag
Базы данных под нагрузкой
- Пул соединений: почему без него всё умирает
- Индексы, EXPLAIN и охота на N+1
- Репликация: реплики, лаг и чтение своих записей
- Шардирование: ключ шарда, решардинг и горячие шарды
- Денормализация и когда пора в NoSQL
Микросервисы и API под нагрузкой
- Монолит vs микросервисы: цена сети
- REST vs gRPC и версионирование API
- Сага вместо распределённых транзакций
- Идемпотентность и дедупликация запросов
- Дедлайны, fan-out и хвосты латентности
Go-конкурентность под нагрузкой
- Worker pool: ограничение параллелизма и его тюнинг
- Context, дедлайны и распространение отмены
- Каналы, буферизация, select и backpressure
- Гонки данных: mutex, atomic и детектор -race
- errgroup, паники и утечки горутин
Наблюдаемость: метрики, логи, трейсы
- Три столпа и метрики Prometheus
- RED, USE и перцентили из гистограмм
- Структурные логи и корреляция запросов
- Распределённый трейсинг: спаны и трейсы
- Алертинг по симптомам и SLO
System Design: метод и разбор задач
- Метод ответа и back-of-envelope расчёты
- API, схема данных и выбор БД под паттерн доступа
- URL shortener: полный разбор по методике
- Лента новостей: fan-out on write vs read
- Счётчики, лайки и идемпотентность в дизайне
Kubernetes под нагрузкой
- Requests, limits и QoS: чем узел платит за неточность
- HPA: формула, метрики и инерция автоскейлера
- Пробы под нагрузкой: readiness, liveness и каскадные отказы
- Graceful shutdown и выкатка без потерянных запросов
- Ресурсы узлов, PDB и поведение кластера при пиках
Капстоун: highload-система от начала до конца
- Требования и оценка нагрузки: rate limiter as a service
- Ядро сервиса: выбор и реализация алгоритма
- Состояние в Redis и деградация при отказе
- Деплой в Kubernetes: HPA, метрики и SLO
- Прод-готовность, узкие места и разбор на интервью
Стоимость курса: 19990 ₽
Открыть курс на Mentorix · Все курсы