# Масштабирование — это расширение узкого места

Экспресс-курс по дизайну систем и масштабированию. 21 понятие — Scalability, Bottleneck, Horizontal Scaling, Stateless Server, Load Balancer, Cache, CDN, Read Replica, Sharding, очереди и Design for Failure — у каждого английское название, схема и карточка с примером. В конце — лестница масштабирования и шпаргалка по всем терминам. Только суть: измеряй, а не гадай.

- **Author:** Фёдор Чищин
- **Level:** intro
- **Reading time:** ~35 минут чтения
- **Published:** 2026-06-02
- **Source:** https://fedorthinks.com/ru/learn/system-design-express

---

## 1. Что значит масштабировать

Масштабирование — это не один тумблер, который ты дёргаешь, а постоянная работа: держать больше нагрузки, не падая. Начинается она с одной мысли: найди часть, что ломается первой.

### Scalability — масштабируемость

> Маленькое кафе работает нормально, пока не подъезжает туристический автобус — и вдруг один бариста, одна касса, пара столиков не справляются. Масштабирование — это подготовка к автобусу.

**Scalability (масштабируемость)** — это способность системы держать рост: больше пользователей, запросов, данных, — оставаясь быстрой и живой. Это не про пик изобретательности; это про то, чтобы система не прогнулась, когда нагрузка умножится.

_Diagram: Нагрузка растёт. Масштабируемая система остаётся быстрой; немасштабируемая в какой-то момент резко «ломается»._

#### Scalability (масштабируемость)

- **Что это:** Умение держать больше нагрузки и не становиться медленным или лежачим.
- **Как работает:** Почти любая задача масштабирования сводится к одному: **что-то становится той частью, что не поспевает.**
- **Пример:** Кафе, в которое внезапно приехал автобус туристов.
- **Связи:** Растёт через **Vertical** и **Horizontal Scaling**; упирается в **Bottleneck**.

### Vertical vs Horizontal — вверх или вширь

> Чтобы везти больше, можно купить грузовик побольше — но он лишь до определённого размера — или купить больше грузовиков: предела почти нет, но теперь нужен диспетчер.

Есть ровно два способа нарастить мощность. **Vertical scaling (вертикальное, scale up)** — это машина побольше: больше CPU, больше RAM. Просто, но есть жёсткий потолок, и остаётся единая точка отказа. **Horizontal scaling (горизонтальное, scale out)** — это много машин, работающих вместе: предела почти нет, но нужна координация (балансировка, общее состояние). Вертикальное покупает время; **горизонтальное — там, где живёт настоящий масштаб.** Подробно — в главе 2.

_Diagram: Слева — одна коробка становится больше и упирается в потолок. Справа — коробок становится больше, а перед ними встаёт балансировщик._

### Bottleneck — узкое место

> Шоссе быстро ровно настолько, насколько быстр его самый узкий участок, — расширять все прочие полосы бессмысленно, пока не починишь горловину.

**Bottleneck (узкое место)** — это самая медленная часть системы, которая ограничивает всё остальное. Система быстра ровно настолько, насколько быстра она. Кидать ресурсы не туда — выброшенные деньги; работа в том, чтобы **найти настоящее узкое место** — базу, медленный сервис, сеть, — расширить его, потом найти следующее.

_Diagram: Цепочка держит столько, сколько держит её самое слабое звено. Здесь это база._

#### Bottleneck (узкое место)

- **Что это:** Одна часть, которая не поспевает и тормозит весь поток.
- **Как работает:** Расширил узкое место — появляется следующее. **Масштабирование — это череда узких мест, а не один фикс.**
- **Пример:** CDN и серверы приложения держат тысячи запросов в секунду, а база — восемьсот. Добавлять серверы бесполезно.
- **Подвох:** Легко «чинить» то, что просто казалось медленным, а не то, что им было.
- **Связи:** Находится через **Measure First**; лечится ступенями **Scaling Ladder**.

### Premature Scaling — преждевременное масштабирование

> Ты не строишь шестиполосную автостраду к домику в лесу. Одна хорошая дорога увезёт всех, кто когда-либо приедет.

**Premature scaling (преждевременное масштабирование)** — это строить под нагрузку, которой у тебя нет. Один приличный сервер плюс база обслуживают поразительное число пользователей. Шардинг, микросервисы, навороченное кэширование до того, как появилась нагрузка, — это стоимость и сложность, которые тебе не нужны.

_Diagram: Реальная нагрузка, то, что держит один сервер с базой, и то, что построено «на вырост»._

#### Premature Scaling (преждевременное масштабирование)

- **Проблема:** Сложность и деньги тратятся на нагрузку, которой нет и может не быть.
- **Пример:** Шардированная база и микросервисы для приложения на сотню пользователей.
- **Лекарство:** **Сначала измерь; масштабируй то, что реально болит, когда оно реально болит.**
- **Связи:** Противоядие — **Measure First** и **Scaling Ladder**.

### Карта: 21 понятие в семи группах

> Карта метро: сначала видишь линии целиком, потом едешь по станциям.

Каждая глава курса — одна группа понятий. Они идут примерно в том порядке, в каком растущая система с ними сталкивается: сначала основы, потом больше серверов, распределение трафика, кэши, база, очереди — и в конце правила, как всё это применять с головой.

_Diagram: Семь групп понятий — по ним идут главы 1–7._

### Как читать каждое понятие

> Паспорт: одинаковые поля у всех, поэтому их легко сравнивать.

У каждого понятия дальше одно и то же: **английское название** (запомни его — это термин, который ты встретишь в документации и на собеседованиях), образ из жизни, **схема** и **карточка**: _проблема_, _идея_, _пример_, _цена_, _когда брать_ и _связи_ с другими понятиями. В конце — **шпаргалка** со всеми терминами на одной странице.

> **Прежде чем масштабировать:** «Какая одна часть ломается первой под нагрузкой — и есть ли у меня уже эта нагрузка?»

> Масштабирование — это не «сделать всё быстрее». Это найти узкое место, расширить его и повторить.

## 2. Вертикально, потом горизонтально

Первые настоящие шаги вверх по лестнице масштабирования: перерасти одну большую коробку, потом сделать так, чтобы приложение могло крутиться сколькими угодно одинаковыми коробками.

### Vertical Scaling — сначала коробка побольше

> Когда кухня захлёбывается, первый фикс — плита побольше и больше столешницы, а не второй ресторан.

**Vertical scaling (вертикальное масштабирование, scale up)** — простейший ход: **машина побольше.** Оно не требует правок кода и быстро покупает реальный запас — часто его хватает надолго. Но есть жёсткий потолок (бесконечный сервер не купить), и эта одна коробка остаётся **единой точкой отказа (single point of failure)**.

_Diagram: Каждый шаг — более мощная машина. Но потолок близко, и машина всё равно одна._

#### Vertical Scaling (вертикальное, scale up)

- **Проблема:** Сервер не тянет нагрузку: CPU или памяти не хватает.
- **Идея:** Перейти на машину с бо́льшим числом CPU и RAM.
- **Пример:** База переезжает с сервера на 8 ядер на сервер на 64 ядра.
- **Цена:** Жёсткий потолок; одна коробка = единая точка отказа.
- **Когда брать:** Первым. **Используй его, чтобы выиграть время, а не как пункт назначения.**
- **Связи:** Первая ступень **Scaling Ladder**; следующий шаг — **Horizontal Scaling**.

### Horizontal Scaling — много коробок, одна работа

> Одна касса становится десятью — теперь десять клиентов обслуживаются разом, а если одна касса заклинит, остальные девять продолжают.

**Horizontal scaling (горизонтальное масштабирование, scale out)** — это **много копий** твоего приложения, между которыми делится работа. Предела почти нет, и оно переживает потерю любой одной машины. Подвох — координация: что-то должно распределять запросы (глава 3), а копии не должны каждая держать своё приватное состояние, — что и есть следующая, ключевая идея.

_Diagram: Пять одинаковых копий за балансировщиком. Одна упала — остальные четыре продолжают работать._

#### Horizontal Scaling (горизонтальное, scale out)

- **Проблема:** Одна машина, даже самая большая, упирается в потолок.
- **Идея:** Запустить N одинаковых копий приложения и делить запросы между ними.
- **Пример:** В «чёрную пятницу» магазин поднимает 20 копий вместо обычных 4.
- **Цена:** Нужна координация: балансировщик и общее место для состояния.
- **Когда брать:** Когда вертикального не хватает или нужна устойчивость к падению машин.
- **Связи:** Работает только со **Stateless Server**; нужен **Load Balancer**.

### Stateless Server — любая коробка обслужит любой запрос

> Колл-центр, где любой оператор может принять любой звонок, потому что все детали клиента лежат в общей системе, а не в голове одного оператора.

Чтобы горизонтальное масштабирование работало, серверы приложения должны быть **stateless (без состояния)**: они не держат в своей памяти ничего о пользователе между запросами. Данные сессии, загрузки, прогресс — всё это живёт где-то в общем месте (база, кэш, токен на руках у клиента). Тогда любой запрос может попасть на любой сервер, и добавление или потеря коробки ничего не меняют.

_Diagram: Запрос может попасть на любой сервер: сами серверы ничего не помнят, всё состояние лежит в общем хранилище._

#### Stateless Server (сервер без состояния)

- **Проблема:** Сервер помнит сессию у себя в памяти — пользователь «привязан» к нему, а при падении всё теряется.
- **Идея:** Сервер ничего не хранит между запросами; состояние — в базе, кэше или токене клиента.
- **Пример:** Корзина лежит в Redis, а не в памяти процесса; вход — через токен.
- **Цена:** Каждый запрос ходит за состоянием в общее хранилище.
- **Когда брать:** Всегда, если планируешь больше одного сервера. **Безсостоятельность — это то, что делает «просто добавь серверов» реально рабочим.**
- **Связи:** Предпосылка для **Horizontal Scaling** и **Rolling Deploy**.

> **Горизонтальный вопрос:** «Мог бы запрос попасть на любой из моих серверов и вести себя так же — или каждый тайком держит состояние?»

> Вертикальное покупает время; горизонтальное покупает масштаб. И горизонтальное работает, только если серверы сами по себе ничего не помнят.

## 3. Распределить трафик

Когда серверов много, что-то должно встать перед ними и решать, кто обработает каждый запрос. Это балансировщик нагрузки — регулировщик масштабированной системы.

### Load Balancer — одна входная дверь, много серверов

> Менеджер очереди в банке, направляющий каждого клиента к тому окошку, что свободно, — чтобы один кассир не был завален, пока другие сидят без дела.

**Load balancer (балансировщик нагрузки)** — Nginx, HAProxy, облачный балансировщик — это единая точка входа, которая распределяет входящие запросы по пулу серверов по простым правилам: **round-robin** (по кругу) или «шли наименее занятому» (**least connections**). Клиенты говорят с ним, а не с отдельными серверами, так что машины за ним можно добавлять и убирать незаметно.

_Diagram: Клиенты знают один адрес. Балансировщик раскидывает их запросы по серверам._

#### Load Balancer (балансировщик нагрузки)

- **Проблема:** Серверов много — кто решает, куда пойдёт каждый запрос?
- **Идея:** Одна точка входа распределяет запросы по пулу серверов.
- **Пример:** Nginx перед четырьмя копиями API шлёт запросы по кругу.
- **Цена:** Ещё один компонент, который сам не должен стать единой точкой отказа.
- **Когда брать:** Как только серверов больше одного.
- **Связи:** **Это то, что превращает кучу серверов в одну систему.** Использует **Health Check**.

### Health Check — не слать на мёртвых

> Менеджер очереди замечает, что кассир отошёл, и просто перестаёт отправлять людей к тому окну — никто не ждёт у пустого стола.

**Health check (проверка здоровья)** — балансировщик постоянно **проверяет, какие серверы здоровы**, и обходит те, что нет. Упавшая или перегруженная коробка автоматически выводится из ротации, а трафик течёт к остальным. Так масштабированная система переживает смерть одной машины без того, чтобы пользователи это заметили.

_Diagram: Сервер B не ответил на проверку — балансировщик перестаёт слать ему трафик._

#### Health Check (проверка здоровья)

- **Проблема:** Балансировщик шлёт запросы на сервер, который уже умер.
- **Идея:** Регулярно опрашивать каждый сервер; не ответил — убрать из ротации, ожил — вернуть.
- **Пример:** Каждые несколько секунд `GET /health`; нет ответа `200` — сервер выведен.
- **Цена:** Плохо написанная проверка врёт: «здоров», когда база недоступна.
- **Связи:** Часть **Load Balancer**; основа для failover и **Design for Failure**.

### Rolling Deploy и Failover — бесплатные бонусы

> Можно ремонтировать по одной кассовой линии за раз, пока остальные обслуживают, — магазин не закрывается.

Раз трафик течёт через балансировщик по взаимозаменяемым серверам, мощные вещи достаются почти даром: **деплой без простоя (zero-downtime / rolling deploy)** — обновляешь серверы по нескольку за раз; **failover** — когда один умирает, трафик уходит на остальные; и быстрый **откат (rollback)**. Балансировщик плюс stateless-серверы — это становой хребет, что делает систему и масштабируемой, и устойчивой.

_Diagram: Серверы обновляются по одному, остальные в это время обслуживают пользователей._

#### Rolling Deploy (деплой без простоя + failover)

- **Проблема:** Выкатка новой версии означает «сайт недоступен».
- **Идея:** Обновлять серверы по нескольку за раз, пока остальные держат трафик.
- **Пример:** Из четырёх серверов два уже на v2, один обновляется, один ещё на v1 — пользователи ничего не замечают.
- **Цена:** Какое-то время работают две версии сразу — они должны уживаться.
- **Связи:** Требует **Stateless Server**, **Load Balancer** и **Health Check**.

> **Вопрос про балансировку:** «Когда один сервер умирает или я выкатываю новую версию — пользователи это чувствуют?»

> Балансировщик превращает много серверов в один адрес — а умирающую машину в несобытие.

## 4. Делать меньше работы

Самая быстрая работа — та, которую ты не делаешь. Прежде чем масштабировать машины, делающие работу, сократи, сколько её вообще есть, — кэшами и CDN.

### Cache — не считай один и тот же ответ дважды

> Повар, который заготавливает популярный соус один раз утром, вместо того чтобы делать его с нуля под каждый отдельный заказ.

**Cache (кэш)** хранит результат дорогой работы — запрос к базе, посчитанную страницу, вызов API, — чтобы следующий запрос получил его мгновенно, а не переделывал. Быстрое хранилище в памяти (**Redis**, **Memcached**) перед базой может впитать основную массу чтений. Самая частая схема — **cache-aside**: сначала смотри в кэш, при промахе иди в базу и положи ответ в кэш.

_Diagram: Cache-aside: проверить кэш → при промахе спросить базу → сохранить ответ на следующий раз._

#### Cache (кэш, cache-aside)

- **Проблема:** База снова и снова считает одни и те же ответы.
- **Идея:** Запомнить результат в быстрой памяти и отдавать его повторно.
- **Пример:** Карточка товара кэшируется в Redis — база её больше не пересчитывает.
- **Цена:** Вторая копия правды, которая может протухнуть.
- **Когда брать:** **Часто перегруженной базе нужен именно кэш, а не больше серверов.**
- **Связи:** Требует продуманной **Cache Invalidation**; его родственник на краю сети — **CDN**.

### CDN — обслуживай пользователей из ближнего

> Глобальная сеть, которая держит одни и те же товары в локальных складах повсюду, — чтобы клиенты получали их из-за угла, а не везли через океан.

**CDN (Content Delivery Network, сеть доставки контента)** держит копии твоего статического контента — картинки, скрипты, видео, всё чаще и целые страницы — в дата-центрах по всему миру (**edge**), обслуживая каждого пользователя из ближайшего. Это режет задержку и снимает огромную нагрузку с твоего **origin** — твоих собственных серверов.

_Diagram: Origin раздаёт копии по edge-узлам в разных регионах; пользователь получает ответ из ближайшего._

#### CDN (Content Delivery Network)

- **Проблема:** Пользователь на другом конце света ждёт, пока байты пересекут океан.
- **Идея:** Хранить копии статики в узлах рядом с пользователями.
- **Пример:** Картинки сайта отдаются из узла во Франкфурте, а не с сервера в США.
- **Цена:** Та же проблема кэша: копии надо обновлять при изменениях.
- **Когда брать:** Для всего глобального и статического — CDN делает тяжёлую работу ещё до того, как твои серверы увидят запрос.
- **Связи:** Это **Cache** на краю сети; страдает от той же **Cache Invalidation**.

### Cache Invalidation — самое сложное

> Календарь на холодильнике быстрее, чем проверять телефон, — пока кто-то не поменяет план в телефоне, и теперь холодильник врёт.

Кэш — это вторая копия правды, а копия может протухнуть (**stale data**). По-настоящему сложный вопрос не в том, чтобы добавить кэш, а в том, чтобы **знать, когда его выбросить**, — это и есть **cache invalidation (инвалидация кэша)**. Кэшируй то, что читают намного чаще, чем пишут, ставь вменяемые сроки жизни (**TTL**) и всегда знай, что будет, когда кэш врёт.

_Diagram: Цена в базе поменялась, а кэш об этом не знает и продолжает отдавать старую._

#### Cache Invalidation (инвалидация кэша)

- **Проблема:** Пользователи видят устаревшие данные из кэша.
- **Идея:** Выбрасывать запись из кэша при изменении данных и/или ставить ей срок жизни (TTL).
- **Пример:** При смене цены удаляем ключ `product:42` из Redis; плюс TTL 5 минут на всякий случай.
- **Подвох:** Забытый путь записи, который не чистит кэш, — и данные тихо врут часами.
- **Связи:** Обратная сторона каждого **Cache** и **CDN**.

> **Вопрос про кэширование:** «Что я пересчитываю или перезапрашиваю снова и снова, что мог бы просто запомнить, — и как я узнаю, что оно протухло?»

> Самый дешёвый запрос — тот, который ты никогда не обслуживаешь. Кэшируй горячее, отдавай статику с edge и потей над инвалидацией.

## 5. Масштабировать данные

Рано или поздно база становится узким местом — это та одна часть, которую правда тяжело масштабировать, потому что она держит правду, общую для всех.

### Database Bottleneck — база обычно стена

> Десять касс, тянущихся в одну-единственную кладовку, — кассиры масштабируются, но одна дверь кладовки становится затором.

Можно крутить сотню stateless-серверов приложения, но они обычно делят **одну базу** — и она становится пределом. В отличие от серверов приложения, её нельзя просто клонировать, потому что каждая копия должна сходиться в данных. Поэтому масштабирование базы — самая тяжёлая, самая аккуратная часть масштабирования системы.

_Diagram: Серверы приложения множатся легко, но все они упираются в одну общую базу._

#### Database Bottleneck (база как узкое место)

- **Что это:** Общая база, в которую упираются все серверы приложения.
- **Почему:** Копии базы должны сходиться в данных — их нельзя просто клонировать.
- **Что делать:** Откладывать кэшированием как можно дольше; потом — реплики; шардинг — в последнюю очередь.
- **Связи:** Лечится через **Cache**, **Read Replica**, **Sharding**.

### Read Replica — копии для чтения

> Раздать фотокопии справочника, чтобы многие читали разом, пока единственный мастер-экземпляр — единственный, в котором кто-либо пишет.

Большинство приложений читают намного больше, чем пишут. **Read replicas (реплики для чтения)** — это копии базы, обслуживающие запросы на чтение, размазывающие эту нагрузку по машинам, пока записи всё ещё идут в один **primary**. Это первый и самый лёгкий шаг масштабирования базы — но копии чуть отстают (**replication lag**), так что только что записанное значение может не появиться на реплике мгновенно.

_Diagram: Записи идут только в primary, чтения раскиданы по репликам. Реплики догоняют primary с небольшой задержкой._

#### Read Replica (реплика для чтения)

- **Проблема:** База тонет в запросах на чтение.
- **Идея:** Копии базы отвечают на чтения; все записи — в один primary.
- **Пример:** Ленту и поиск читают с трёх реплик, а заказы пишутся в primary.
- **Цена:** Replication lag: пользователь сохранил профиль, обновил страницу — а там ещё старое.
- **Когда брать:** Когда нагрузка в основном чтения и кэша уже не хватает.
- **Связи:** Следующая ступень после **Cache**; если не хватает записей — **Sharding**.

### Sharding — дели записи

> Один переполненный гроссбух становится несколькими — A–M в одной книге, N–Z в другой, — чтобы два клерка писали разом, не дерясь за одну страницу.

Когда даже записи перерастают одну машину, ты **шардируешь (sharding)**: делишь данные по нескольким базам по какому-то ключу — **shard key**, — чтобы каждая держала свой кусок. Это открывает огромный масштаб, но правда тяжело — межшардовые запросы становятся болезненными, а ключ шардирования — почти необратимый выбор.

_Diagram: Роутер смотрит на ключ и отправляет данные в нужный шард. Каждый шард держит свой кусок._

#### Sharding (шардирование, горизонтальное партиционирование)

- **Проблема:** Записей столько, что одна машина-primary их не вывозит.
- **Идея:** Разрезать данные по ключу на несколько независимых баз.
- **Пример:** Клиенты A–H в шарде 1, I–P в шарде 2, Q–Z в шарде 3.
- **Цена:** Запросы через несколько шардов болезненны; ключ почти нельзя поменять.
- **Когда брать:** **Это глубокий конец; достигай его последним, когда реплик и кэширования правда не хватает.**
- **Связи:** Последняя ступень **Scaling Ladder**; после **Read Replica**.

> **Вопрос про данные:** «Моя нагрузка — это в основном чтения (добавь реплики, кэшируй сильнее) — или записи, перерастающие одну машину (тяжёлая дорога шардинга)?»

> Серверы приложения клонируются легко; база — нет. Кэшируй и реплицируй долго, прежде чем вообще шардировать.

## 6. Сглаживание и развязка

Не всякая работа должна происходить, пока пользователь ждёт. Унести медленную работу с пути запроса и поставить буферы между частями — вот как система остаётся быстрой и впитывает всплески.

### Background Job — унеси медленную работу с пути запроса

> В ресторане у тебя принимают заказ, и ты садишься, — тебя не заставляют стоять у стойки, пока блюдо готовится.

Когда запрос запускает что-то медленное — отправку письма, генерацию отчёта, обработку загрузки, — не заставляй пользователя этого ждать. **Передай это в фоновую очередь** и сразу возвращайся; **worker (обработчик)** сделает медленную часть позже. Это **background job (фоновая задача)**. Страница остаётся шустрой, а тяжёлая работа идёт в стороне. (Идея из курсов про протоколы и архитектуру.)

_Diagram: Приложение кладёт задачу в очередь и сразу отвечает. Письмо отправит worker — позже и в стороне._

#### Background Job (фоновая задача, async processing)

- **Проблема:** Пользователь ждёт секунды, пока сервер делает медленную работу.
- **Идея:** Положить задачу в очередь, ответить сразу, а работу сделает worker.
- **Пример:** После регистрации письмо «добро пожаловать» отправляется в фоне — страница открывается сразу.
- **Цена:** Результат приходит не сразу; нужна очередь и обработка ошибок worker'а.
- **Когда брать:** Для всего, что пользователю не нужно увидеть прямо сейчас.
- **Связи:** Та же очередь даёт **Load Leveling** и **Decoupling**.

### Load Leveling — очереди впитывают всплески

> Водохранилище между разлившейся рекой и городом — паводок наполняет водохранилище, а не топит улицы, и стекает ровным темпом.

Очередь — это ещё и **буфер.** Этот приём называют **queue-based load leveling (выравнивание нагрузки очередью)**. Когда трафик внезапно подскакивает — запуск, вирусный момент, — работа копится в очереди, а воркеры разгребают её в своём темпе, вместо того чтобы поток обрушил систему. Без этого буфера всплеск, что приходит быстрее, чем ты успеваешь обработать, кладёт всё.

_Diagram: Слева — рваный входящий трафик, в середине — очередь копит задачи, справа — воркеры работают ровно._

#### Load Leveling (queue-based load leveling)

- **Проблема:** Всплеск трафика быстрее, чем система успевает обработать.
- **Идея:** Очередь копит работу, воркеры разбирают её с постоянной скоростью.
- **Пример:** В момент запуска приходит в десять раз больше заказов — они ждут в очереди, а не роняют сервис.
- **Цена:** Во время всплеска работа делается с задержкой; очередь надо мониторить.
- **Связи:** **Очередь превращает смертельный всплеск в управляемый бэклог.** Родственник **Background Job**.

### Decoupling — одна медленная часть не топит остальные

> Водонепроницаемые отсеки на корабле — если один затопит, переборки держат остальные сухими, а корабль на плаву.

**Decoupling (развязка)** — когда сервисы говорят через очереди и события, а не прямыми блокирующими вызовами, медленный или упавший компонент **не замораживает всех, кто его ждёт.** Заказ всё равно принимается, даже если сервис писем лежит, — он просто догонит позже. Развязка — это то, что позволяет большой системе деградировать изящно под стрессом, а не падать целиком разом.

_Diagram: Сверху — прямой вызов: упал сервис писем, упал и заказ. Снизу — через очередь: заказ принят, письмо уйдёт позже._

#### Decoupling (развязка через очереди и события)

- **Проблема:** Один упавший сервис тянет за собой всех, кто его вызывает.
- **Идея:** Общаться через очередь или события, а не ждать ответа напрямую.
- **Пример:** Сервис заказов кладёт событие «заказ создан»; сервис писем заберёт, когда оживёт.
- **Цена:** Сложнее проследить, что произошло; данные согласуются не мгновенно.
- **Связи:** Основа **Design for Failure**; строится на тех же очередях, что **Background Job**.

> **Вопрос про асинхронность:** «Пользователю правда нужно этого ждать — или это может случиться за очередью, пока ответ возвращается сейчас?»

> Заставляй пользователя ждать только то, что нужно ему сейчас. Всё остальное — за очередь, которая ещё и спасает тебя, когда бьёт всплеск.

## 7. Масштабировать здраво

Хорошо масштабировать — это в основном сдержанность и порядок: измерь настоящее узкое место, поднимайся по дешёвым ступеням первыми и готовься к отказам, которые приносит больше машин.

### Measure First — измеряй, прежде чем масштабировать

> Врач делает анализы, прежде чем оперировать, — резать не тот орган, потому что ты угадал, не поможет никому.

Прежде чем что-то добавлять, **найди настоящее узкое место** метриками и **профилированием (profiling)** — это база, медленный запрос, сеть, CPU? Инженеры регулярно оптимизируют не то, потому что оно просто казалось медленным. Данные говорят, где система реально болит; **масштабируй это и больше ничего.** (Вот где **наблюдаемость (observability)** оправдывает себя.)

_Diagram: Разбор одного запроса: почти всё время уходит на запрос к базе. Чинить надо его._

#### Measure First (сначала измерь, profiling)

- **Проблема:** Оптимизируют то, что «кажется» медленным, а узкое место в другом месте.
- **Идея:** Метрики и профилирование показывают, куда реально уходит время.
- **Пример:** Запрос идёт 400 мс, из них 280 мс — один запрос к базе. Значит, нужен индекс или кэш, а не больше серверов.
- **Цена:** Нужна наблюдаемость: метрики, трейсы, логи.
- **Связи:** Находит **Bottleneck**; защищает от **Premature Scaling**.

### Scaling Ladder — поднимайся по дешёвой лестнице по порядку

> Ты добавляешь утепление и герметизируешь окна, прежде чем покупать вторую печь, — дешёвые фиксы первыми.

Есть порядок, дешёвое и простое первым: **коробка побольше**, потом **кэширование и CDN**, потом **stateless-серверы за балансировщиком** с горизонтальным масштабированием, потом **read-реплики**, потом **очереди** для медленной работы — и лишь в самом конце **шардинг**. Каждая ступень — больше работы и больше сложности.

_Diagram: Шесть ступеней: чем выше, тем дороже и сложнее. Поднимайся, только когда нагрузка заставляет._

#### Scaling Ladder (лестница масштабирования)

- **Проблема:** Хватаются сразу за самое мощное и сложное средство.
- **Идея:** Идти по ступеням: коробка побольше → кэш и CDN → stateless + балансировщик → реплики → очереди → шардинг.
- **Пример:** Сайт тормозит — сначала больше RAM и кэш; до шардинга дело может так и не дойти.
- **Когда брать:** Всегда. **Поднимайся ровно настолько, насколько вынуждает нагрузка.**
- **Связи:** Объединяет все понятия глав 2–6.

### Design for Failure — больше машин, больше отказов

> Одна лампочка редко перегорает за вечер; на стадионе из десяти тысяч несколько всегда не горят. На масштабе что-то всегда сломано.

По мере добавления машин вероятность, что _что-то_ отказывает в любой момент, стремится к достоверности. Поэтому масштабирование и надёжность — один проект: **избыточность (redundancy)** — никакой **единой точки отказа (single point of failure, SPOF)**; **health-чеки и failover**; и **изящная деградация (graceful degradation)**, чтобы сломанная часть сбрасывала качество, а не убивала систему.

_Diagram: У каждого компонента есть запасной: второй балансировщик, несколько серверов, резервная база с переключением._

#### Design for Failure (проектирование под отказ)

- **Проблема:** На масштабе какая-то машина ломается всегда.
- **Идея:** Redundancy, health-чеки, failover и graceful degradation — отказ части не валит целое.
- **Пример:** Упал сервис рекомендаций — магазин показывает страницу без блока «вам понравится», но продаёт.
- **Цена:** Запасные машины стоят денег; переключения надо регулярно проверять.
- **Связи:** Собирает **Health Check**, **Rolling Deploy** (failover) и **Decoupling**.

### Как всё связано

> Карта после поездки: теперь видно, какие станции на одной линии.

Понятия курса — не отдельные трюки, а одна цепочка. **Измерь** → найди **узкое место** → поднимись на нужную ступень **лестницы**. Горизонтальному масштабу **нужны** stateless-серверы и балансировщик; балансировщику — health-чеки; кэшу — инвалидация; очередям — выравнивание и развязка. А всё вместе служит одной цели: **отказ одной части не должен убивать систему**.

_Diagram: Главные связи между понятиями курса._

#### Прежде чем что-либо масштабировать

- **Измерил ли я**, где настоящее узкое место, — а не угадал?
- **Есть ли ступень дешевле** — коробка побольше, кэш, CDN — перед этой?
- **Stateless ли мои серверы приложения**, чтобы я _мог_ добавить ещё?
- **Нагрузка на базу — это чтения** (реплики, кэш) или записи (тяжёлая дорога)?
- **Может ли медленная работа уйти** за очередь?
- **Есть ли у меня вообще эта нагрузка** — или я строю под будущее, которое может не прийти?

#### Признаки, что ты переусложнил

- **Шардинг** базы, которую легко уместила бы одна коробка.
- **Микросервисы и очереди** для приложения на сотню пользователей.
- Масштабирование **части, что не была узким местом**, потому что оно казалось медленным.
- **Слой кэша** настолько запутанный, что никто не уверен, когда он протух.
- Постройка под **миллионы пользователей**, которых у тебя нет, и запуск, которого не было.

#### Признаки, что ты масштабировал хорошо

- Ты **масштабировал измеренное узкое место**, и следующее теперь видно.
- Серверы **stateless**; добавить или потерять один — несобытие.
- Чтения **закэшированы и реплицированы**; база дышит.
- Медленная работа идёт **за очередями**, и всплеск становится бэклогом, а не падением.
- **Нет единой точки отказа** — любая одна машина может тихо умереть.
- Ты поднялся **ровно настолько по лестнице, насколько потребовала нагрузка.**

## Шпаргалка: все 21 понятие

### Основы

- **Scalability** (масштабируемость): Держать больше нагрузки и оставаться быстрым и живым.
- **Bottleneck** (узкое место): Самая медленная часть; она ограничивает всю систему.
- **Premature Scaling** (преждевременное масштабирование): Строить под нагрузку, которой нет. Стоимость без пользы.

### Вертикально и горизонтально

- **Vertical Scaling** (scale up): Машина побольше. Просто, но потолок и единая точка отказа.
- **Horizontal Scaling** (scale out): Много одинаковых копий. Почти без предела, нужна координация.
- **Stateless Server** (сервер без состояния): Ничего не помнит между запросами — любой сервер обслужит любой запрос.

### Распределить трафик

- **Load Balancer** (балансировщик): Одна входная дверь, раздаёт запросы по серверам.
- **Health Check** (проверка здоровья): Мёртвые серверы автоматически выводятся из ротации.
- **Rolling Deploy** (деплой без простоя, failover): Обновлять по нескольку серверов; при падении трафик уходит на остальные.

### Делать меньше работы

- **Cache** (кэш, cache-aside): Запомнить дорогой ответ и отдавать повторно из памяти.
- **CDN** (Content Delivery Network): Копии статики рядом с пользователями по всему миру.
- **Cache Invalidation** (инвалидация кэша): Знать, когда выбросить копию: удаление при записи и TTL.

### Масштабировать данные

- **Database Bottleneck** (база как стена): Одна общая база, которую нельзя просто клонировать.
- **Read Replica** (реплика для чтения): Копии для чтений, записи в один primary. Есть небольшое отставание.
- **Sharding** (шардирование): Делить данные по ключу на несколько баз. Последнее средство.

### Сглаживание и развязка

- **Background Job** (фоновая задача): Медленная работа уходит в очередь, пользователь не ждёт.
- **Load Leveling** (выравнивание очередью): Очередь превращает всплеск в бэклог, а не в падение.
- **Decoupling** (развязка): Общение через очереди и события — упавшая часть не топит остальные.

### Масштабировать здраво

- **Measure First** (сначала измерь): Метрики и профилирование показывают настоящее узкое место.
- **Scaling Ladder** (лестница масштабирования): Коробка → кэш/CDN → stateless + LB → реплики → очереди → шардинг.
- **Design for Failure** (проектирование под отказ): Избыточность, failover и изящная деградация: на масштабе что-то всегда сломано.

> Масштабируй узкое место, которое измерил, самым дешёвым инструментом, что его чинит, и считай, что на масштабе что-то всегда сломано. Всё остальное преждевременно.

Конец экспресс-курса · 7 глав · 21 понятие · измеряй, а не гадай

Дальше — глубина: снова «Designing Data-Intensive Applications», книги «System Design Interview» и инженерные блоги компаний, что масштабировались по-настоящему. Но держи ключевую мысль выше паттернов — система сильна ровно настолько, насколько прочна её слабейшая точка под нагрузкой. Найди эту точку, расширь её и не строй остальное, пока не придётся.
