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

Как масштабировать высоконагруженную систему?

2.7 Senior🔥 161 комментариев
#DevOps и инфраструктура#Архитектура и паттерны

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

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

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

Масштабирование высоконагруженной системы

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

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

Load Balancing — распределение трафика между серверами

Клиенты
   |
   v
+--------+
|  LB    | (Load Balancer - nginx, HAProxy)
+--------+
   |
   +--- API Server 1
   +--- API Server 2
   +--- API Server 3
   +--- API Server N
# nginx config
upstream backend {
    server 192.168.1.1:8000;
    server 192.168.1.2:8000;
    server 192.168.1.3:8000;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Round-robin балансировка:

  • Запрос 1 → Сервер A
  • Запрос 2 → Сервер B
  • Запрос 3 → Сервер C
  • Запрос 4 → Сервер A (циклически)

Weighted балансировка — разные серверы разной мощности:

upstream backend {
    server 192.168.1.1:8000 weight=5;  # 50% трафика
    server 192.168.1.2:8000 weight=3;  # 30% трафика
    server 192.168.1.3:8000 weight=2;  # 20% трафика
}

Кеширование (Caching)

In-Memory Cache — Redis для горячих данных

import redis
from datetime import timedelta

redis_client = redis.Redis(host='localhost', port=6379, db=0)

def get_user(user_id: int):
    # Проверяем кеш
    cached = redis_client.get(f"user:{user_id}")
    if cached:
        return json.loads(cached)
    
    # Запрашиваем БД
    user = db.query(User).filter(User.id == user_id).first()
    
    # Сохраняем в кеш на 1 час
    redis_client.setex(
        f"user:{user_id}",
        timedelta(hours=1),
        json.dumps(user)
    )
    return user

# Инвалидация кеша при обновлении
def update_user(user_id: int, data: dict):
    user = db.query(User).filter(User.id == user_id).update(data)
    db.commit()
    redis_client.delete(f"user:{user_id}")  # Очистить кеш
    return user

HTTP Caching — браузерный кеш, CDN

from fastapi import Response
from datetime import datetime, timedelta

@app.get("/users/{user_id}")
async def get_user(user_id: int, response: Response):
    user = await get_user_from_db(user_id)
    
    # Кешировать 1 час в браузере
    response.headers["Cache-Control"] = "max-age=3600, public"
    response.headers["ETag"] = f'"{hash(user)}"'
    
    return user

CDN — Content Delivery Network, геораспределённое кеширование

Клиент в Москве
  |
  v
+----------+
| CDN Node | (в Москве) — кеширует статику
+----------+
  |
  v
+----------+
| Origin   | (основной сервер в другой стране)
+----------+

Асинхронность и очереди (Message Queues)

Offload тяжелые операции в фоновые задачи

# Основной API (быстро)
from celery import Celery

app = Celery('myapp', broker='redis://localhost:6379')

@app.route("/send-email", methods=["POST"])
async def send_email(data: EmailData):
    # Не ждём результат, кладём в очередь
    send_email_task.delay(data.email, data.subject, data.body)
    return {"status": "email queued"}

# Фоновая задача
@app.task
def send_email_task(email: str, subject: str, body: str):
    # Это выполнится в отдельном рабочем процессе
    smtp.send(email, subject, body)

Publish-Subscribe — многие потребители

import asyncio
from aio_pika import connect_robust, Message

async def publish_event(event_name: str, data: dict):
    connection = await connect_robust("amqp://guest:guest@localhost/")
    channel = await connection.channel()
    exchange = await channel.declare_exchange(event_name, 'topic', durable=True)
    await exchange.publish(
        Message(body=json.dumps(data).encode()),
        routing_key='notification.user.created'
    )

# Потребители слушают событие
async def on_user_created(event_data):
    await send_welcome_email(event_data['email'])

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

Read Replicas — копии БД для чтения

Пишем → Primary БД
Читаем → Replica 1, Replica 2, Replica 3
from sqlalchemy import create_engine

# Для записи
write_engine = create_engine('postgresql://user:pass@primary:5432/db')

# Для чтения (round-robin между репликами)
read_engines = [
    create_engine('postgresql://user:pass@replica1:5432/db'),
    create_engine('postgresql://user:pass@replica2:5432/db'),
]

def get_read_engine():
    return random.choice(read_engines)

# При запросе
user = get_read_engine().query(User).filter(...).first()

Sharding — разделение данных по ключу

user_id = 12345
shard_num = user_id % 4  # Распределить на 4 шарда

db = db_shards[shard_num]  # Выбрать нужную БД
user = db.query(User).filter(User.id == user_id).first()

Асинхронные фреймворки

# FastAPI + async (быстрее обрабатывает много одновременных запросов)
from fastapi import FastAPI
import asyncio

app = FastAPI()

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # Ждём асинхронно, не блокируя поток
    user = await db.fetch_user(user_id)
    posts = await db.fetch_user_posts(user_id)
    return {"user": user, "posts": posts}

# Uvicorn с несколькими рабочими процессами
# uvicorn main:app --workers 4 --host 0.0.0.0

Мониторинг и профилирование

# Выявляем узкие места
import cProfile
import pstats
from functools import wraps
import time

def profile_func(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        result = func(*args, **kwargs)
        elapsed = time.perf_counter() - start
        print(f"{func.__name__} took {elapsed:.4f}s")
        return result
    return wrapper

@profile_func
def heavy_operation():
    time.sleep(1)

# Метрики для мониторинга
from prometheus_client import Counter, Histogram

request_count = Counter('http_requests_total', 'Total requests')
request_duration = Histogram('http_request_duration_seconds', 'Request duration')

@app.get("/api/data")
@request_duration.time()
async def get_data():
    request_count.inc()
    return {"data": "value"}

Архитектура примера

[Клиенты]
    |
    v
[CloudFlare CDN] (статика, DDoS защита)
    |
    v
[nginx LB] (10k соединений / сервер)
    |
    +--- [Python API 1-100] (async/await, uvicorn)
    +--- [Python API 2-100] (async/await, uvicorn)
    +--- [Python API N-100] (async/await, uvicorn)
    |
    +--- [Redis Cluster] (кеш, сессии, очереди)
    +--- [PostgreSQL Primary] (основные данные)
    +--- [PostgreSQL Replicas x3] (для чтения)
    +--- [Elasticsearch] (полнотекстовый поиск)
    +--- [RabbitMQ/Kafka] (асинхронные задачи)

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

Начни с простого — масштабируй когда действительно нужно. Профилируй перед оптимизацией — не гадай. Кешируй часто запрашиваемые данные — Redis дешевле БД. Используй асинхронность — FastAPI + asyncpg. Разделяй на сервисы — микросервисная архитектура. Мониторь всё — prometeus, Grafana, ELK stack.