Решение проблем и отладка
Подробное руководство по диагностике и решению типичных проблем в Localzet Server.
Диагностика проблем
Проверка статуса сервера
# Статус всех процессов
php start.php status
# Статус в реальном времени
php start.php status -d
# Текущие соединения
php start.php connections
Вывод статуса включает:
- Количество процессов
- Статус каждого процесса
- Статистику соединений и запросов
- Использование памяти
- Время работы
Логирование
// Настройка файла лога
Server::$logFile = '/var/log/localzet.log';
// Все ошибки автоматически логируются
// Проверка логов
tail -f /var/log/localzet.log
Отладка через код
// Вывод в лог
Server::log("Debug message");
// Безопасный вывод в консоль
Server::safeEcho("Debug: " . $data . "\n");
// Dump переменных
Server::log(var_export($data, true));
Типичные проблемы
1. Сервер не запускается
Симптомы:
- Процесс завершается сразу после старта
- Ошибки в логах
- Порт недоступен
Диагностика:
# Проверка PID файла
cat localzet.start.php.pid
# Проверка, не запущен ли уже сервер
ps aux | grep start.php
# Проверка доступности порта
netstat -tuln | grep 8080
# или
ss -tuln | grep 8080
Решения:
- Порт занят:
# Найти процесс, использующий порт
lsof -i :8080
# или
fuser 8080/tcp
# Остановить процесс
kill -9 <PID>
- Отсутствуют расширения:
# Проверка расширений
php -m | grep -E 'pcntl|posix|sockets'
# Установка расширений
# Для Debian/Ubuntu:
apt-get install php8.1-pcntl php8.1-posix php8.1-sockets
# Перезапуск PHP-FPM или CLI
- Проблемы с правами:
# Проверка прав на файлы
ls -la start.php
# Установка прав
chmod +x start.php
2. Высокое использование памяти
Симптомы:
- Процессы потребляют много памяти
- Утечки памяти со временем
Диагностика:
// Мониторинг памяти в коде
$server->onMessage = function($conn, $req) {
$memory = memory_get_usage(true);
if ($memory > 100 * 1024 * 1024) { // 100MB
Server::log("High memory usage: " . ($memory / 1024 / 1024) . " MB");
}
};
Решения:
- Проверка на утечки:
// Всегда очищайте ссылки при закрытии соединения
$server->onClose = function($conn) {
// Очистка данных соединения
$conn->onMessage = null;
$conn->onClose = null;
// Удаление из глобальных массивов
unset($globalArray[$conn->id]);
};
- Ограничение размеров буферов:
// Уменьшение максимальных размеров
TcpConnection::$defaultMaxSendBufferSize = 524288; // 512KB
TcpConnection::$defaultMaxPackageSize = 5242880; // 5MB
- Принудительная сборка мусора:
// Периодическая сборка мусора
Timer::repeat(60.0, function() {
gc_collect_cycles();
});
3. Соединения закрываются неожиданно
Симптомы:
- Клиенты теряют соединение
- Ошибки "Connection reset"
- Таймауты
Диагностика:
// Логирование закрытий
$server->onClose = function($conn) {
Server::log("Connection closed: " . $conn->getRemoteAddress());
Server::log("Status: " . $conn->status);
Server::log("Bytes read: " . $conn->bytesRead);
Server::log("Bytes written: " . $conn->bytesWritten);
};
Решения:
- Настройка Keep-Alive:
// Для HTTP
$response = new Response(200, [
'Connection' => 'keep-alive',
'Keep-Alive' => 'timeout=60'
]);
- Увеличение таймаутов:
# В sysctl.conf
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 60
net.ipv4.tcp_keepalive_probes = 3
- Heartbeat механизм:
$server->onConnect = function($conn) {
$conn->context->heartbeatTimer = Timer::repeat(30.0, function() use ($conn) {
if (!$conn->sendPing()) {
Timer::del($conn->context->heartbeatTimer);
$conn->close();
}
});
};
4. Низкая производительность
Симптомы:
- Медленная обработка запросов
- Высокая латентность
- Низкий throughput
Диагностика:
// Профилирование запросов
$server->onMessage = function($conn, $req) {
$start = microtime(true);
// Обработка...
$duration = microtime(true) - $start;
if ($duration > 0.1) {
Server::log("Slow request: {$duration}s - " . $req->path());
}
};
Решения:
- Использование оптимального Event Loop:
# Установка libuv
pecl install uv
# Проверка использования
php -r "echo get_event_loop_name();"
- Оптимизация количества процессов:
// Соответствие количеству CPU
$server->count = cpu_count();
- Оптимизация протоколов:
// Использование кеша запросов
// Минимизация парсинга
// Оптимизация encode/decode
5. Ошибки при перезагрузке
Симптомы:
- Ошибки при команде
reload - Потеря соединений при перезагрузке
- Не применяются изменения кода
Решения:
- Graceful reload:
# Плавная перезагрузка
php start.php reload -g
- Проверка reloadable:
// Убедитесь, что сервер можно перезагружать
$server->reloadable = true;
- Инициализация в onServerStart:
// Код, который должен выполняться при каждой перезагрузке
$server->onServerStart = function($server) {
// Инициализация соединений с БД
// Загрузка конфигурации
// Инициализация ресурсов
};
6. Проблемы с SSL/TLS
Симптомы:
- Ошибки рукопожатия
- Соединения не устанавливаются
- Ошибки сертификатов
Диагностика:
// Логирование SSL ошибок
$server->onError = function($conn, $code, $reason) {
if ($conn->transport === 'ssl') {
Server::log("SSL Error: $code - $reason");
}
};
Решения:
- Проверка сертификатов:
# Проверка сертификата
openssl x509 -in cert.pem -text -noout
# Проверка ключа
openssl rsa -in key.pem -check
- Настройка SSL контекста:
$context = [
'ssl' => [
'local_cert' => '/path/to/cert.pem',
'local_pk' => '/path/to/key.pem',
'verify_peer' => false, // Для разработки
'allow_self_signed' => true,
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER,
]
];
7. Проблемы с WebSocket
Симптомы:
- Соединения не устанавливаются
- Данные не передаются
- Соединения закрываются сразу
Диагностика:
// Логирование WebSocket событий
$server->onWebSocketConnect = function($conn, $req) {
Server::log("WebSocket connect from: " . $conn->getRemoteAddress());
Server::log("Origin: " . $req->header('origin'));
Server::log("Sec-WebSocket-Key: " . $req->header('sec-websocket-key'));
return null; // Принять соединение
};
Решения:
- Проверка Origin:
$server->onWebSocketConnect = function($conn, $req) {
$origin = $req->header('origin');
$allowedOrigins = ['https://example.com', 'https://app.example.com'];
if (!in_array($origin, $allowedOrigins)) {
Server::log("Rejected WebSocket from: $origin");
return new Response(403); // Отклонение
}
return null; // Принятие
};
- Проверка протокола:
// Убедитесь, что используется правильный протокол
$server = new Server('websocket://0.0.0.0:2000');
// НЕ 'http://' или 'tcp://'
Отладка производительности
Профилирование запросов
class RequestProfiler {
private static array $profiles = [];
public static function start(string $requestId): void {
self::$profiles[$requestId] = [
'start' => microtime(true),
'memory' => memory_get_usage(true),
'peak_memory' => memory_get_peak_usage(true)
];
}
public static function checkpoint(string $requestId, string $name): void {
if (!isset(self::$profiles[$requestId])) {
return;
}
$now = microtime(true);
$memory = memory_get_usage(true);
$timing = $now - self::$profiles[$requestId]['start'];
$memoryDelta = $memory - self::$profiles[$requestId]['memory'];
Server::log("[$requestId] $name: {$timing}s, memory: +{$memoryDelta}b");
}
public static function end(string $requestId): array {
if (!isset(self::$profiles[$requestId])) {
return [];
}
$profile = self::$profiles[$requestId];
$duration = microtime(true) - $profile['start'];
$memory = memory_get_usage(true) - $profile['memory'];
unset(self::$profiles[$requestId]);
return [
'duration' => $duration,
'memory' => $memory,
'peak_memory' => memory_get_peak_usage(true) - $profile['peak_memory']
];
}
}
// Использование
$server->onMessage = function($conn, $req) {
$requestId = uniqid();
RequestProfiler::start($requestId);
RequestProfiler::checkpoint($requestId, 'after_decode');
// Обработка...
$result = processRequest($req);
RequestProfiler::checkpoint($requestId, 'after_process');
$conn->send($result);
$stats = RequestProfiler::end($requestId);
if ($stats['duration'] > 1.0) {
Server::log("Slow request: {$stats['duration']}s");
}
};
Отслеживание соединений
class ConnectionTracker {
private static array $connections = [];
public static function track(TcpConnection $conn): void {
self::$connections[$conn->id] = [
'address' => $conn->getRemoteAddress(),
'connected_at' => microtime(true),
'bytes_read' => 0,
'bytes_written' => 0,
'requests' => 0
];
}
public static function update(TcpConnection $conn): void {
if (!isset(self::$connections[$conn->id])) {
return;
}
self::$connections[$conn->id]['bytes_read'] = $conn->bytesRead;
self::$connections[$conn->id]['bytes_written'] = $conn->bytesWritten;
self::$connections[$conn->id]['requests']++;
}
public static function untrack(TcpConnection $conn): void {
if (isset(self::$connections[$conn->id])) {
$stats = self::$connections[$conn->id];
$duration = microtime(true) - $stats['connected_at'];
Server::log(sprintf(
"Connection %d closed: duration=%.2fs, requests=%d, read=%d, written=%d",
$conn->id,
$duration,
$stats['requests'],
$stats['bytes_read'],
$stats['bytes_written']
));
unset(self::$connections[$conn->id]);
}
}
public static function getStats(): array {
return self::$connections;
}
}
// Использование
$server->onConnect = [ConnectionTracker::class, 'track'];
$server->onMessage = function($conn, $data) {
ConnectionTracker::update($conn);
// Обработка...
};
$server->onClose = [ConnectionTracker::class, 'untrack'];
Инструменты отладки
1. Встроенные команды
# Статус процессов
php start.php status
# Соединения
php start.php connections
# Перезагрузка с выводом отладочной информации
php start.php reload -d
2. Внешние инструменты
strace - отслеживание системных вызовов:
strace -p $(cat localzet.start.php.pid) -e trace=network
tcpdump - анализ сетевого трафика:
tcpdump -i any port 8080 -A
lsof - проверка открытых файлов:
lsof -p $(cat localzet.start.php.pid)
3. Мониторинг в реальном времени
// Endpoint для мониторинга
$server->onMessage = function($conn, $req) {
if ($req->path() === '/debug/stats') {
$stats = [
'connections' => count($conn->server->connections),
'memory' => memory_get_usage(true),
'peak_memory' => memory_get_peak_usage(true),
'global_stats' => ConnectionInterface::$statistics
];
$conn->send(json_encode($stats, JSON_PRETTY_PRINT));
}
};
Чеклист для диагностики
При проблемах с запуском
- PHP версия >= 8.1
- Расширения pcntl, posix, sockets установлены
- Функции не в disable_functions
- Порт не занят другим процессом
- Права на файлы корректны
- PID файл не заблокирован
При проблемах с производительностью
- Оптимальный Event Loop выбран
- Количество процессов соответствует CPU
- Буферы настроены правильно
- Нет блокирующих операций
- Операционная система оптимизирована
При проблемах с соединениями
- Keep-Alive настроен
- Heartbeat работает
- Таймауты установлены
- Rate limiting не слишком строгий
- Firewall не блокирует соединения
Получение помощи
Полезная информация для баг-репортов
При сообщении о проблеме укажите:
- Версию Localzet Server
- Версию PHP и расширения
- Операционную систему
- Вывод команды
status - Релевантные логи
- Шаги для воспроизведения
Логирование для отладки
// Включение подробного логирования
Server::$logFile = '/var/log/localzet-debug.log';
// Логирование всех событий
$server->onConnect = function($conn) {
Server::log("Connect: " . $conn->getRemoteAddress());
};
$server->onMessage = function($conn, $data) {
Server::log("Message from " . $conn->getRemoteAddress() . ": " . substr($data, 0, 100));
};
$server->onClose = function($conn) {
Server::log("Close: " . $conn->getRemoteAddress());
};
$server->onError = function($conn, $code, $reason) {
Server::log("Error on " . $conn->getRemoteAddress() . ": $code - $reason");
};

