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

Что такое горизонтальное масштабирование?

2.2 Middle🔥 151 комментариев
#DevOps и инфраструктура#Архитектура и паттерны

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

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

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

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

Горизонтальное масштабирование — это добавление новых серверов/узлов в систему для распределения нагрузки и увеличения пропускной способности. Это противоположность вертикальному масштабированию (добавление мощности одному серверу).

Горизонтальное vs Вертикальное масштабирование

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

Сервер 1        →        Сервер 1 (мощнее)
4 CPU, 8GB RAM   →        16 CPU, 64GB RAM

Плюсы:

  • Просто реализовать
  • Приложение не нужно менять
  • Нет проблем с синхронизацией

Минусы:

  • Есть потолок (нельзя бесконечно добавлять мощность)
  • Дорого (экспоненциально)
  • Простой при апгрейде
  • Single point of failure

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

    ┌──────────┐
    │ Load     │
    │ Balancer │
    └────┬─────┘
         │
    ┌────┴────┬──────┐
    │          │      │
Server 1   Server 2  Server 3
4CPU, 8GB  4CPU, 8GB  4CPU, 8GB

Плюсы:

  • Масштабируется практически без ограничений
  • Дешевле (много дешевых серверов vs один мощный)
  • Не требует простоя (hot scaling)
  • Отказоустойчивость (если один падает, остальные работают)

Минусы:

  • Сложнее реализовать
  • Нужен load balancer
  • Требует распределение состояния
  • Проблемы с синхронизацией данных
  • Усложняет отладку

Архитектура горизонтального масштабирования

┌─────────────────────────────────────┐
│         Internet / Clients          │
└────────────────┬────────────────────┘
                 │
         ┌───────▼────────┐
         │  Load Balancer │ (Nginx, HAProxy)
         ├────────────────┤
         │ - Round Robin  │
         │ - Sticky       │
         │ - Least Conn   │
         └────────┬───────┘
                  │
      ┌───────────┼───────────┐
      │           │           │
  ┌─────────┐ ┌─────────┐ ┌─────────┐
  │ Server 1│ │ Server 2│ │ Server 3│
  │ App     │ │ App     │ │ App     │
  └──┬──────┘ └──┬──────┘ └──┬──────┘
     │           │           │
     └───────────┼───────────┘
                 │
         ┌───────▼────────┐
         │  Shared DB     │ (PostgreSQL, MySQL)
         └────────────────┘
         
         └───────▼────────┐
         │  Cache (Redis) │
         └────────────────┘

Методы распределения нагрузки (Load Balancing)

1 Round Robin

Запрос 1 → Server 1
Запрос 2 → Server 2
Запрос 3 → Server 3
Запрос 4 → Server 1
Запрос 5 → Server 2

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

2 Least Connections

Server 1: 5 активных соединений
Server 2: 2 активных соединения ← новый запрос идет сюда
Server 3: 8 активных соединений

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

3 IP Hash

ip_hash(client_ip) % num_servers → сервер для этого клиента

Плюсы: клиент всегда попадает на один сервер (sticky sessions) Минусы: несбалансированное распределение, если клиентов неравномерно

4 Weighted Distribution

Server 1 (вес 3): 60% трафика
Server 2 (вес 1): 20% трафика
Server 3 (вес 1): 20% трафика

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

Пример с Nginx

upstream app_servers {
    # Round Robin (по умолчанию)
    server 192.168.1.10:8000;
    server 192.168.1.11:8000;
    server 192.168.1.12:8000;
    
    # Или Least Connections
    # least_conn;
    
    # Или Weighted
    # server 192.168.1.10:8000 weight=3;
    # server 192.168.1.11:8000 weight=1;
}

server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://app_servers;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # Health check
        proxy_connect_timeout 5s;
        proxy_send_timeout 10s;
        proxy_read_timeout 10s;
    }
}

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

Проблема 1: Session State

# Без синхронизации — НЕПРАВИЛЬНО
# Запрос 1 → Server 1: session['user_id'] = 123
# Запрос 2 → Server 2: session['user_id'] не определен!

Решение 1: Sticky Sessions (Session Affinity)

Любой запрос от клиента всегда идет на тот же сервер.

**Решение 2: Распределённая сессия (Redis)

# Использовать Redis для хранения сессий
# Все серверы читают/пишут в Redis

import redis
from flask import Flask
from flask_session import Session

app = Flask(__name__)
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.from_url('redis://localhost:6379')

Session(app)

@app.route('/login')
def login():
    session['user_id'] = 123
    return 'OK'

@app.route('/profile')
def profile():
    # Работает на любом сервере
    return f"User {session['user_id']}"

Проблема 2: Синхронизация данных

# Кэш разный на каждом сервере
Server 1 cache: user.name = "John"
Server 2 cache: user.name = "Jane"

Решение: Центральный кэш (Redis, Memcached)

import redis

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

def get_user(user_id):
    # Кэш на центральном сервере
    cached = cache.get(f'user:{user_id}')
    if cached:
        return json.loads(cached)
    
    user = db.query(User).filter(User.id == user_id).one()
    cache.setex(f'user:{user_id}', 3600, json.dumps(user.to_dict()))
    return user

Проблема 3: Uploads и files

# Неправильно: файл только на Server 1
Server 1: /uploads/user_123_photo.jpg
Server 2: файл не существует! 404

Решение: Объектное хранилище (S3, GCS, Minio)

import boto3

s3 = boto3.client('s3')

# Загружаем на S3 (доступно со всех серверов)
s3.put_object(
    Bucket='my-bucket',
    Key=f'uploads/user_{user_id}_photo.jpg',
    Body=file_content
)

# Получаем с S3 (работает на любом сервере)
url = s3.generate_presigned_url(
    'get_object',
    Params={'Bucket': 'my-bucket', 'Key': f'uploads/user_{user_id}_photo.jpg'},
    ExpiresIn=3600
)

Базы данных и горизонтальное масштабирование

Проблема: БД становится узким местом

Server 1 ──┐
Server 2 ──┼─→ Single Database ← узкое место
Server 3 ──┘

Решение 1: Database Replication (Master-Slave)

Master (write)              Slave 1 (read)
    ├─────────────────────────────┤
    │                             │
Server 1 (write)        Server 2 (read)
Server 1 (read)         Server 3 (read)

Решение 2: Sharding (горизонтальное разделение БД)

Shard 1: users 1-1000000
Shard 2: users 1000001-2000000
Shard 3: users 2000001-3000000

get_shard(user_id) = hash(user_id) % num_shards

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

# app.py
from flask import Flask, request, session
import redis
import boto3

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'

# Распределённая сессия
redis_session = redis.Redis(host='redis', port=6379, db=0)

# Кэш
redis_cache = redis.Redis(host='redis', port=6379, db=1)

# S3 для файлов
s3 = boto3.client('s3', endpoint_url='http://minio:9000')

# БД (master для write, slaves для read)
from sqlalchemy import create_engine
db_write = create_engine('postgresql://user:pass@db-master/app')
db_read = create_engine('postgresql://user:pass@db-slave-1/app')

@app.route('/profile')
def profile():
    user_id = session.get('user_id')
    
    # Пытаемся из кэша
    cached = redis_cache.get(f'user:{user_id}')
    if cached:
        return cached.decode()
    
    # Читаем с read replica
    user = db_read.execute(f'SELECT * FROM users WHERE id = {user_id}').first()
    
    # Кэшируем результат
    redis_cache.setex(f'user:{user_id}', 3600, str(user))
    
    return str(user)

@app.route('/upload', methods=['POST'])
def upload():
    file = request.files['file']
    user_id = session.get('user_id')
    
    # Загружаем на S3
    s3.put_object(
        Bucket='app-bucket',
        Key=f'user_{user_id}/{file.filename}',
        Body=file.read()
    )
    
    # Инвалидируем кэш
    redis_cache.delete(f'user:{user_id}')
    
    return 'OK'

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

Используй горизонтальное масштабирование для:

  • Stateless приложений (HTTP API, микросервисы)
  • Высоконагруженных систем
  • Когда нужна отказоустойчивость
  • Web приложений
  • Микросервисной архитектуры

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

  • Legacy приложений со статом
  • Когда вертикальное масштабирование дешевле
  • Высокочастотного трейдинга (latency критичен)

Итог

Горизонтальное масштабирование — это стандартный подход в современной архитектуре. Оно позволяет системе расти без ограничений, но требует правильной архитектуры, удаления state из приложения и использования распределённых сервисов (Redis, S3, message queues). При правильной реализации, это мощный инструмент для создания масштабируемых систем.

Что такое горизонтальное масштабирование? | PrepBro