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

Как решишь проблему перегрузки сервера Load Average?

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

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

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

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

Решение проблемы перегрузки сервера (High Load Average)

Высокий Load Average указывает на перегрузку CPU или I/O. Подход должен быть систематичным: диагностика → анализ → оптимизация.

1. Диагностика: Определить причину

# Проверить load average
uptime
# Вывод: load average: 15.23, 12.45, 10.56
# 5 минут: 15.23 | 10 минут: 12.45 | 15 минут: 10.56

# Системный мониторинг
top -b -n 1 | head -15  # Процессы с высокой нагрузкой

ps aux --sort=-%cpu | head -10  # По CPU
ps aux --sort=-%mem | head -10  # По памяти

# I/O нагрузка
iotop -b -n 1
iostat -x 1 5  # Дисковая активность

# Network нагрузка
netstat -an | grep ESTABLISHED | wc -l
ss -s  # Сокеты и соединения

# Системные ресурсы
free -h  # Память
df -h   # Диск

2. Python код: Диагностический скрипт

import psutil
import time
from collections import defaultdict

class SystemDiagnostics:
    def __init__(self):
        self.cpu_count = psutil.cpu_count()
        self.thresholds = {
            'load_avg': self.cpu_count * 2,  # Warning выше 2x CPU count
            'memory': 85,  # 85% памяти
            'disk': 90,    # 90% диска
        }
    
    def check_load_average(self):
        load_avg = psutil.getloadavg()
        cpu_count = psutil.cpu_count()
        
        severity = "OK"
        if load_avg[0] > cpu_count * 1.5:
            severity = "WARNING"
        elif load_avg[0] > cpu_count * 3:
            severity = "CRITICAL"
        
        print(f"Load Average: {load_avg}")
        print(f"CPU Count: {cpu_count}")
        print(f"Status: {severity}")
        
        return load_avg, severity
    
    def check_process_bottleneck(self):
        """Определить какие процессы потребляют ресурсы"""
        processes = []
        
        for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_percent']):
            try:
                processes.append(proc.info)
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                pass
        
        # Сортируем по CPU
        top_cpu = sorted(processes, key=lambda x: x['cpu_percent'], reverse=True)[:5]
        
        print("\nTop 5 CPU consumers:")
        for proc in top_cpu:
            print(f"{proc['name']}: {proc['cpu_percent']}% CPU")
        
        return top_cpu
    
    def check_io_bottleneck(self):
        """Проверить I/O нагрузку"""
        disk_io = psutil.disk_io_counters()
        print(f"\nDisk I/O:")
        print(f"Read: {disk_io.read_bytes / 1024 / 1024:.2f} MB")
        print(f"Write: {disk_io.write_bytes / 1024 / 1024:.2f} MB")
        
        net_io = psutil.net_io_counters()
        print(f"\nNetwork I/O:")
        print(f"Sent: {net_io.bytes_sent / 1024 / 1024:.2f} MB")
        print(f"Recv: {net_io.bytes_recv / 1024 / 1024:.2f} MB")
        
        return disk_io, net_io

diag = SystemDiagnostics()
diag.check_load_average()
diag.check_process_bottleneck()
diag.check_io_bottleneck()

3. Решение: Оптимизация на уровне Python приложения

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

# ❌ Неправильно — синхронные I/O операции
def handle_request(request):
    data = requests.get('https://api.example.com/data')  # Блокирует
    result = database.query('SELECT * FROM users')  # Блокирует
    return result

# Если 100 запросов одновременно — нужно 100 потоков/процессов

Решение 1: Асинхронный код

# ✅ Правильно — асинхронные операции
import asyncio
import aiohttp
from sqlalchemy.ext.asyncio import create_async_engine

async def handle_request(request):
    async with aiohttp.ClientSession() as session:
        async with session.get('https://api.example.com/data') as resp:
            data = await resp.json()  # Не блокирует
    
    # Асинхронный запрос к БД
    async with db_session() as session:
        result = await session.execute(select(User))
    
    return result

# 1000 одновременных запросов — один поток, one event loop

Решение 2: Кеширование

from functools import lru_cache
import time

class DataCache:
    def __init__(self, ttl_seconds=60):
        self.cache = {}
        self.ttl = ttl_seconds
    
    def get_data(self, key):
        if key in self.cache:
            value, timestamp = self.cache[key]
            if time.time() - timestamp < self.ttl:
                return value  # Из кеша
        
        # Если нет в кеше — вычислить
        value = self._expensive_operation(key)
        self.cache[key] = (value, time.time())
        return value
    
    def _expensive_operation(self, key):
        # Дорогостоящая операция
        return f"data_{key}"

# Redis кеширование (еще лучше)
import redis

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

def get_user_with_cache(user_id):
    cache_key = f"user:{user_id}"
    
    # Попытка получить из Redis
    cached = redis_client.get(cache_key)
    if cached:
        return json.loads(cached)
    
    # Если нет — получить из БД
    user = database.get_user(user_id)
    
    # Сохранить в Redis на 10 минут
    redis_client.setex(cache_key, 600, json.dumps(user))
    
    return user

Решение 3: Queue & Worker Pool

from celery import Celery
from kombu import Queue

app = Celery('myapp')

# Асинхронная очередь для тяжелых операций
@app.task(queue='background')
def process_heavy_task(data):
    # Эта операция выполняется в отдельном worker'е
    # Не блокирует основное приложение
    return expensive_computation(data)

def handle_request(request):
    # Просто добавляем в очередь
    task = process_heavy_task.delay(request.data)
    return {"status": "processing", "task_id": task.id}

# Worker конфигурация
app.conf.update(
    broker_url='redis://localhost:6379',
    result_backend='redis://localhost:6379',
    worker_max_tasks_per_child=1000,  # Перезагружать процесс каждые 1000 задач
    worker_prefetch_multiplier=4,     # Сколько задач захватить за раз
    worker_concurrency=8,             # Количество worker процессов
)

Решение 4: Database Query Optimization

from sqlalchemy import select, joinedload
from sqlalchemy.orm import Session

# ❌ N+1 problem — множество запросов
def get_users_bad():
    users = session.query(User).all()
    for user in users:
        print(user.posts)  # Отдельный запрос для каждого пользователя!

# ✅ Eager loading
def get_users_good():
    users = session.query(User).options(
        joinedload(User.posts)
    ).all()
    # Один или два запроса максимум
    for user in users:
        print(user.posts)

# ✅ Индексы
# ALTER TABLE users ADD INDEX idx_email (email);
# CREATE INDEX idx_created_at ON orders(created_at DESC);

Решение 5: Connection Pooling

from sqlalchemy import create_engine

# Хорошая конфигурация
engine = create_engine(
    'postgresql://user:password@localhost/db',
    pool_size=20,              # Базовый размер пула
    max_overflow=40,           # Максимум дополнительных соединений
    pool_recycle=3600,         # Переиспользовать соединение каждый час
    pool_pre_ping=True,        # Проверить соединение перед использованием
    echo_pool=True,            # Логировать статистику пула
)

4. Системный уровень: DevOps решения

# Увеличить лимиты файлов
ulimit -n 65536

# TCP оптимизация
sysctl -w net.ipv4.tcp_max_syn_backlog=4096
sysctl -w net.core.somaxconn=4096
sysctl -w net.ipv4.tcp_tw_reuse=1

# Kernel scheduler tuning
sysctl -w kernel.sched_migration_cost_ns=5000000

5. Стратегия скейлинга

# Горизонтальный скейлинг — несколько инстансов
# Load Balancer (nginx, HAProxy) распределяет трафик

# Вертикальный скейлинг — мощнее железо

# Гибридный подход:
# 1. Кеширование (Redis)
# 2. Асинхронность (asyncio, Celery)
# 3. Несколько worker'ов (4-8 процессов)
# 4. Несколько инстансов приложения
# 5. Load balancer (nginx)

Чеклист решения проблемы

  1. Диагностика: top, iostat, ps aux
  2. Определить тип нагрузки: CPU-bound vs I/O-bound
  3. Профилирование: cProfile, PyFlame для CPU
  4. Оптимизация:
    • CPU: Асинхронность, multiprocessing
    • I/O: Кеширование, Connection pooling, SQL optimization
  5. Масштабирование: Горизонтальное или вертикальное
  6. Мониторинг: Prometheus, Grafana, DataDog

Высокий Load Average редко решается одним решением — обычно нужна комбинация техник и постоянный мониторинг.