System Design
Основы масштабирования
Цели урока
- Понять когда и зачем нужно масштабирование
- Разобраться в вертикальном и горизонтальном масштабировании
- Освоить концепцию Stateless vs Stateful
- Понять CAP теорему и её практические следствия
- Изучить основные паттерны масштабирования
Предварительные знания
- Сбор требований (предыдущий урок)
- Базовое понимание клиент-серверной архитектуры
2008 год, Twitter. Суперкубок, 50 000 твитов в секунду. Сервис падает. Пользователи видят «Fail Whale». Акции рекламодателей идут вниз. Именно тот день стал поворотным - команда начала строить архитектуру, которая через 5 лет выдерживала 143 000 твитов в секунду.
- **Twitter 2013** - переход на горизонтальное масштабирование позволил выдержать нагрузку Суперкубка без единого Fail Whale
- **Netflix** кешируют 99% запросов через EVCache (распределённый Memcached) - без кеша AWS bills выросли бы на порядок
- **Amazon** разделил монолит на 100+ микросервисов в 2002 - каждый stateless, каждый масштабируется независимо
- **Instagram** в 2012 году с 13 сотрудниками обслуживал 30 миллионов пользователей - PostgreSQL + Redis + Nginx + горизонтальное масштабирование
Закон Амдала и рождение горизонтального масштабирования
В 1967 году Джин Амдал (IBM) предсказал пределы параллельных вычислений. Его формула показала: последовательный код - bottleneck всей системы. В 2000-е, когда одиночные серверы достигли физического предела, индустрия массово перешла на горизонтальное масштабирование. Google в 2003 опубликовал GFS и MapReduce - первые публичные архитектуры для commodity hardware. Amazon перешёл на сервисную архитектуру по приказу Безоса в 2002. Netflix публично описал свою microservices трансформацию в 2009. Каждый следовал одной логике: не один производительный сервер - а много дешёвых.
Зачем масштабировать?
2008 год. Twitter запущен полтора года назад. Во время Супербоула сервис падает под нагрузкой. Все видят знаменитый "Fail Whale" - картинку с китом. 50 000 твитов в секунду. Один сервер. Конец истории. Тогда Twitter начал разбираться что такое **масштабирование**.
**Масштабирование** (Scaling) - способность системы обрабатывать растущую нагрузку. Не поддержать 100 пользователей, а перейти от 100 к 100 000 к 10 миллионам без переписывания с нуля.
**Когда нужно думать о масштабировании?**
- **Latency растёт** - запросы выполняются медленнее
- **CPU/Memory на пределе** - сервер загружен на 80-90%
- **Ошибки под нагрузкой** - система падает в пиковые часы
- **База данных - bottleneck** - запросы к БД занимают большую часть времени
Premature optimization is the root of all evil. Не масштабируй заранее - это добавляет сложность. Но проектируй так, чтобы масштабирование было возможным.
Когда стоит начинать масштабировать систему?
Вертикальное vs Горизонтальное
Есть два фундаментальных подхода к масштабированию: **вертикальное** (Scale Up) и **горизонтальное** (Scale Out). Разница не только техническая - она определяет всю архитектуру системы.
**Вертикальное масштабирование (Scale Up)** - увеличиваем производительность одного сервера: больше CPU, RAM, быстрее диск.
**Горизонтальное масштабирование (Scale Out)** - добавляем больше серверов, распределяем нагрузку между ними.
**Закон Амдала: математика против энтузиазма**
Не всё можно распараллелить. Закон Амдала - это холодный душ для архитекторов: последовательная часть кода ограничивает максимальное ускорение, сколько бы серверов ни добавить.
AWS EC2 instance types: от t3.micro (2 vCPU, 1 GB) до u-24tb1.metal (448 vCPU, 24 TB RAM). Вертикальное масштабирование имеет физический потолок - горизонтальное практически нет.
При проектировании главный вопрос: какая часть системы НЕ может быть распараллелена? Это bottleneck по Амдалу. База данных часто такой bottleneck - поэтому sharding и репликация так важны.
Stateless REST API. Какой тип масштабирования предпочтительнее?
Stateless vs Stateful
**Stateless** (без состояния) и **Stateful** (с состоянием) - ключевое разделение для масштабирования. Stateless сервисы масштабируются легко, Stateful - сложно. Это не рекомендация - это математика.
**Stateless сервис** - не хранит информацию между запросами. Каждый запрос содержит всё необходимое для обработки.
**Stateful сервис** - хранит состояние между запросами. Следующий запрос зависит от предыдущего.
**Как сделать Stateful -> Stateless?** Ключевая идея: выносим состояние во внешнее хранилище (Redis, Database), а серверы остаются без состояния.
- **JWT tokens** - состояние в самом токене, сервер не хранит сессии
- **Client-side state** - храним состояние в браузере (Redux, localStorage)
- **Centralized cache** - Redis/Memcached для общего состояния
- **Database** - все данные в БД, сервер только бизнес-логика
Stateful сервисы всё равно нужны: базы данных, очереди, кеши. Но их масштабируют отдельно и более аккуратно. Application layer должен быть stateless.
Веб-приложение хранит сессии пользователей в памяти сервера. Как сделать его stateless?
CAP теорема
**CAP теорема** (теорема Брюера) - фундаментальный закон распределённых систем. Невозможно одновременно гарантировать все три свойства: Consistency, Availability, Partition Tolerance. Это не рекомендация - это математически доказанная теорема.
В распределённой системе сетевые разделения (network partitions) **неизбежны**. Серверы в разных дата-центрах, сеть ненадёжна. Если система не переживает partition - она не распределённая. Поэтому реальный выбор: CP или AP.
**Уточнение: PACELC** - CAP говорит о поведении во время partition. Но что происходит в нормальном режиме? Расширение PACELC добавляет: Else (Latency vs Consistency). Даже без partition есть trade-off.
На практике большинство систем выбирают eventual consistency для большинства операций, и strong consistency только для критичных (платежи, инвентарь).
Проектируется система подсчёта лайков в социальной сети. Какой trade-off выбрать?
Паттерны масштабирования
Теория выше - фундамент. Теперь практика: пять паттернов, которые используются в реальных системах от стартапа до FAANG.
**1. Load Balancing** - распределяем запросы между серверами. Первый шаг горизонтального масштабирования.
**2. Database Replication** - копируем данные на несколько серверов. Увеличиваем read throughput и отказоустойчивость.
**3. Database Sharding** - разделяем данные на части (shards) по ключу. Масштабируем и чтение, и запись.
**4. Caching** - храним «горячие» данные в памяти. Снижаем нагрузку на БД и latency. Netflix кешируют метаданные фильмов в памяти - это 90% запросов без обращения к БД.
**5. Asynchronous Processing** - выносим тяжёлые операции в фоновую обработку через очереди.
Большинство реальных систем используют комбинацию паттернов. Load Balancing + Caching + Database Replication - базовый набор для любой нагруженной системы.
База данных - bottleneck. Читаем в 100 раз чаще, чем пишем. Какой паттерн применить первым?
Ключевые идеи
- Вертикальное масштабирование (Scale Up) - увеличение производительности сервера, просто но имеет потолок
- Горизонтальное (Scale Out) - добавление серверов, требует stateless архитектуры
- Закон Амдала: 5% последовательного кода ограничивает ускорение до 20x даже при 100 серверах
- CAP теорема: при network partition выбираем Consistency или Availability - третьего не дано
- Паттерны: Load Balancing, Replication, Sharding, Caching, Async Processing - применяются в комбинации
Что дальше
Следующий урок: Основы баз данных - SQL vs NoSQL, ACID, репликация и шардинг на практике. Это детализация паттернов масштабирования для data layer.
- CAP теорема (подробно) — Полный разбор CP vs AP с примерами Cassandra, etcd, Spanner
- Базы данных: репликация и шардинг — Детализация паттернов масштабирования для data layer
Вопросы для размышления
- Instagram с 13 сотрудниками обслуживал 30 миллионов пользователей. Какие именно решения по масштабированию позволили это сделать? Что было бы, если бы они выбрали CP вместо AP для лент?
Связанные уроки
- ds-02 — CAP-теорема - фундамент выбора между CP и AP системами
- bd-03 — Репликация и шардинг - детализация паттернов масштабирования для БД
- cloud-03 — Auto-scaling в облаке строится поверх горизонтального масштабирования
- devops-05 — Load balancing - первый шаг горизонтального масштабирования в prod
- alg-01 — Big-O помогает найти bottleneck - последовательную часть по закону Амдала
- se-08 — CQRS разделяет read/write path - та же логика что read replicas
- dist-11-replication