← Назад к вопросам

Какие способы масштабирования баз данных вы знаете? Чем отличается вертикальное от горизонтального масштабирования?

1.8 Middle🔥 161 комментариев
#Архитектура систем#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Масштабирование баз данных (Database Scaling)

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

Два основных подхода

1. Вертикальное масштабирование (Vertical Scaling)

Определение: Увеличение мощности существующего сервера (больше CPU, RAM, диск).

Принцип:

Серверное оборудование:
Шаг 1: 8 CPU, 16 GB RAM, 500 GB SSD
       ↓
Шаг 2: 16 CPU, 64 GB RAM, 2 TB SSD
       ↓
Шаг 3: 32 CPU, 256 GB RAM, 10 TB SSD

Примеры:

AWS:
t3.medium → t3.large → t3.xlarge → t3.2xlarge

DigitalOcean:
2GB → 4GB → 8GB → 16GB

Преимущества вертикального масштабирования:

  • Просто реализовать
  • Нет изменений в коде
  • Нет необходимости в перехвате данных между серверами
  • Транзакции остаются локальными (ACID гарантии)
  • Кэширование эффективнее (одна копия данных)

Недостатки вертикального масштабирования:

  • Финитный (есть лимит мощности)
  • Дорого (цена растет экспоненциально)
  • Downtime при переходе (нужно перезагрузиться)
  • Single point of failure (одна машина — весь БД)
  • Предел оборудования (max 128 CPU, 1TB RAM в облаке)

Когда использовать:

  • Стартап с растущей нагрузкой
  • Предсказуемый рост
  • До момента когда вертикальное масштабирование больше не помогает

2. Горизонтальное масштабирование (Horizontal Scaling)

Определение: Распределение нагрузки на несколько серверов.

Принцип:

1 сервер с 1TB:
┌─────────────────┐
│  Вся база       │
│  Нагрузка: 100% │
└─────────────────┘

4 сервера с 250GB каждый:
┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐
│ Часть 1 │  │ Часть 2 │  │ Часть 3 │  │ Часть 4 │
│ 25%     │  │ 25%     │  │ 25%     │  │ 25%     │
└─────────┘  └─────────┘  └─────────┘  └─────────┘

Преимущества горизонтального масштабирования:

  • Масштабируется почти бесконечно
  • Дешевле в целом (много дешевых серверов вместо одного дорогого)
  • Высокая доступность (если один сервер упал, остальные работают)
  • Распределенность (географическое распределение)
  • Может добавляться на лету

Недостатки горизонтального масштабирования:

  • Сложно реализовать
  • Требует изменений в коде и архитектуре
  • Сложнее поддерживать консистентность данных
  • Network latency между серверами
  • Сложнее с транзакциями
  • Операционная сложность

Когда использовать:

  • Высоконагруженные системы
  • Когда вертикальное масштабирование недостаточно
  • Требуется высокая доступность
  • Требуется географическое распределение

Стратегии горизонтального масштабирования

1. Sharding (Шардирование)

Что это: Разделение данных на логические подмножества (shards), каждый shard находится на отдельном сервере.

Пример по User ID:

Sharding key: user_id % 4

Shard 1: user_id % 4 == 0  (users 0, 4, 8, 12...)
Shard 2: user_id % 4 == 1  (users 1, 5, 9, 13...)
Shard 3: user_id % 4 == 2  (users 2, 6, 10, 14...)
Shard 4: user_id % 4 == 3  (users 3, 7, 11, 15...)

Запрос: SELECT * FROM users WHERE user_id = 5
Шаг 1: 5 % 4 = 1 → Обращаемся к Shard 2
Шаг 2: SELECT * FROM users WHERE user_id = 5  (локально на Shard 2)
Результат: User с ID 5

Стратегии выбора shard key:

Плохо: shard key = random()
       → Нельзя найти данные

Хорошо: shard key = user_id
        → Можно быстро найти все данные пользователя

Хорошо: shard key = tenant_id (для multi-tenant)
        → Данные одного клиента всегда в одном shard

Проблемы sharding:

Проблема: Hot shard (один shard получает 90% нагрузки)
Решение: Пересмотреть shard key

Проблема: Запрос нужен из нескольких shards
Запрос: SELECT COUNT(*) FROM orders WHERE status = 'pending'
Решение: Параллельный запрос всем shards, агрегировать результаты

Проблема: Транзакция затрагивает несколько shards
Решение: 2-phase commit (сложно), или избегать таких транзакций

Проблема: Перебалансировка shards (добавление нового shard)
Решение: Consistent hashing, алгоритм ренумерации

Пример: e-commerce система

Таблица orders:
- Shard 1: orders for users 0-24999
- Shard 2: orders for users 25000-49999
- Shard 3: orders for users 50000-74999
- Shard 4: orders for users 75000-99999

Выполнить заказ для user_id = 12345:
1. Вычислить shard: 12345 / 25000 = 0 → Shard 1
2. Выполнить INSERT INTO shard1.orders VALUES (...)

2. Replication (Репликация)

Что это: Копирование всех данных на несколько серверов.

Master-Slave репликация:

Master (primary):
  └─ Принимает все write запросы
  └─ Отправляет changes на slaves

Slave 1 (replica):
  └─ Read-only копия
  └─ Принимает read запросы

Slave 2 (replica):
  └─ Read-only копия
  └─ Принимает read запросы

Примерной нагрузки:
Writes: 10%  → Master
Reads:  90%  → Slaves

Пример архитектуры:

Апликация
├─ Write запросы → Master (UPDATE, INSERT, DELETE)
└─ Read запросы → Load Balancer
                 ├─ Slave 1
                 ├─ Slave 2
                 └─ Slave 3

Проблемы репликации:

Проблема: Lag (отставание slave от master)
└─ Master изменил data, но slave еще не обновился
└─ Решение: Читать важные данные с master, некритичные со slave

Проблема: Replication break
└─ Slave не может применить change
└─ Решение: Мониторинг, automated failover

Проблема: Master умер
└─ Какой slave стать новым master?
└─ Решение: Automatic failover, heartbeat

3. Read/Write Splitting

Что это: Разделение нагрузки чтения и записи на разные серверы.

Архитектура:

Application
├─ Write Driver → Master (primary, all writes)
│                 └─ Replicates to slaves
│
└─ Read Driver → Load Balancer
                ├─ Slave 1 (read replica)
                ├─ Slave 2 (read replica)
                └─ Slave 3 (read replica)

Пример (MySQL):

import mysql.connector

# Для writes
write_conn = mysql.connector.connect(
    host="master.db.com",
    user="user",
    password="pass",
    database="mydb"
)

# Для reads
read_conn = mysql.connector.connect(
    host="slave1.db.com",  # или load balancer
    user="user",
    password="pass",
    database="mydb"
)

# Выполнение
write_cursor = write_conn.cursor()
write_cursor.execute("INSERT INTO users VALUES ...")
write_conn.commit()

# Чтение (может быть с lag)
read_cursor = read_conn.cursor()
read_cursor.execute("SELECT * FROM users WHERE id = ?")
result = read_cursor.fetchone()

4. Partitioning (Разбиение таблиц)

Что это: Разделение таблицы на части внутри одной БД (или на разных).

Partition по дате:

Таблица events:
Partition 2024-01: orders from 2024-01-01 to 2024-01-31
Partition 2024-02: orders from 2024-02-01 to 2024-02-28
Partition 2024-03: orders from 2024-03-01 to 2024-03-31

Преимущество: Arching старых partitions, быстрее поиск

Partition по range:

Таблица users:
Partition p1: user_id < 1000000
Partition p2: user_id >= 1000000 AND user_id < 2000000
Partition p3: user_id >= 2000000

5. Caching Layer

Что это: Добавление кэша между приложением и БД.

Без кэша:
Query → DB → 100ms

С кэшем:
Query → Cache (hit) → 1ms
Query → Cache (miss) → DB → 100ms, then cache

Популярные решения:

  • Redis — in-memory data store
  • Memcached — distributed memory caching
  • Varnish — HTTP cache
  • Application-level cache

Пример:

import redis

cache = redis.Redis(host='localhost', port=6379)

# Check cache
user = cache.get(f"user:{user_id}")
if not user:
    # Cache miss, get from DB
    user = db.query(f"SELECT * FROM users WHERE id = {user_id}")
    # Store in cache for 1 hour
    cache.setex(f"user:{user_id}", 3600, user)

return user

Сравнение стратегий

СтратегияМасштабируемостьСложностьКонсистентностьКогда использовать
VerticalОграниченоНизкаяПолнаяСтартап, небольшая нагрузка
ShardingВысокаяВысокаяЛокальнаяОчень большие данные
ReplicationСредняяСредняяEventualRead-heavy приложение
PartitioningСредняяСредняяПолнаяВременные данные, archiving
CachingЗависитНизкаяEventualЛюбое приложение

Практический подход

Фаза 1: Стартап

Одна хорошая машина
├─ PostgreSQL 16GB RAM
├─ Оптимизированные queries
├─ Индексы
└─ Может выдержать миллионы записей

Фаза 2: Растущая нагрузка

Вертикальное масштабирование
├─ 64GB RAM
├─ SSD
├─ Читай-оптимизированная конфигурация
└─ Плюс read replicas для SELECT

Фаза 3: Высокие требования

Replication + Caching
├─ Master-Slave репликация
├─ Read load balancing
├─ Redis caching
├─ Query optimization
└─ Мониторинг

Фаза 4: Мега-масштабирование

Sharding + Replication + Caching
├─ Разделение данных по shards
├─ Replicas каждого shard
├─ Redis cluster
├─ Distributed transactions (если нужны)
└─ Operational expertise

Лучшие практики

  1. Сначала оптимизируй queries

    • INDEX!
    • Избегай N+1 queries
    • Analyze EXPLAIN планов
  2. Добавь кэш рано

    • Redis дешево
    • Огромный ROI
  3. Мониторь от начала

    • Когда горячие таблицы?
    • Какие queries медленные?
    • Какой CPU/RAM usage?
  4. План на масштабирование

    • Выбери shard key заранее
    • Архитектурные решения сейчас
    • Тестируй нагрузку
  5. Не масштабируй раньше времени

    • Premature optimization
    • Сначала fix queries
    • Потом add replication
    • Потом sharding

Масштабирование БД — это искусство и наука. Правильный выбор стратегии зависит от типа данных, паттернов доступа и бизнес-требований.

Какие способы масштабирования баз данных вы знаете? Чем отличается вертикальное от горизонтального масштабирования? | PrepBro