Производительность и оптимизация

Localzet Server разработан с фокусом на максимальную производительность и эффективное использование ресурсов системы.

Архитектурные оптимизации

1. Многопроцессорная обработка

Принцип работы:

  • Каждый CPU core обслуживается отдельным worker процессом
  • Использование SO_REUSEPORT для распределения соединений на уровне ядра
  • Минимизация конкуренции за ресурсы между процессами

Оптимальная настройка:

// Количество процессов = количество CPU cores
$server->count = cpu_count(); // Автоматическое определение

2. Event-driven I/O

Преимущества:

  • Неблокирующие операции чтения/записи
  • Обработка тысяч соединений в одном процессе
  • Минимальное использование потоков

Сравнение с блокирующим I/O:

Блокирующий I/O:         Event-driven I/O:
Process → Socket         Process → Event Loop
    ↓                        ↓
  Wait                   Monitor (non-blocking)
    ↓                        ↓
  Block                  Continue processing
    ↓                        ↓
Handle 1 connection    Handle 1000+ connections

3. Эффективное мультиплексирование

Выбор механизма:

  • epoll (Linux): O(1) для большого количества дескрипторов
  • kqueue (BSD/macOS): Аналогично epoll
  • select (fallback): O(n), но работает везде

Производительность:

Дескрипторовselectepoll
100~1ms~0.1ms
1,000~10ms~0.1ms
10,000~100ms~0.1ms

Оптимизация памяти

1. Изоляция процессов

Каждый worker процесс имеет изолированную память:

  • Преимущество: Отказ одного процесса не влияет на другие
  • Недостаток: Нельзя напрямую делиться данными между процессами
  • Решение: Использование внешних хранилищ (Redis, Memcached) для общих данных

2. Управление буферами

Оптимизация буферов:

// Чтение оптимальными порциями
READ_BUFFER_SIZE = 87380; // Размер TCP окна

// Управление буфером отправки
if (strlen($sendBuffer) < $maxSendBufferSize) {
    // Продолжаем накопление
} else {
    // Приостанавливаем прием (backpressure)
    pauseRecv();
}

Стратегии управления памятью:

  • Предварительное выделение: Избежание частых аллокаций
  • Переиспользование объектов: Кеширование и клонирование объектов
  • Своевременная очистка: Освобождение ресурсов при закрытии соединений

3. Кеширование

Кеш запросов:

// Для повторяющихся HTTP запросов
static $requests = [];

// LRU кеш с ограничением размера
if (count($requests) > MAX_CACHE_SIZE) {
    unset($requests[key($requests)]); // Удаление самого старого
}

Эффективность кеша:

  • Снижение нагрузки на парсинг на 30-70% для повторяющихся запросов
  • Минимальные накладные расходы памяти
  • Автоматическое управление размером

Оптимизация сети

1. TCP оптимизации

Настройки сокета:

// TCP_NODELAY - отключение алгоритма Nagle
socket_set_option($socket, SOL_TCP, TCP_NODELAY, 1);

// SO_KEEPALIVE - поддержание соединения
socket_set_option($socket, SOL_SOCKET, SO_KEEPALIVE, 1);

// SO_REUSEPORT - распределение нагрузки
socket_set_option($socket, SOL_SOCKET, SO_REUSEPORT, 1);

Backlog очередь:

// Максимальная длина очереди ожидающих соединений
const DEFAULT_BACKLOG = 102400;

2. Буферизация отправки

Алгоритм:

1. Попытка прямой отправки:
   if (sendBuffer empty) {
       len = fwrite(socket, data);
       if (len == data.length) {
           return success; // Отправлено полностью
       }
   }

2. Добавление в буфер:
   sendBuffer .= data;

3. Регистрация в Event Loop:
   eventLoop->onWritable(socket, baseWrite);

Преимущества:

  • Минимизация системных вызовов
  • Автоматическое управление backpressure
  • Эффективная обработка медленных соединений

3. Потоковая передача файлов

Для больших файлов:

// Для файлов > 2MB - потоковая передача
if ($fileSize > 2 * 1024 * 1024) {
    // 1. Отправка заголовков
    send($responseHeaders);
    
    // 2. Постепенное чтение и отправка
    while (!feof($file)) {
        $chunk = fread($file, 8192);
        send($chunk, true); // raw mode
    }
}

Преимущества:

  • Не загружает весь файл в память
  • Эффективное использование памяти
  • Поддержка больших файлов без ограничений

Оптимизация CPU

1. Эффективные алгоритмы

Парсинг протоколов:

  • Использование нативных функций PHP где возможно
  • Минимизация регулярных выражений
  • Кеширование результатов парсинга

Структуры данных:

  • Min-heap для таймеров: O(log n) вставка, O(1) получение минимума
  • Хэш-таблицы для быстрого доступа к соединениям
  • Оптимизированные строковые операции

2. Минимизация копирования данных

Zero-copy подходы:

// Использование ссылок вместо копирования
$package = &$this->recvBuffer; // Ссылка, не копия

// Извлечение только при необходимости
$this->recvBuffer = substr($this->recvBuffer, $length);

Оптимизация строк:

  • Использование substr() вместо explode() где возможно
  • Избежание конкатенации в циклах
  • Использование pack()/unpack() для бинарных данных

3. Оптимизация таймеров

Timer Queue:

// Min-heap для эффективного управления
class TimerQueue {
    private array $heap = [];
    
    public function extract(float $now): ?TimerCallback {
        if (empty($this->heap)) {
            return null;
        }
        
        // O(1) получение минимального элемента
        $timer = $this->heap[0];
        
        if ($timer->getTime() > $now) {
            return null; // Еще не время
        }
        
        // O(log n) удаление корня
        $this->removeRoot();
        
        return $timer;
    }
}

Метрики производительности

Бенчмарки

HTTP сервер (4 процесса, 4 CPU cores):

МетрикаЗначение
Requests/sec50,000+
Concurrent connections10,000+
Latency (p50)< 1ms
Latency (p99)< 10ms
Memory per process20-50 MB

WebSocket сервер:

МетрикаЗначение
Connections50,000+ на процесс
Messages/sec100,000+
Latency< 5ms

Факторы производительности

1. Количество процессов:

Оптимально: CPU cores × 1-2
Слишком мало: Недостаточное использование CPU
Слишком много: Конкуренция за ресурсы

2. Размер буферов:

Оптимально:
- maxSendBufferSize: 1-4 MB
- maxPackageSize: 1-10 MB
- readBufferSize: 64-128 KB

3. Выбор Event Loop:

Производительность:
libuv > libev > libevent > stream_select

Рекомендации по оптимизации

1. Настройка операционной системы

Linux:

# Увеличение лимитов файловых дескрипторов
ulimit -n 65535

# Оптимизация TCP
echo 'net.core.somaxconn = 65535' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_tw_reuse = 1' >> /etc/sysctl.conf
echo 'net.ipv4.ip_local_port_range = 1024 65535' >> /etc/sysctl.conf

# Применение
sysctl -p

2. Настройка PHP

php.ini оптимизации:

; Отключение неиспользуемых функций
disable_functions = ""

; Оптимизация памяти
memory_limit = 256M
opcache.enable = 1
opcache.memory_consumption = 128

; Оптимизация сборщика мусора
zend.enable_gc = 1

3. Оптимизация кода приложения

Избегайте:

  • Блокирующих операций в обработчиках
  • Долгих вычислений в onMessage
  • Использования sleep() вместо Timer::sleep()

Используйте:

  • Асинхронные операции для I/O
  • Таймеры для отложенных операций
  • Кеширование результатов вычислений

4. Мониторинг производительности

Встроенная статистика:

// Получение статистики
$stats = ConnectionInterface::$statistics;
// [
//     'connection_count' => 1234,
//     'total_request' => 56789,
//     'throw_exception' => 5,
//     'send_fail' => 2
// ]

// Статистика сервера
Server::getAllServers();

Внешний мониторинг:

  • Интеграция с Prometheus/Grafana
  • Логирование метрик
  • Алерты при превышении лимитов

Профилирование

Инструменты профилирования

  1. Xdebug - Профилирование PHP кода
  2. Blackfire - Профессиональное профилирование
  3. strace - Отслеживание системных вызовов
  4. tcpdump - Анализ сетевого трафика

Типичные проблемы производительности

1. Утечки памяти:

// Проблема: Накопление объектов
$connections[] = $connection; // Без удаления

// Решение: Очистка при закрытии
$connection->onClose = function($conn) use (&$connections) {
    unset($connections[$conn->id]);
};

2. Блокирующие операции:

// Проблема
onMessage($conn, $data) {
    $result = file_get_contents('large_file.txt'); // Блокирует!
}

// Решение
onMessage($conn, $data) {
    $file = fopen('large_file.txt', 'r');
    $eventLoop->onReadable($file, function($file) use ($conn) {
        $chunk = fread($file, 8192);
        $conn->send($chunk);
    });
}

3. Неоптимальные структуры данных:

// Проблема: Линейный поиск
foreach ($connections as $conn) {
    if ($conn->id === $targetId) {
        // O(n)
    }
}

// Решение: Хэш-таблица
$connection = $connections[$targetId]; // O(1)

Масштабирование

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

Load Balancer + Multiple Servers:

                ┌──────────────┐
                │ Load Balancer│
                └──────┬───────┘
                       │
        ┌──────────────┼──────────────┐
        │              │              │
   ┌────▼────┐    ┌────▼────┐    ┌────▼────┐
   │ Server 1│    │ Server 2│    │ Server 3│
   │ (4 CPU) │    │ (4 CPU) │    │ (4 CPU) │
   └─────────┘    └─────────┘    └─────────┘

Оптимальная конфигурация:

  • Nginx/HAProxy как load balancer
  • Session sticky для WebSocket соединений
  • Shared storage для сессий (Redis)

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

Оптимизация одного сервера:

  • Увеличение количества worker процессов
  • Оптимизация буферов
  • Использование более производительного Event Loop
  • Настройка операционной системы

Безопасность и валидация