Производительность и оптимизация
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), но работает везде
Производительность:
| Дескрипторов | select | epoll |
|---|---|---|
| 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/sec | 50,000+ |
| Concurrent connections | 10,000+ |
| Latency (p50) | < 1ms |
| Latency (p99) | < 10ms |
| Memory per process | 20-50 MB |
WebSocket сервер:
| Метрика | Значение |
|---|---|
| Connections | 50,000+ на процесс |
| Messages/sec | 100,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
- Логирование метрик
- Алерты при превышении лимитов
Профилирование
Инструменты профилирования
- Xdebug - Профилирование PHP кода
- Blackfire - Профессиональное профилирование
- strace - Отслеживание системных вызовов
- 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
- Настройка операционной системы

