TrueAsync Server

(PHP 8.6+, true_async_server 0.6+)

TrueAsync Server — нативное PHP-расширение, которое запускает производительный HTTP-сервер прямо внутри PHP-процесса. Без отдельного daemon, без reverse-proxy, без FastCGI-моста.

Из коробки поддерживает HTTP/1.1 и HTTP/2 на одном TCP-порту. Выбор протокола происходит через ALPN-negotiation (для TLS) или HTTP Upgrade. HTTP/3 работает на том же UDP-порту (QUIC) и анонсируется клиентам через заголовок Alt-Svc.

WebSocket, SSE и gRPC уже спроектированы под ту же модель одного listener'а с детектом протокола, но пока ещё в работе (см. Roadmap).

php
use TrueAsync\HttpServer;
use TrueAsync\HttpServerConfig;

$server = new HttpServer(
    (new HttpServerConfig())
        ->addListener('0.0.0.0', 8080)
        ->setWorkers(4)
);

$server->addHttpHandler(function ($request, $response) {
    $response->setStatusCode(200)->setBody('Hello, World!');
});

$server->start();

Зачем

Цель сервера — раскрыть потенциал конкурентных приложений на PHP.

TrueAsync дал языку настоящие корутины, неблокирующий I/O и пулы соединений. Чтобы этот потенциал реализовался в production-нагрузке, нужен сервер, который изначально спроектирован под эту модель: долгоживущий процесс с event-loop'ом, где каждый запрос получает свою корутину, а планировщик переключается между ними на каждом I/O-ожидании.

TrueAsync Server и есть такой сервер. Никакой прослойки между корутинами и сетью: listener, парсер протокола, диспетчер запросов и обработчик живут в одном процессе и в одном event-loop'е. Соединения с БД переиспользуются через Async\Pool, opcache горячий между запросами, cold-start платится один раз, при start().

Возможности

СтатусВозможностьДетали
HTTP/1.1Полное соответствие RFC 9112, keep-alive, pipelining (через llhttp, тот же парсер, что у Node.js)
HTTP/2Мультиплексирование, server push (libnghttp2 ≥ 1.57, floor для CVE-2023-44487)
HTTP/3 / QUICUDP-транспорт на libngtcp2 + libnghttp3, OpenSSL 3.5 QUIC TLS API
TLS 1.2 / 1.3OpenSSL 3.x, ALPN negotiation, отключены слабые шифры
Компрессияgzip (zlib-ng / zlib), Brotli, zstd: на ответ и декодинг входящих тел во всех протоколах
Multipart / file uploadsStreaming zero-copy парсер
BackpressureCoDel (RFC 8289), адаптивная приостановка accept под нагрузкой
Streaming request bodyОпционально через HttpRequest::readBody(); uploads без удержания тела в RAM
sendFileЭффективная отдача файлов с диска прямо из обработчика
Built-in worker poolsetWorkers(N): N потоков через Async\ThreadPool + SO_REUSEPORT
Per-request scopeКаждый обработчик в своём scope; Async\request_context() даёт общий контекст по всему дереву корутин запроса
Native coroutinesГлубокая интеграция с TrueAsync: любой блокирующий I/O в обработчике приостанавливает корутину, а не поток
Zero-copyМинимум аллокаций на горячем пути
📋WebSocketRFC 6455, Upgrade с HTTP/1.1 и HTTP/2
📋SSEServer-Sent Events
📋gRPCповерх HTTP/2, unary и streaming

Архитектура: single-threaded event loop

Та же модель, что у NGINX, Envoy, Node.js и Rust Tokio/hyper.

Один поток владеет и соединением, и запросом от accept до send. Нет передачи между accept-thread и worker-thread, нет блокировок, нет переключений контекста между ними. Один event-loop принимает соединение, читает байты из сокета, парсит HTTP, диспетчеризует запрос в обработчик и пишет ответ, не покидая поток.

       ┌─────────────────────────────────────────┐
       │              Event Loop Thread          │
       │                                         │
accept ─►  parse  ─►  dispatch  ─►  respond      │
       │     ▲                        │          │
       │     └──── coroutine yield ◄──┘          │
       └─────────────────────────────────────────┘

Неблокирующий I/O делает libuv-реактор (через TrueAsync). Когда корутине нужно подождать файл, БД или следующий WebSocket-кадр, она передаёт управление event-loop, который сразу подбирает следующее готовое событие. Поток никогда не простаивает в read()/recv().

Для масштабирования по ядрам поднимается multi-worker через setWorkers(N): встроенный Async\ThreadPool поднимает N OS-потоков, каждый с собственным независимым event-loop, и SO_REUSEPORT (Linux/BSD) даёт ядру распределять входящие соединения по ним. Никакого shared state, никаких глобальных блокировок.

Где начинать

Справочник API

Альтернативы

FrankenPHP — отдельный встраиваемый сервер на Caddy/Go, в котором PHP выступает воркером. Удобен, когда нужны Caddy-фичи (автоматический Let's Encrypt, конфиг через Caddyfile) или интеграция в существующую Caddy-инфраструктуру. TrueAsync Server — нативная альтернатива без Go-runtime: сервер живёт прямо в процессе PHP.