TrueAsync Server

(PHP 8.6+, true_async_server 0.6+)

TrueAsync Server ist eine native PHP-Extension, die einen leistungsstarken HTTP-Server direkt innerhalb des PHP-Prozesses ausführt. Ohne separaten Daemon, ohne Reverse-Proxy, ohne FastCGI-Brücke.

Standardmäßig werden HTTP/1.1 und HTTP/2 auf demselben TCP-Port unterstützt. Die Protokollwahl erfolgt über ALPN-Negotiation (bei TLS) oder HTTP Upgrade. HTTP/3 läuft über denselben UDP-Port (QUIC) und wird Clients per Alt-Svc-Header angekündigt.

WebSocket, SSE und gRPC sind bereits für dasselbe Single-Listener-Modell mit Protokollerkennung entworfen, befinden sich aber noch in Arbeit (siehe 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();

Motivation

Ziel des Servers ist es, das Potenzial konkurrenter PHP-Anwendungen voll auszuschöpfen.

TrueAsync hat der Sprache echte Coroutinen, nicht-blockierendes I/O und Connection-Pools gegeben. Damit dieses Potenzial unter Produktionslast wirksam wird, braucht es einen Server, der von Grund auf für dieses Modell konzipiert ist: einen langlebigen Prozess mit Event-Loop, in dem jede Anfrage ihre eigene Coroutine bekommt und der Scheduler bei jedem I/O-Wait zwischen ihnen wechselt.

TrueAsync Server ist genau dieser Server. Keine Zwischenschicht zwischen Coroutinen und Netzwerk: Listener, Protokoll-Parser, Request-Dispatcher und Handler leben in einem Prozess und in einem Event-Loop. Datenbankverbindungen werden über Async\Pool wiederverwendet, Opcache bleibt zwischen Anfragen warm, der Cold-Start fällt einmal bei start() an.

Funktionen

StatusFunktionDetails
HTTP/1.1Vollständige RFC-9112-Konformität, Keep-Alive, Pipelining (über llhttp, derselbe Parser wie in Node.js)
HTTP/2Multiplexing, Server Push (libnghttp2 ≥ 1.57, Floor für CVE-2023-44487)
HTTP/3 / QUICUDP-Transport über libngtcp2 + libnghttp3, OpenSSL 3.5 QUIC TLS API
TLS 1.2 / 1.3OpenSSL 3.x, ALPN-Negotiation, schwache Cipher deaktiviert
Komprimierunggzip (zlib-ng / zlib), Brotli, zstd: für Responses und Decoding eingehender Bodies in allen Protokollen
Multipart / File UploadsStreaming-Zero-Copy-Parser
BackpressureCoDel (RFC 8289), adaptive Accept-Pausierung unter Last
Streaming Request BodyOptional über HttpRequest::readBody(); Uploads ohne Body im RAM zu halten
sendFileEffiziente Auslieferung von Dateien direkt aus dem Handler
Built-in Worker PoolsetWorkers(N): N Threads über Async\ThreadPool + SO_REUSEPORT
Per-Request ScopeJeder Handler in eigenem Scope; Async\request_context() liefert gemeinsamen Kontext für den gesamten Coroutine-Baum der Anfrage
Native CoroutinenTiefe Integration mit TrueAsync: jedes blockierende I/O im Handler suspendiert die Coroutine, nicht den Thread
Zero-CopyMinimale Allokationen auf dem Hot Path
📋WebSocketRFC 6455, Upgrade von HTTP/1.1 und HTTP/2
📋SSEServer-Sent Events
📋gRPCüber HTTP/2, unary und streaming

Architektur: Single-Threaded Event Loop

Dasselbe Modell wie bei NGINX, Envoy, Node.js und Rust Tokio/hyper.

Ein Thread besitzt sowohl die Verbindung als auch die Anfrage von accept bis send. Keine Übergabe zwischen Accept-Thread und Worker-Thread, keine Locks, keine Kontextwechsel zwischen ihnen. Ein Event-Loop akzeptiert die Verbindung, liest Bytes aus dem Socket, parst HTTP, dispatcht die Anfrage zum Handler und schreibt die Antwort, ohne den Thread zu verlassen.

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

Nicht-blockierendes I/O übernimmt der libuv-Reactor (über TrueAsync). Wenn eine Coroutine auf eine Datei, eine DB oder den nächsten WebSocket-Frame warten muss, übergibt sie die Kontrolle an den Event-Loop, der sofort das nächste fertige Event aufnimmt. Der Thread bleibt nie in read()/recv() stehen.

Für Skalierung über CPU-Kerne hinweg wird Multi-Worker über setWorkers(N) aktiviert: Der integrierte Async\ThreadPool startet N OS-Threads, jeder mit eigenem unabhängigem Event-Loop, und SO_REUSEPORT (Linux/BSD) sorgt dafür, dass der Kernel eingehende Verbindungen verteilt. Kein Shared State, keine globalen Locks.

Einstieg

API-Referenz

Alternativen

FrankenPHP ist ein eigenständiger einbettbarer Server auf Basis von Caddy/Go, in dem PHP als Worker fungiert. Praktisch, wenn man Caddy-Features (automatisches Let's Encrypt, Konfiguration über Caddyfile) oder die Integration in eine bestehende Caddy-Infrastruktur benötigt. TrueAsync Server ist die native Alternative ohne Go-Runtime: Der Server lebt direkt im PHP-Prozess.