Skip to content

Масштабирование и производительность

Что такое масштабирование?

Масштабирование (Scaling) — это способность системы справляться с растущей нагрузкой путём добавления ресурсов. Есть два основных подхода:

┌─────────────────────────────────────────────────────────────┐
│                    МАСШТАБИРОВАНИЕ                          │
├────────────────────────┬────────────────────────────────────┤
│  Вертикальное (Scale Up)│  Горизонтальное (Scale Out)       │
│                        │                                    │
│  Увеличиваем мощность  │  Добавляем больше серверов         │
│  одного сервера        │                                    │
│                        │                                    │
│  ┌──────────┐          │  ┌─────┐ ┌─────┐ ┌─────┐         │
│  │ ████████ │          │  │ ██  │ │ ██  │ │ ██  │         │
│  │ ████████ │          │  │ ██  │ │ ██  │ │ ██  │         │
│  │ ████████ │          │  └─────┘ └─────┘ └─────┘         │
│  │ ████████ │          │                                    │
│  └──────────┘          │  + Больше CPU, RAM, диска          │
│                        │  + Отказоустойчивость              │
│  + Просто              │  - Сложнее в управлении            │
│  - Есть предел         │  - Нужна синхронизация             │
│  - Single point of     │  + Нет теоретического предела      │
│    failure             │                                    │
└────────────────────────┴────────────────────────────────────┘

Вертикальное масштабирование (Scale Up)

Увеличение ресурсов одного сервера: больше CPU, RAM, быстрее диски.

Плюсы:

  • Простая реализация — не нужно менять архитектуру
  • Нет проблем с распределённостью и синхронизацией
  • Подходит для начального этапа

Минусы:

  • Есть физический предел (самый мощный сервер ограничен)
  • Single Point of Failure — если сервер упадёт, всё рухнет
  • Стоимость растёт экспоненциально (удвоение мощности ≠ удвоение цены)

Когда использовать: начальные стадии проекта, базы данных (до определённого предела), когда данные не партиционируются.

Горизонтальное масштабирование (Scale Out)

Добавление большего количества серверов в пул.

Плюсы:

  • Теоретически неограниченное масштабирование
  • Отказоустойчивость — падение одного сервера не роняет систему
  • Экономически эффективно (commodity hardware)

Минусы:

  • Сложная архитектура (распределённые системы)
  • Нужна синхронизация данных между узлами
  • Требуется балансировка нагрузки

Когда использовать: высоконагруженные системы, stateless-сервисы, когда нужна отказоустойчивость.

Практика крупных компаний

Google, Netflix, Amazon используют горизонтальное масштабирование. Вместо одного суперсервера — тысячи обычных серверов, объединённых в кластер.

Балансировка нагрузки (Load Balancing)

Балансировщик нагрузки распределяет входящие запросы между несколькими серверами.

                    Клиенты
                   /   |   \
                  /    |    \
            ┌────▼────▼────▼────┐
            │   Load Balancer    │
            └──┬──────┬──────┬──┘
               │      │      │
          ┌────▼─┐ ┌──▼───┐ ┌▼─────┐
          │ Srv 1│ │ Srv 2│ │ Srv 3│
          └──────┘ └──────┘ └──────┘

Алгоритмы балансировки

1. Round Robin

Запросы распределяются по кругу: 1 → 2 → 3 → 1 → 2 → 3 → ...

Запрос 1  →  Сервер A
Запрос 2  →  Сервер B
Запрос 3  →  Сервер C
Запрос 4  →  Сервер A  (по кругу)
Запрос 5  →  Сервер B

Плюсы: простота, равномерное распределение. Минусы: не учитывает текущую загрузку серверов.

2. Weighted Round Robin

Как Round Robin, но серверы получают трафик пропорционально весу.

Сервер A (вес 5):  █████
Сервер B (вес 3):  ███
Сервер C (вес 2):  ██

Используется когда: серверы имеют разную мощность.

3. Least Connections

Запрос направляется на сервер с наименьшим числом активных соединений.

Сервер A: 12 соединений
Сервер B: 5 соединений   ← новый запрос пойдёт сюда
Сервер C: 8 соединений

Плюсы: учитывает реальную загрузку. Идеален для: длительных соединений (WebSocket, стриминг).

4. IP Hash

Хеш IP-адреса клиента определяет сервер. Один и тот же клиент всегда попадает на один сервер.

hash(client_ip) % N = номер сервера

hash("192.168.1.1") % 3 = 0  →  Сервер A
hash("10.0.0.5")    % 3 = 2  →  Сервер C

Плюсы: sticky sessions без хранения состояния. Минусы: при добавлении/удалении серверов маршруты меняются.

5. Consistent Hashing

Решает проблему IP Hash при изменении числа серверов. Используется в распределённых кешах и БД.

        Хеш-кольцо (0 ... 2^32)
              ┌───┐
         S1 ──┤   ├── S2
              │   │
    Key A ──► │   │ ◄── Key B
              │   │
         S3 ──┤   ├── S4
              └───┘

Ключ попадает на ближайший сервер
по часовой стрелке на кольце.

При добавлении S5 перераспределяется
только часть ключей (не все).

Используется в: Amazon DynamoDB, Apache Cassandra, Memcached.

Уровни балансировки

УровеньПротоколОписаниеПример
L4 (Transport)TCP/UDPБалансировка по IP и портуHAProxy, AWS NLB
L7 (Application)HTTP/HTTPSБалансировка по URL, заголовкам, cookiesNginx, AWS ALB
L7 балансировка — можно маршрутизировать по URL:

/api/*      →  Серверы API
/static/*   →  CDN / Серверы статики
/admin/*    →  Административные серверы

CDN (Content Delivery Network)

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

   Без CDN:                         С CDN:

   Пользователь                     Пользователь
   (Токио)                          (Токио)
       │                                │
       │ 200ms                          │ 20ms
       │                                │
       ▼                            ┌───▼───┐
   ┌───────┐                        │ CDN   │ (Edge-сервер в Токио)
   │Origin │                        │ Node  │
   │Server │                        └───┬───┘
   │(Нью-  │                            │ cache miss?
   │Йорк)  │                            │ 200ms (один раз)
   └───────┘                        ┌───▼───┐
                                    │Origin │
                                    │Server │
                                    └───────┘

Типы CDN

Push CDN:

  • Контент загружается на CDN заранее
  • Вы контролируете, что и когда загружать
  • Подходит для сайтов с редко меняющимся контентом

Pull CDN:

  • CDN запрашивает контент с origin при первом обращении
  • Автоматическое кеширование
  • Подходит для сайтов с высоким трафиком

Что размещать в CDN

  • Статические файлы (JS, CSS, изображения, шрифты)
  • Видео и аудио
  • HTML-страницы (для статических сайтов)
  • API-ответы (с осторожностью, нужна стратегия инвалидации)

Примеры CDN: CloudFront (AWS), Cloudflare, Akamai, Fastly.

Репликация баз данных

Репликация — создание копий базы данных на нескольких серверах.

Master-Slave (Primary-Replica)

                ┌──────────┐
    Запись ───► │  Master  │
                │ (Primary)│
                └─────┬────┘
                      │ репликация
           ┌──────────┼──────────┐
           │          │          │
      ┌────▼───┐ ┌───▼────┐ ┌──▼─────┐
      │ Slave 1│ │ Slave 2│ │ Slave 3│  ◄─── Чтение
      │(Replica)│ │(Replica)│ │(Replica)│
      └────────┘ └────────┘ └────────┘
  • Master обрабатывает все записи
  • Slave (реплики) обрабатывают чтения
  • Подходит для систем с соотношением чтение:запись >> 1

Master-Master (Multi-Primary)

      ┌──────────┐     ┌──────────┐
      │ Master 1 │◄───►│ Master 2 │
      └────┬─────┘     └────┬─────┘
           │                │
      Запись/Чтение    Запись/Чтение
  • Оба сервера принимают записи
  • Более сложная синхронизация
  • Риск конфликтов при одновременной записи

Синхронная vs асинхронная репликация

ХарактеристикаСинхроннаяАсинхронная
КонсистентностьСильнаяEventual
Latency записиВыше (ждём подтверждения)Ниже
Потеря данныхНетВозможна
ДоступностьНижеВыше

Шардирование баз данных

Шардирование (Sharding) — разбиение данных на части (шарды), которые хранятся на разных серверах.

                    Все пользователи (1M)

              ┌────────────┼────────────┐
              │            │            │
         ┌────▼────┐  ┌───▼────┐  ┌───▼────┐
         │ Shard 1 │  │ Shard 2│  │ Shard 3│
         │ A - H   │  │ I - P  │  │ Q - Z  │
         │ 333K    │  │ 333K   │  │ 333K   │
         └─────────┘  └────────┘  └────────┘

Стратегии шардирования

По ключу (Hash-based)

shard_id = hash(user_id) % num_shards
  • Равномерное распределение
  • Сложно добавлять шарды (нужен rehash)

По диапазону (Range-based)

Shard 1: user_id 1 - 1,000,000
Shard 2: user_id 1,000,001 - 2,000,000
Shard 3: user_id 2,000,001 - 3,000,000
  • Просто добавлять шарды
  • Возможна неравномерная нагрузка (hotspots)

По географии

Shard EU:  пользователи из Европы
Shard US:  пользователи из Америки
Shard Asia: пользователи из Азии
  • Низкая latency для пользователей
  • Используется в глобальных системах

Проблемы шардирования

  1. JOINs — запросы через шарды очень дорогие
  2. Ребалансировка — перемещение данных при добавлении шардов
  3. Горячие шарды — неравномерная нагрузка
  4. Транзакции — распределённые транзакции сложны

Путь масштабирования: от 0 до 1M пользователей

Этап 1: Один сервер (0 - 1K пользователей)

┌─────────┐     ┌──────────────────┐
│ Клиенты │────►│  Один сервер     │
└─────────┘     │  App + DB + Кеш  │
                └──────────────────┘

Этап 2: Разделение (1K - 10K)

┌─────────┐     ┌──────────┐     ┌──────┐
│ Клиенты │────►│ App      │────►│  DB  │
└─────────┘     │ Server   │     └──────┘
                └──────────┘

Этап 3: Масштабирование чтения (10K - 100K)

┌─────────┐     ┌────┐     ┌───────┐     ┌────────┐
│ Клиенты │────►│ LB │────►│  App  │────►│ Master │
└─────────┘     └────┘     │Servers│     └───┬────┘
                           │ (x3)  │         │
                           └───┬───┘    ┌────▼────┐
                               │        │ Replicas│
                               └───────►│  (x2)   │
                          (чтение)      └─────────┘

Этап 4: Кеширование и CDN (100K - 1M)

                    ┌─────┐
               ┌───►│ CDN │ (статика)
┌─────────┐    │    └─────┘
│ Клиенты │────┤
└─────────┘    │    ┌────┐    ┌─────┐    ┌───────┐    ┌────────┐
               └───►│ LB │───►│ App │───►│ Redis │───►│   DB   │
                    └────┘    │(x5) │    │ Cache │    │Sharded │
                              └─────┘    └───────┘    └────────┘

Этап 5: Полная архитектура (1M+)

┌──────────┐     ┌─────┐     ┌────┐     ┌──────────┐
│ Клиенты  │────►│ CDN │────►│ LB │────►│ API      │
└──────────┘     └─────┘     └────┘     │ Gateway  │
                                        └────┬─────┘
                              ┌───────────────┼───────────────┐
                              │               │               │
                         ┌────▼────┐    ┌────▼────┐    ┌────▼────┐
                         │ Service │    │ Service │    │ Service │
                         │    A    │    │    B    │    │    C    │
                         └────┬────┘    └────┬────┘    └────┬────┘
                              │              │              │
                         ┌────▼────┐    ┌───▼────┐    ┌───▼────┐
                         │  DB A   │    │  DB B  │    │  DB C  │
                         │(sharded)│    │(sharded)│   │(sharded)│
                         └─────────┘    └────────┘    └────────┘

                    ┌─────────┼─────────┐
                    │         │         │
               ┌────▼──┐ ┌──▼───┐ ┌──▼────┐
               │ Redis │ │ Kafka│ │Elastic│
               │ Cache │ │Queue │ │Search │
               └───────┘ └──────┘ └───────┘

Вопросы для собеседования

  1. В чём разница между вертикальным и горизонтальным масштабированием?
  2. Как работает Load Balancer? Какие алгоритмы вы знаете?
  3. Что такое Consistent Hashing и зачем он нужен?
  4. Объясните разницу между Push CDN и Pull CDN.
  5. Когда использовать Master-Slave, а когда Master-Master репликацию?
  6. Какие проблемы возникают при шардировании?
  7. Как бы вы масштабировали систему с 1000 до 1 000 000 пользователей?

Ключевой принцип

Масштабирование — это не только про технологии, но и про компромиссы. Каждое решение имеет цену: больше серверов — сложнее управление, шардирование — сложнее JOINs, кеширование — проблемы с инвалидацией. Хороший инженер понимает эти trade-offs.