PHP 7.4 → 8.5 · Linux · aaPanel · DirectAdmin

Make PHP apps faster, with proof.Tăng tốc ứng dụng PHP, có số liệu chứng minh.

QHturbo builds PHP from the official source, installs it beside your existing PHP (never over it) and gives you two ways to run your code: a drop-in PHP-FPM, or long-lived workers with async I/O that run Laravel and Symfony unchanged at 6–15× the requests per second.

QHturbo build PHP từ mã nguồn chính thức, cài song song với PHP hiện có (không bao giờ ghi đè) và cho bạn hai cách chạy mã: PHP-FPM thay thế trực tiếp, hoặc worker chạy lâu dài với I/O bất đồng bộ, chạy Laravel và Symfony không cần sửa code, nhanh gấp 6–15 lần số request/giây.

14.6×Laravel 13 health route vs PHP-FPMRoute health Laravel 13 so với PHP-FPM
6.3×Symfony 8.1 JSON routeRoute JSON Symfony 8.1
1.7×async MySQL vs 64 FPM childrenMySQL bất đồng bộ so với 64 tiến trình FPM
0code changes in Compatible modedòng code phải sửa ở chế độ Compatible

What is QHturbo?QHturbo là gì?

QHturbo is a PHP distribution and runtime toolkit. Every speed claim in the project comes with a reproducible benchmark; experiments that did not help are recorded as NO-GO instead of hidden. It has three parts:

QHturbo là một bản phân phối PHP kèm bộ công cụ runtime. Mọi con số về tốc độ trong dự án đều đi kèm benchmark có thể chạy lại; các thử nghiệm không hiệu quả được ghi là NO-GO chứ không bị giấu đi. Dự án gồm ba phần:

Build systemHệ thống build

Builds PHP 7.4–8.5 from pinned, hash-verified php-src tags into /opt/qhturbo/<version>, side by side with the system PHP.

Build PHP 7.4–8.5 từ các tag php-src đã ghim và kiểm tra hash, cài vào /opt/qhturbo/<phiên-bản>, chạy song song với PHP của hệ thống.

Two run modesHai chế độ chạy

Compatible (tuned PHP-FPM, no code changes) and Performance (long-lived workers, event loop, async Redis/MySQL).

Compatible (PHP-FPM đã tinh chỉnh, không sửa code) và Performance (worker chạy lâu dài, event loop, Redis/MySQL bất đồng bộ).

Panels and toolingPanel và công cụ

aaPanel and DirectAdmin integration with per-site switching and automatic rollback, plus qht-doctor, fpm-tune and bench.py.

Tích hợp aaPanel và DirectAdmin, chuyển từng site một và tự động rollback, kèm qht-doctor, fpm-tune và bench.py.

Status (2026-10-22): the PHP binary itself is not faster than upstream yet (PGO was tried twice and rejected, and there are no Zend Engine patches yet). Today's speed-ups come from how PHP runs (workers, async I/O) and from configuration.

Trạng thái (22/10/2026): bản thân file thực thi PHP chưa nhanh hơn bản gốc (PGO đã thử hai lần và bị loại, chưa có bản vá Zend Engine). Tốc độ tăng hiện nay đến từ cách PHP chạy (worker, I/O bất đồng bộ) và từ cấu hình.

Key featuresTính năng chính

Pinned PHP buildsBuild PHP được ghim phiên bản

PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5 from upstream tags verified against their commit hash. Profiles minimal and full (PHP-FPM + 51 modules). Each binary ships a BUILD-INFO.txt with sha256, flags and patch list.

PHP 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5 từ tag gốc, đối chiếu với hash commit. Hai profile minimal và full (PHP-FPM + 51 module). Mỗi bản build có file BUILD-INFO.txt ghi sha256, cờ biên dịch và danh sách bản vá.

Side-by-side installCài song song

Installs to /opt/qhturbo/<version> with its own socket and systemd unit. install.sh refuses /usr, /etc and /www/server/php. PHP 7.4/8.0 link a private OpenSSL 1.1.1 on OpenSSL 3 distros.

Cài vào /opt/qhturbo/<phiên-bản> với socket và unit systemd riêng. install.sh từ chối cài vào /usr, /etc và /www/server/php. PHP 7.4/8.0 dùng OpenSSL 1.1.1 riêng trên các distro dùng OpenSSL 3.

Long-lived workersWorker chạy lâu dài

The app boots once per process. A supervisor forks workers, recycles them after N requests or a memory limit, reloads with zero downtime on SIGHUP, and backs off on crash loops.

Ứng dụng chỉ khởi động một lần cho mỗi tiến trình. Supervisor fork các worker, thay mới sau N request hoặc khi vượt giới hạn RAM, reload không gián đoạn bằng SIGHUP và tự giãn thời gian khi worker crash liên tục.

Event loop + FibersEvent loop + Fiber

async(), await(), all(), delay(), timeout(), non-blocking TCP and an HTTP client. Pure PHP 8.1+, no extension required.

async(), await(), all(), delay(), timeout(), TCP không chặn và HTTP client. Viết thuần PHP 8.1+, không cần extension.

Async Redis and MySQLRedis và MySQL bất đồng bộ

RESP2 Redis client with pipelining; mysqlnd async MySQL/MariaDB with ? placeholders (including IN (?)), transactions and timeouts. Bounded pool per worker.

Redis client RESP2 có pipeline; MySQL/MariaDB bất đồng bộ qua mysqlnd, hỗ trợ tham số ? (kể cả IN (?)), transaction và timeout. Pool kết nối có giới hạn cho mỗi worker.

State guardBảo vệ trạng thái

Per-request isolation: reset hooks, removal of leaked globals, restore of changed ini settings and output buffers, detection of growing statics and memory, --strict-state for staging.

Cô lập từng request: hook reset, xoá biến global bị rò, khôi phục ini và output buffer, phát hiện static property và bộ nhớ tăng dần, chế độ --strict-state cho staging.

Laravel and SymfonyLaravel và Symfony

--framework=laravel|symfony runs an existing project unchanged. Guards, sessions, cookies, scoped instances, transactions, config and locale are reset after every request.

--framework=laravel|symfony chạy dự án có sẵn mà không sửa code. Guard, session, cookie, scoped instance, transaction, config và locale được reset sau mỗi request.

Panel integrationTích hợp panel

aaPanel and DirectAdmin: switch one site at a time, automatic rollback if the web server config test fails or the site returns 5xx, disable_functions copied from the panel's php.ini.

aaPanel và DirectAdmin: chuyển từng site một, tự rollback nếu kiểm tra cấu hình web server lỗi hoặc site trả về 5xx, sao chép disable_functions từ php.ini của panel.

Diagnostics and benchmarksChẩn đoán và benchmark

qht-doctor checks an install and scans code for worker-mode risks; fpm-tune sizes pm.max_children; bench.py runs interleaved benchmarks with A/A control and 95% CI.

qht-doctor kiểm tra bản cài và quét code tìm rủi ro khi chạy worker; fpm-tune tính pm.max_children; bench.py chạy benchmark xen kẽ có đối chứng A/A và khoảng tin cậy 95%.

Two run modesHai chế độ chạy

Pick per site. Compatible is the safe default for everything; Performance is for APIs and apps that follow the state rules.

Chọn theo từng site. Compatible là lựa chọn an toàn mặc định cho mọi thứ; Performance dành cho API và ứng dụng tuân thủ quy tắc quản lý trạng thái.

CompatiblePerformance
ForDùng choAny site: WordPress, Laravel, legacy code, aaPanelMọi site: WordPress, Laravel, code cũ, aaPanelAPIs and new apps that need high throughputAPI và ứng dụng mới cần thông lượng cao
How it runsCách chạynginx/Apache → PHP-FPMnginx → qhturbo-serve (workers, event loop, async I/O)nginx → qhturbo-serve (worker, event loop, I/O bất đồng bộ)
PHP7.4 → 8.58.1 → 8.5 (Fiber)
Code changesSửa codeNoneKhôngFollow the state rulesTuân thủ quy tắc trạng thái
Laravel 13288–353 req/s1,924–5,150 req/s
Symfony 8.11,737 req/s11,160 req/s
3 × 20 ms MySQL queries3 truy vấn MySQL × 20 ms1,011 req/s (64 FPM children)1,011 req/s (64 tiến trình FPM)1,724 req/s (async MySQL)1,724 req/s (MySQL bất đồng bộ)

Compatible: what changesCompatible: khác gì PHP-FPM thường

  • OPcache on: 256 MB, 50,000 files, 32 MB interned stringsBật OPcache: 256 MB, 50.000 file, 32 MB interned strings
  • validate_timestamps=1 kept (checked every 2 s), so FTP edits and WordPress updates still applyGiữ validate_timestamps=1 (kiểm tra mỗi 2 giây), nên sửa file qua FTP hay cập nhật WordPress vẫn có hiệu lực
  • JIT off until you measureTắt JIT cho tới khi bạn đo đạc
  • realpath_cache 4M/600s, pm.max_requests=1000, slowlog, status/ping pagesrealpath_cache 4M/600s, pm.max_requests=1000, slowlog, trang status/ping

Performance: what you getPerformance: bạn nhận được gì

  • No per-request framework boot: the biggest winKhông khởi động lại framework mỗi request: lợi ích lớn nhất
  • Parallel I/O inside one request with async()/all()I/O song song trong một request với async()/all()
  • Zero-downtime deploys with kill -HUP; a broken deploy is aborted and old workers keep servingDeploy không gián đoạn bằng kill -HUP; nếu code mới lỗi, reload bị huỷ và worker cũ vẫn phục vụ
  • Not for WordPress or code that uses exit() for control flowKhông dùng cho WordPress hoặc code dùng exit() để điều khiển luồng

Requirements and versionsYêu cầu và phiên bản

Linux (Debian/Ubuntu with apt, RHEL family with dnf), or Windows through WSL2. Building takes 10–40 minutes per PHP version. Performance mode needs PHP 8.1+, plus pcntl/posix for multiple workers and mysqli for the MySQL client.

Linux (Debian/Ubuntu dùng apt, dòng RHEL dùng dnf), hoặc Windows qua WSL2. Mỗi phiên bản PHP build mất 10–40 phút. Chế độ Performance cần PHP 8.1+, thêm pcntl/posix để chạy nhiều worker và mysqli cho MySQL client.

BranchNhánhUpstream tagTag gốcUpstream supportHỗ trợ từ PHPJITPerformance
7.4php-7.4.33⚠️ end of life⚠️ hết hỗ trợnokhôngnokhông
8.0php-8.0.30⚠️ end of life⚠️ hết hỗ trợyescónokhông
8.1php-8.1.34⚠️ end of life⚠️ hết hỗ trợyescóyescó
8.2php-8.2.35security fixes onlychỉ vá bảo mậtyescóyescó
8.3php-8.3.36security fixes onlychỉ vá bảo mậtyescóyescó
8.4php-8.4.27activeđang hỗ trợyescóyescó
8.5php-8.5.12activeđang hỗ trợyescóyescó

InstallationCài đặt

Choose the path that matches your server. Every path installs beside the PHP you already have; nothing is overwritten and every switch can be undone.

Chọn cách phù hợp với máy chủ của bạn. Mọi cách đều cài song song với PHP hiện có; không ghi đè gì cả và mọi thao tác chuyển đổi đều có thể hoàn tác.

Take a server snapshot first, and try one test site before production.

Hãy chụp snapshot máy chủ trước, và thử trên một site test trước khi áp dụng cho production.

Compatible mode, one site at a time. enable backs up the vhost, switches it to the QHturbo socket, runs nginx -t and checks the site over HTTP; if the test fails or the site returns 5xx it rolls back on its own. It also copies disable_functions and limits from aaPanel's php.ini.

Chế độ Compatible, từng site một. enable sao lưu vhost, chuyển sang socket của QHturbo, chạy nginx -t và kiểm tra site qua HTTP; nếu kiểm tra lỗi hoặc site trả 5xx thì tự động rollback. Lệnh cũng sao chép disable_functions và các giới hạn từ php.ini của aaPanel.

aaPanel · SSH
git clone https://github.com/qhsvn/QHTurbo.git /opt/qhturbo-src && cd /opt/qhturbo-src
sudo scripts/aapanel.sh check   --php=8.5                    # inspect only, changes nothing
sudo scripts/aapanel.sh install --php=8.5                    # build + install + start PHP-FPM (10-40 min)
sudo scripts/aapanel.sh enable  test.example.com --php=8.5   # switch one site; auto-rollback on errors
sudo scripts/aapanel.sh status                               # which sites use QHturbo
sudo scripts/aapanel.sh disable test.example.com             # back to aaPanel's PHP

Prefer a UI? Download qhturbo-aapanel.zip, then in aaPanel open App Store → Import and upload it. The plugin lists PHP versions and sites, switches a site in one click and streams the task log.

Muốn dùng giao diện? Tải qhturbo-aapanel.zip, vào aaPanel mở App Store → Import và tải file lên. Plugin liệt kê phiên bản PHP và các site, chuyển site bằng một cú nhấp và hiển thị log tác vụ trực tiếp.

UsageHướng dẫn sử dụng

Compatible modeChế độ Compatible

Nothing to learn: after installing, the site runs on QHturbo's PHP-FPM exactly as before. Useful day-to-day commands:

Không cần học gì thêm: sau khi cài, site chạy trên PHP-FPM của QHturbo y như trước. Một số lệnh hay dùng:

bash
/opt/qhturbo/8.5/bin/php -v                                          # the QHturbo PHP binary
sudo systemctl status qhturbo-php85-fpm                              # FPM service
sudo /opt/qhturbo/8.5/sbin/php-fpm -t                                # test FPM config
python3 scripts/fpm-tune.py                                          # suggest pm.max_children
sudo scripts/install-ext.sh redis --php=8.5                          # add a PECL extension
/opt/qhturbo/8.5/bin/php /opt/qhturbo/8.5/share/qhturbo/qht-doctor.php   # health check

Performance mode: your first worker appChế độ Performance: ứng dụng worker đầu tiên

A Performance app is a PHP file that returns a closure. Code above the return runs once when the worker boots; the closure runs for every request and returns a Response, an array (sent as JSON) or a string (sent as HTML).

Ứng dụng Performance là một file PHP trả về một closure. Phần code phía trên return chạy một lần khi worker khởi động; closure chạy cho mỗi request và trả về Response, mảng (gửi dạng JSON) hoặc chuỗi (gửi dạng HTML).

app.php
<?php // app.php: this part runs ONCE per worker
use QHTurbo\Runtime\Http\{Request, Response};

$config = require __DIR__ . '/config.php';           // booted once, reused

return function (Request $request) use ($config): Response|array|string {
    // this part runs for EACH request; request state lives in $request
    if ($request->path() === '/health') {
        return Response::text("ok\n");
    }
    return ['path' => $request->path(), 'env' => $config['env']];   // array -> JSON
};
qhturbo-serve
# development
php runtime/bin/qhturbo-serve app.php --port=8080 --strict-state --debug
# production: 1 worker per CPU, respawn after 10,000 requests or 256 MiB
qhturbo-serve app.php --workers=4 --concurrency=1 --max-requests=10000 --memory-limit=256M
# zero-downtime deploy: replace workers one by one
kill -HUP <master-pid>

If the returned object implements ResetInterface, its reset() is called after every request. On SIGHUP, OPcache is invalidated for loaded files, new workers boot first, and old ones stop only after that, with up to 60 s to finish in-flight requests. If the new code fails to boot, the log says reload aborted and the old workers keep serving.

Nếu đối tượng được trả về implement ResetInterface, hàm reset() của nó được gọi sau mỗi request. Khi nhận SIGHUP, OPcache của các file đã nạp bị vô hiệu, worker mới khởi động trước và worker cũ chỉ dừng sau đó, có tối đa 60 giây để xử lý nốt request đang chạy. Nếu code mới khởi động lỗi, log ghi reload aborted và worker cũ tiếp tục phục vụ.

Laravel and SymfonyLaravel và Symfony

Point qhturbo-serve at the project directory. No code changes are needed (tested on Laravel 13 and Symfony 8.1, written for Laravel 9+ and Symfony 5.4+).

Trỏ qhturbo-serve vào thư mục dự án. Không cần sửa code (đã kiểm thử trên Laravel 13 và Symfony 8.1, viết cho Laravel 9+ và Symfony 5.4+).

Laravel / Symfony
qhturbo-serve /var/www/laravel --framework=laravel --workers=4 --max-requests=5000
qhturbo-serve /var/www/symfony --framework=symfony --workers=4
Laravel stateTrạng thái LaravelHandled after every requestXử lý sau mỗi request
Authenticated userNgười dùng đã đăng nhậpforgetGuards()
Sessionflush() + regenerate() on the shared storeflush() + regenerate() trên store dùng chung
Queued cookiesCookie trong hàng đợiflushQueuedCookies()
Open DB transactionTransaction DB còn mởrolled back and loggedrollback và ghi log
Runtime config, localeConfig lúc chạy, localerestoredkhôi phục
Scoped instances, view sections, log context, Str cache, query logScoped instance, view section, log context, Str cache, query logclearedxoá

Use file or redis for SESSION_DRIVER and CACHE_STORE, never array (it lives in worker RAM and grows forever). Run php artisan optimize or cache:warmup, and configure trusted proxies since requests come from nginx. Symfony resets services tagged kernel.reset.

Dùng file hoặc redis cho SESSION_DRIVER và CACHE_STORE, không dùng array (dữ liệu nằm trong RAM của worker và tăng mãi). Chạy php artisan optimize hoặc cache:warmup, và cấu hình trusted proxies vì request đi qua nginx. Symfony tự reset các service gắn tag kernel.reset.

Behind nginx and systemdChạy sau nginx và systemd

nginx handles TLS, HTTP/2, static files and compression; qhturbo-serve speaks plain HTTP/1.1 on localhost. install.sh installs the unit qhturbo-php85-worker@<name>.service configured by /etc/qhturbo/worker-<name>.env.

nginx đảm nhận TLS, HTTP/2, file tĩnh và nén; qhturbo-serve chỉ nói HTTP/1.1 trên localhost. install.sh cài unit qhturbo-php85-worker@<tên>.service, cấu hình qua /etc/qhturbo/worker-<tên>.env.

nginx → qhturbo-serve
upstream app { server 127.0.0.1:8080; keepalive 64; }
server {
    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://app;
    }
}

qhturbo-serve optionsTuỳ chọn của qhturbo-serve

OptionTuỳ chọnDefaultMặc địnhMeaningÝ nghĩa
--host=ADDR127.0.0.1Address to listen onĐịa chỉ lắng nghe
--port=N8080TCP portCổng TCP
--workers=N0Number of processes. 0 = one process, no pcntl needed, no automatic respawnSố tiến trình. 0 = một tiến trình, không cần pcntl, không tự khởi động lại
--concurrency=C1Requests interleaved inside one worker. 1 is safe for any codeSố request xen kẽ trong một worker. 1 là an toàn cho mọi code
--max-requests=N10000Respawn a worker after N requests (contains slow leaks)Thay worker sau N request (chặn rò rỉ chậm)
--memory-limit=SIZE256MRespawn a worker when its RAM exceeds the limitThay worker khi RAM vượt ngưỡng
--superglobalsoffFill $_GET/$_POST/$_COOKIE/$_SERVER for legacy code (requires concurrency 1)Điền $_GET/$_POST/$_COOKIE/$_SERVER cho code cũ (cần concurrency 1)
--strict-stateoffState rule violations return 500 and are logged (dev/staging)Vi phạm quy tắc trạng thái trả về 500 và ghi log (dev/staging)
--state-check-every=N100Check static properties and RAM every N requests (1 with --strict-state)Kiểm tra static property và RAM mỗi N request (bằng 1 khi có --strict-state)
--framework=NAME—laravel or symfony: run a project directory (requires concurrency 1)laravel hoặc symfony: chạy thư mục dự án (cần concurrency 1)
--max-body=SIZE8MMaximum request size including uploads (512K, 8M, 1G)Kích thước request tối đa, kể cả upload (512K, 8M, 1G)
--max-connections=N512Open connections per worker (max 1000, a stream_select limit)Số kết nối mở mỗi worker (tối đa 1000, giới hạn của stream_select)
--debugoffVerbose logging and error detailsGhi log chi tiết và hiện chi tiết lỗi

State rules for Performance modeQuy tắc trạng thái cho chế độ Performance

In PHP-FPM everything disappears when a request ends. In a worker, whatever survives a request leaks into the next one, possibly another user's. These rules are mandatory:

Với PHP-FPM, mọi thứ tự biến mất khi request kết thúc. Với worker, bất cứ thứ gì còn sót lại sẽ rò sang request kế tiếp, có thể là của người dùng khác. Các quy tắc sau là bắt buộc:

#RuleQuy tắcRuntime supportRuntime hỗ trợ
R1Do not keep request data in globals, static properties or static variables. Put it on the Request or a fresh object.Không lưu dữ liệu request trong biến global, static property hay biến static. Đặt nó trong Request hoặc một object tạo mới mỗi request.New globals are deleted and logged; growing statics trigger a warningBiến global mới bị xoá và ghi log; static tăng dần sẽ bị cảnh báo
R2Services holding per-request state implement ResetInterface.Service giữ trạng thái theo request phải implement ResetInterface.reset() is called after every requestreset() được gọi sau mỗi request
R3No exit()/die(): return a Response.Không dùng exit()/die(): hãy trả về Response.The worker is restarted, but the in-flight request failsWorker được khởi động lại, nhưng request đang xử lý bị lỗi
R4No header(), setcookie() or echo for output: set them on the Response.Không dùng header(), setcookie() hay echo để trả kết quả: đặt chúng trên Response.qht-doctor --scan lists themqht-doctor --scan liệt kê các chỗ cần sửa
R5Do not change ini_set, timezone or locale per request.Không đổi ini_set, múi giờ hay locale theo từng request.Changed ini settings are restoredIni bị đổi sẽ được khôi phục
R6Close the output buffers you open.Đóng các output buffer bạn đã mở.Leftover buffers are cleaned and loggedBuffer còn sót được dọn và ghi log
R7Open DB/Redis connections once, handle reconnects, never leave a transaction open.Mở kết nối DB/Redis một lần, xử lý kết nối lại, không bao giờ để transaction mở sang request sau.Runtime clients pool connections and roll back open transactionsClient của runtime dùng pool và tự rollback transaction còn mở
R8With --concurrency > 1: no superglobals, and no blocking calls (PDO, sleep, file_get_contents on a URL); use async I/O only.Khi --concurrency > 1: không dùng superglobal và không gọi hàm chặn (PDO, sleep, file_get_contents với URL); chỉ dùng I/O bất đồng bộ.--superglobals is rejected--superglobals bị từ chối
R9Do not register handlers per request (set_error_handler, register_shutdown_function).Không đăng ký handler theo từng request (set_error_handler, register_shutdown_function).qht-doctor --scan warnsqht-doctor --scan cảnh báo

Migration pathLộ trình chuyển đổi

  1. php qht-doctor.php --scan=/var/www/app lists R1–R9 violations (vendor/ is skipped).php qht-doctor.php --scan=/var/www/app liệt kê vi phạm R1–R9 (bỏ qua vendor/).
  2. Run staging with --concurrency=1 --superglobals --strict-state: violations show up as 500 errors with a log line.Chạy staging với --concurrency=1 --superglobals --strict-state: vi phạm hiện thành lỗi 500 kèm dòng log.
  3. Fix them, turn off --superglobals and read input from Request.Sửa hết, tắt --superglobals và đọc dữ liệu từ Request.
  4. Raise --concurrency only once all I/O is async.Chỉ tăng --concurrency khi toàn bộ I/O đã bất đồng bộ.
  5. Go to production with a canary share of traffic, keeping Compatible (FPM) as the fallback.Đưa lên production với một phần lưu lượng (canary), giữ Compatible (FPM) làm phương án dự phòng.

API reference (runtime)Tài liệu hàm (runtime)

All classes live under the namespace QHTurbo\Runtime. Load them with Composer (qhturbo/runtime) or with runtime/src/autoload.php. They need PHP 8.1+ and no extension except mysqli for MySQL.

Mọi class nằm trong namespace QHTurbo\Runtime. Nạp bằng Composer (qhturbo/runtime) hoặc bằng runtime/src/autoload.php. Cần PHP 8.1+ và không cần extension nào ngoài mysqli cho MySQL.

Async functions · AsyncHàm bất đồng bộ · Async

Import with use function QHTurbo\Runtime\Async\{async, await, all, delay, timeout};. Outside a fiber (FPM, CLI) the same calls simply block.

Import bằng use function QHTurbo\Runtime\Async\{async, await, all, delay, timeout};. Ngoài fiber (FPM, CLI) các lời gọi này đơn giản là chạy chặn.

async(callable $fn, mixed ...$args): Future
Runs $fn in a new Fiber and returns a Future right away. Inside it, await(), delay(), read() and write() suspend only that fiber, so other requests keep running.Chạy $fn trong một Fiber mới và trả về Future ngay lập tức. Bên trong, await(), delay(), read(), write() chỉ tạm dừng fiber đó, các request khác vẫn tiếp tục chạy.
await(Future $future): mixed
Waits for a future and returns its value (or throws its error). In a fiber it suspends the fiber; outside any fiber it drives the event loop until the future completes.Chờ một future và trả về giá trị (hoặc ném lỗi của nó). Trong fiber thì tạm dừng fiber; ngoài fiber thì chạy event loop cho tới khi future hoàn tất.
all(array $futures): array
Awaits several futures that already run concurrently; keys are preserved. Total time is the slowest one, not the sum.Chờ nhiều future đang chạy đồng thời; giữ nguyên key của mảng. Tổng thời gian bằng future chậm nhất, không phải tổng cộng.
delay(float $seconds): void
Non-blocking sleep: the worker serves other requests meanwhile.Ngủ không chặn: trong lúc đó worker vẫn phục vụ request khác.
timeout(Future $future, float $seconds): Future
Returns a future that fails with TimeoutException if $future is not done in time.Trả về future sẽ lỗi với TimeoutException nếu $future không xong đúng hạn.
connect(string $uri, float $timeoutSeconds = 10.0): resource
Opens a non-blocking TCP stream, e.g. tcp://10.0.0.5:9000.Mở stream TCP không chặn, ví dụ tcp://10.0.0.5:9000.
read($stream, int $length = 65536, ?float $timeoutSeconds = null): string
Reads up to $length bytes once the stream is readable; returns '' at end of stream.Đọc tối đa $length byte khi stream sẵn sàng; trả về '' khi hết stream.
write($stream, string $data, ?float $timeoutSeconds = null): void
Writes all of $data, suspending while the socket buffer is full.Ghi toàn bộ $data, tạm dừng khi bộ đệm socket đầy.
readable($stream, ?float $t = null) / writable($stream, ?float $t = null): void
Suspends until the stream can be read from / written to.Tạm dừng cho tới khi stream có thể đọc / ghi.
async.php
use QHTurbo\Runtime\Http\{Request, Client};
use function QHTurbo\Runtime\Async\{async, all, timeout, await, delay};

return function (Request $r): array {
    // 3 backend calls in parallel: ~20 ms total instead of ~60 ms
    [$a, $b, $c] = all([
        async(fn () => Client::get('http://stats.internal/a')['body']),
        async(fn () => Client::get('http://stats.internal/b')['body']),
        async(fn () => Client::get('http://stats.internal/c')['body']),
    ]);
    // give up after 0.5 s
    $slow = await(timeout(async(fn () => Client::get('http://slow.internal/')), 0.5));
    return compact('a', 'b', 'c') + ['slow' => $slow['status']];
};

Future · Async\FutureFuture · Async\Future

Future::resolved(mixed $value = null): Future
A future that is already done.Future đã hoàn tất sẵn.
resolve(mixed $value) · fail(Throwable $e)
Completes the future with a value or an error.Hoàn tất future với một giá trị hoặc một lỗi.
isDone(): bool · result(): mixed · await(): mixed
State check, result of a done future, or await($this).Kiểm tra trạng thái, lấy kết quả của future đã xong, hoặc await($this).
onDone(callable $cb): void
Callback fn(?Throwable $error, mixed $value) when the future completes.Callback fn(?Throwable $error, mixed $value) khi future hoàn tất.

Event loop · EventLoop\LoopEvent loop · EventLoop\Loop

Loop::get(): Loop · Loop::reset(): void
The worker's shared loop (a singleton); reset() is for tests.Event loop dùng chung của worker (singleton); reset() dùng cho test.
defer(callable $cb): void
Runs a callback on the next loop tick.Chạy callback ở vòng lặp kế tiếp.
delay(float $s, callable $cb): string · repeat(float $interval, callable $cb): string
One-shot or repeating timer; returns a watcher id.Hẹn giờ một lần hoặc lặp lại; trả về id watcher.
onReadable($stream, callable $cb): string · onWritable($stream, callable $cb): string
Watches a stream with stream_select.Theo dõi stream bằng stream_select.
cancel(string $id): void
Removes a timer or stream watcher.Huỷ timer hoặc watcher của stream.
run() · runUntil(callable $done) · stop() · isRunning(): bool · stats(): array
Drive the loop and inspect it.Chạy event loop và xem thông tin của nó.

Request · Http\RequestRequest · Http\Request

$request->method · uri · protocol · headers · body · server · query
Read-only properties. Header names are lower-case; query is the parsed query string.Thuộc tính chỉ đọc. Tên header viết thường; query là query string đã phân tích.
path(): string
URI path without the query string.Đường dẫn URI, không có query string.
header(string $name, ?string $default = null): ?string
Case-insensitive header lookup.Lấy header, không phân biệt hoa thường.
parsedBody(): array
Decoded JSON, x-www-form-urlencoded or multipart/form-data fields.Dữ liệu JSON, x-www-form-urlencoded hoặc các trường multipart/form-data đã giải mã.
uploadedFiles(): array
Uploads in PHP's $_FILES layout (including photos[]). Temp files are deleted after the response; move them with rename(), not move_uploaded_file().File upload theo cấu trúc $_FILES của PHP (kể cả photos[]). File tạm bị xoá sau khi trả response; dùng rename() để chuyển, không dùng move_uploaded_file().
cookies(): array
Request cookies as name ⇒ value.Cookie của request dạng tên ⇒ giá trị.

Response · Http\ResponseResponse · Http\Response

new Response(int $status = 200, array $headers = [], string $body = '')
Headers map a name to a string or a list of strings (several Set-Cookie lines).Header ánh xạ tên tới một chuỗi hoặc danh sách chuỗi (nhiều dòng Set-Cookie).
Response::json(mixed $data, int $status = 200): Response
JSON with unescaped slashes and Unicode.JSON không escape dấu gạch chéo và Unicode.
Response::text(string $text, int $status = 200): Response
text/plain; charset=utf-8.text/plain; charset=utf-8.
Response::from(mixed $result): Response
What the server does with your handler's return value: a Response as is, a string as HTML, an array or JsonSerializable as JSON.Cách server xử lý giá trị handler trả về: Response giữ nguyên, chuỗi thành HTML, mảng hoặc JsonSerializable thành JSON.

HTTP client · Http\ClientHTTP client · Http\Client

Client::request(string $method, string $url, string $body = '', array $headers = [], float $timeout = 10.0): array
Async HTTP/1.1 client for http:// URLs. Returns ['status' => int, 'headers' => array, 'body' => string].HTTP/1.1 client bất đồng bộ cho URL http://. Trả về ['status' => int, 'headers' => array, 'body' => string].
Client::get(string $url, float $timeout = 10.0): array
Shortcut for a GET request.Viết tắt cho request GET.

MySQL / MariaDB · Mysql\ClientMySQL / MariaDB · Mysql\Client

new Mysql\Client(string|Config $config, ?Closure $log = null)
URI form mysql://user:pass@host:3306/db?charset=utf8mb4&pool=10&socket=/run/mysqld/mysqld.sock. Create it once per worker.Dạng URI mysql://user:pass@host:3306/db?charset=utf8mb4&pool=10&socket=/run/mysqld/mysqld.sock. Tạo một lần cho mỗi worker.
query(string $sql, array $params = []): Result
? placeholders; an array param expands for IN (?); DateTime is formatted. Values are escaped by charset (like PDO emulated prepares).Tham số ?; tham số dạng mảng được mở rộng cho IN (?); DateTime được định dạng. Giá trị được escape theo charset (giống emulated prepares của PDO).
transaction(callable $fn): mixed
$fn(Connection $c) runs between BEGIN and COMMIT on one connection; any exception rolls back and is re-thrown.$fn(Connection $c) chạy giữa BEGIN và COMMIT trên một kết nối; có exception thì rollback và ném lại.
withConnection(callable $fn): mixed
Borrows one pooled connection for several statements (session variables, temp tables).Mượn một kết nối từ pool cho nhiều câu lệnh (biến session, bảng tạm).
poolStats(): array · close(): void
Pool counters; close all connections.Thống kê pool; đóng mọi kết nối.
Result: $rows · $affectedRows · $insertId · first() · value() · count()
Rows are associative arrays with native int/float. value() is the first column of the first row. Iterable and countable.Mỗi dòng là mảng kết hợp với kiểu int/float gốc. value() là cột đầu tiên của dòng đầu tiên. Có thể duyệt và đếm.
QueryException: getCode() · $sql · isConnectionError()
MySQL error code (e.g. 1062 duplicate key). On timeout the connection is discarded.Mã lỗi MySQL (ví dụ 1062 trùng khoá). Khi timeout, kết nối bị loại bỏ.

Redis · Redis\ClientRedis · Redis\Client

new Redis\Client(string $uri = 'redis://127.0.0.1:6379', int $poolSize = 16, float $timeout = 5.0)
redis://[user:pass@]host[:port][/db] or unix:///path/redis.sock?db=N&password=….redis://[user:pass@]host[:port][/db] hoặc unix:///path/redis.sock?db=N&password=….
$redis->get('k') · set('k', 'v', 'EX', 30) · incr · hset · expire …
Any Redis command as a method call (via __call).Gọi mọi lệnh Redis như một phương thức (qua __call).
command(string|int|float ...$args): mixed
Sends a raw command: command('ZADD', 'board', 10, 'alice').Gửi lệnh thô: command('ZADD', 'board', 10, 'alice').
pipeline(array $commands): array
Sends several commands in one round trip: pipeline([['SET','a',1], ['INCR','a']]).Gửi nhiều lệnh trong một lượt: pipeline([['SET','a',1], ['INCR','a']]).
poolStats(): array · close(): void
Pool counters; close all connections. Errors such as WRONGTYPE throw RedisException and keep the connection.Thống kê pool; đóng mọi kết nối. Lỗi như WRONGTYPE ném RedisException và kết nối vẫn dùng được.
db.php
use QHTurbo\Runtime\Mysql\Client as Mysql;
use QHTurbo\Runtime\Redis\Client as Redis;
use function QHTurbo\Runtime\Async\{all, async};

$db    = new Mysql('mysql://app:[email protected]:3306/shop?pool=16');   // once per worker
$redis = new Redis('redis://:[email protected]:6379/0', poolSize: 16);

return function (Request $r) use ($db, $redis): array {
    if (($cached = $redis->get('home')) !== null) {
        return json_decode($cached, true);
    }
    [$users, $orders, $visits] = all([            // 3 queries on 3 pooled connections
        async(fn () => $db->query('SELECT id, name FROM users WHERE id IN (?)', [[1, 2, 3]])->rows),
        async(fn () => $db->query('SELECT * FROM orders WHERE created_at > ?', [new DateTime('-1 day')])->rows),
        async(fn () => $db->query('SELECT COUNT(*) FROM visits')->value()),
    ]);
    $db->transaction(function ($c) {
        $c->query('UPDATE stock SET qty = qty - 1 WHERE id = ?', [42]);
        $c->query('INSERT INTO sales (item_id) VALUES (?)', [42]);
    });
    $redis->set('home', json_encode($data = compact('users', 'orders', 'visits')), 'EX', 30);
    return $data;
};

Connection pool · Pool\PoolPool kết nối · Pool\Pool

new Pool(Closure $factory, int $maxSize = 10, ?Closure $closer = null, ?Closure $check = null, float $acquireTimeout = 10.0)
Generic bounded pool used by the Redis and MySQL clients. $check($conn, $idleSeconds) validates idle connections.Pool có giới hạn dùng chung cho Redis và MySQL client. $check($conn, $idleSeconds) kiểm tra kết nối đang rảnh.
use(callable $fn, ?callable $isBroken = null): mixed
Acquire, run $fn($conn), then release, or discard if broken. Callers wait when the pool is exhausted.Lấy kết nối, chạy $fn($conn), rồi trả lại, hoặc loại bỏ nếu hỏng. Khi pool hết, lời gọi sẽ chờ.
acquire() · release($c) · discard($c) · stats() · close()
Manual control.Điều khiển thủ công.

State · StateTrạng thái · State

interface ResetInterface { public function reset(): void; }
Implement it on services that hold per-request state, or on the object your app file returns.Implement cho service giữ trạng thái theo request, hoặc cho object mà file ứng dụng trả về.
StateGuard::addResetter(ResetInterface|callable $r) · captureBaseline() · afterRequest(): array
What the worker runs around each request: reset hooks, then cleanup of globals, ini, output buffers, superglobals; returns the violations found.Những gì worker chạy quanh mỗi request: gọi hook reset, rồi dọn global, ini, output buffer, superglobal; trả về danh sách vi phạm.
StateViolation
Thrown in --strict-state mode; the request returns 500.Ném ra ở chế độ --strict-state; request trả về 500.
reset.php
use QHTurbo\Runtime\Http\{Request, Response};
use QHTurbo\Runtime\State\ResetInterface;

final class App implements ResetInterface {
    private ?array $user = null;                       // per-request state
    public function __invoke(Request $r): Response {
        $this->user = ['id' => (int) ($r->query['uid'] ?? 0)];
        return Response::json($this->user, 200);
    }
    public function reset(): void { $this->user = null; }   // called after every request
}
return new App();

Framework bridges · BridgeCầu nối framework · Bridge

new Bridge\Laravel(string $basePath) · handle(Request): Response · reset()
What --framework=laravel uses.Thứ mà --framework=laravel sử dụng.
new Bridge\Symfony(string $basePath) · handle(Request): Response
What --framework=symfony uses; sets APP_RUNTIME_MODE=web=1&worker=1.Thứ mà --framework=symfony sử dụng; đặt APP_RUNTIME_MODE=web=1&worker=1.
HttpFoundation::toSymfony(Request $r): SymfonyRequest · fromSymfony(SymfonyResponse $r): Response
Converters for any HttpFoundation-based app.Bộ chuyển đổi cho mọi ứng dụng dựa trên HttpFoundation.

Scripts and toolsScript và công cụ

aaPanel and DirectAdminaaPanel và DirectAdmin

scripts/aapanel.sh and scripts/directadmin.sh share the same verbs (DirectAdmin takes a domain instead of a site and has no sync-ini). Web server: nginx or Apache, detected automatically (--web=nginx|apache to force).

scripts/aapanel.sh và scripts/directadmin.sh dùng chung các lệnh (DirectAdmin nhận tên domain thay cho site và không có sync-ini). Web server: nginx hoặc Apache, tự nhận diện (ép bằng --web=nginx|apache).

CommandLệnhWhat it doesChức năng
check [--php=8.5]Inspect the server and print a plan; changes nothingKiểm tra máy chủ và in kế hoạch; không thay đổi gì
install [--php=8.5]Build + install /opt/qhturbo/, start FPM, copy extensionsBuild + cài /opt/qhturbo/, khởi động FPM, sao chép extension
enable <site> [--php=8.5] [--url=URL]Switch ONE site to QHturbo; auto-rollback on errorsChuyển MỘT site sang QHturbo; tự rollback khi lỗi
disable <site>Switch the site back to the panel's PHPĐưa site về PHP của panel
statusSites on QHturbo and service healthCác site đang dùng QHturbo và tình trạng dịch vụ
sync-ini [--php=8.5]Re-copy limits and disable_functions from aaPanel php.iniSao chép lại giới hạn và disable_functions từ php.ini của aaPanel
sync-ext [--php=8.5]Give QHturbo the extensions of the panel's PHP of that version (NO_SYNC_EXT=1 to skip)Cấp cho QHturbo các extension của PHP cùng phiên bản trong panel (NO_SYNC_EXT=1 để bỏ qua)
uninstall [--php=8.5]Disable all sites, stop and remove the serviceTắt mọi site, dừng và gỡ dịch vụ
versions | sitesTab-separated lists for the panel pluginDanh sách phân tách bằng tab cho plugin panel

qht-doctorqht-doctor

Checks a PHP install (OPcache sizing, Xdebug in production, EOL versions, missing extensions, realpath cache) and, with --scan, finds worker-mode risks: globals, statics, exit(), header(), sessions, superglobals, move_uploaded_file(). Runs on PHP 7.4+.

Kiểm tra bản cài PHP (kích thước OPcache, Xdebug trên production, phiên bản hết hỗ trợ, extension thiếu, realpath cache) và với --scan thì tìm rủi ro khi chạy worker: global, static, exit(), header(), session, superglobal, move_uploaded_file(). Chạy trên PHP 7.4+.

bash
php qht-doctor.php                       # check the PHP running this script
php -c /path/php.ini qht-doctor.php      # check with a specific php.ini
php qht-doctor.php --scan=/var/www/app   # also scan code for worker-mode risks
php qht-doctor.php --json                # machine-readable output

fpm-tunefpm-tune

Recommends pm.max_children and related settings from RAM and the measured memory of running FPM workers.

Đề xuất pm.max_children và các thiết lập liên quan dựa trên RAM và bộ nhớ đo được của các worker FPM đang chạy.

bash
python3 scripts/fpm-tune.py                                 # measure this host
python3 scripts/fpm-tune.py --ram 8192 --reserve 2048 --worker-rss 60 --pools 2 --cpus 4

bench.py and web benchmarksbench.py và benchmark web

Interleaved, warmed-up runs with an A/A noise check, peak RSS, bootstrap 95% confidence intervals and output verification. Options: --php, --runs (7), --warmup (1), --size full|quick, --workloads, --modes interp,jit, --out.

Chạy xen kẽ, có khởi động trước, đối chứng nhiễu A/A, đo RSS đỉnh, khoảng tin cậy 95% bằng bootstrap và kiểm tra đầu ra. Tuỳ chọn: --php, --runs (7), --warmup (1), --size full|quick, --workloads, --modes interp,jit, --out.

bash
python3 scripts/bench.py php --variants baseline,qhturbo --runs 10  # compare builds
python3 scripts/bench.py cross --php 7.4,8.5 --langs php            # compare PHP versions
python3 scripts/bench.py cross --php 8.5 --langs python,node,go     # compare languages
sudo benchmarks/web/run.sh                                          # Compatible vs Performance over HTTP

Build, install and packageBuild, cài đặt và đóng gói

Environment: QHT_LAB (work directory), QHT_PHP (7.4 … 8.5, default 8.5), QHT_PROFILE (minimal | full).

Biến môi trường: QHT_LAB (thư mục làm việc), QHT_PHP (7.4 … 8.5, mặc định 8.5), QHT_PROFILE (minimal | full).

CommandLệnhWhat it doesChức năng
scripts/bootstrap.sh [--all]Clone php-src and fetch the pinned tag (QHT_PHP) or all of them, verifying each commitClone php-src và lấy tag đã ghim (QHT_PHP) hoặc tất cả, kiểm tra từng commit
scripts/build.sh baseline|qhturbo|qhturbo-pgoBuild a variant; QHT_PROFILE=minimal|full chooses the extension setBuild một biến thể; QHT_PROFILE=minimal|full chọn bộ extension
scripts/install.sh [--variant=] [--destdir=] [--user=] [--group=]Install a full build with both run modes' config; never overwrites config (writes *.qhturbo-new)Cài bản full kèm cấu hình cho cả hai chế độ; không ghi đè cấu hình (ghi ra *.qhturbo-new)
scripts/package.sh [--variant=] [--user=] [--group=]Stripped .tar.gz + .sha256 for servers on the same distroFile .tar.gz đã strip + .sha256 cho máy chủ cùng distro
scripts/deps-openssl11.shPrivate OpenSSL 1.1.1w for PHP 7.4/8.0OpenSSL 1.1.1w riêng cho PHP 7.4/8.0
scripts/install-ext.sh <ext> [--php=] [--version=]Build and enable a PECL extension (redis, imagick, apcu…), ionCube, or a bundled one (pgsql, xsl…); falls back to GitHub when PECL is downBuild và bật extension PECL (redis, imagick, apcu…), ionCube hoặc extension đi kèm PHP (pgsql, xsl…); dùng GitHub khi PECL không truy cập được
scripts/run-tests.sh <variant> [interp|opcache|jit]Run the official PHPT suite and save a summaryChạy bộ test PHPT chính thức và lưu tóm tắt

Measured resultsKết quả đo

4 vCPU, PHP 8.5.12, production config, nginx + wrk on the same shared cloud VM (±8% noise). Requests per second; grey is PHP-FPM (Compatible), colour is workers (Performance).

4 vCPU, PHP 8.5.12, cấu hình production, nginx + wrk trên cùng một VM cloud dùng chung (nhiễu ±8%). Đơn vị request/giây; màu xám là PHP-FPM (Compatible), màu nổi là worker (Performance).

PHP-FPMPHP-FPM QHturbo workersWorker QHturbo
ChangeThay đổiSpeed-upMức tăngNotesGhi chú
Workers instead of PHP-FPM, real Laravel 13 appWorker thay cho PHP-FPM, ứng dụng Laravel 13 thật6.7–14.6×Removes the per-request framework bootBỏ chi phí khởi động framework mỗi request
Async MySQL instead of blocking PDOMySQL bất đồng bộ thay cho PDO chặn1.7×When requests wait on the databaseKhi request phải chờ database
Async HTTP callsGọi HTTP bất đồng bộ2.5×With half the RAMDùng một nửa RAM
Enable JIT on 8.5 (CPU workloads)Bật JIT trên 8.5 (tác vụ CPU)1.56×~0 for JSON/string/array work~0 với xử lý JSON/chuỗi/mảng
Upgrade 7.4 → 8.5 (interpreter only)Nâng 7.4 → 8.5 (chỉ trình thông dịch)1.05×1.69× with JIT1.69× khi bật JIT
PGO-optimised binaryBản build tối ưu PGO+0.3% / −3.2%NO-GO: no stable gainNO-GO: không có lợi ích ổn định

Examples and performance testingVí dụ và đo hiệu năng

The examples/ folder next to this page has runnable PHP examples. Each one exists twice: fpm.php written the classic way (runs from the top on every request) and app.php for QHturbo workers. compare.sh starts both, loads them with bench.php (a load generator written in PHP) and prints the results side by side.

Thư mục examples/ cạnh trang này chứa các ví dụ PHP chạy được ngay. Mỗi ví dụ có hai bản: fpm.php viết kiểu truyền thống (chạy lại từ đầu ở mỗi request) và app.php cho worker QHturbo. compare.sh khởi động cả hai, tạo tải bằng bench.php (công cụ tạo tải viết bằng PHP) rồi in kết quả cạnh nhau.

ExampleVí dụWhat it showsCho thấy điều gì
01-helloNo boot cost: the baseline. Expect no big gain, because the speed-up comes from removing work.Không có chi phí khởi động: dùng làm mốc. Không kỳ vọng tăng nhiều, vì tốc độ đến từ việc bỏ bớt công việc.
02-frameworkA stand-in framework (300 classes, 40 configs, DI container, 200 routes) booted per request vs once per worker.Framework mô phỏng (300 class, 40 config, DI container, 200 route) khởi động mỗi request so với một lần mỗi worker.
03-async-io3 backend calls of 20 ms each: sequential and blocking vs parallel with async() + all().3 lời gọi backend 20 ms: tuần tự và bị chặn so với song song bằng async() + all().
04-mysqlA full shop API (schema, seed data, .env, systemd, nginx) written twice over the same SQL: PDO vs the async MySQL client. Ready to upload to a real server; bench-server.sh compares route by route.API cửa hàng hoàn chỉnh (schema, dữ liệu mẫu, .env, systemd, nginx) viết hai lần trên cùng các câu SQL: PDO so với MySQL client bất đồng bộ. Sẵn sàng đưa lên máy chủ thật; bench-server.sh so sánh từng route.
06-asyncAsync patterns: all, timeout, settle, race, mapLimit, retry, timers and a Redis cache. demo.php runs in the terminal without a server.Các mẫu async: all, timeout, settle, race, mapLimit, retry, hẹn giờ và cache Redis. demo.php chạy ngay trên terminal, không cần server.
05-cpu-jitCPU workloads: interpreter vs OPcache vs JIT, or two PHP binaries side by side.Tác vụ CPU: thông dịch, OPcache và JIT, hoặc so hai bản PHP với nhau.
compare.sh · bench.php · cpu.php
git clone https://github.com/qhsvn/QHTurbo.git && cd QHTurbo
cp -r /path/to/examples ./examples                 # next to runtime/
bash examples/compare.sh all                       # hello + framework + async-io
WORKERS=4 C=128 D=15 bash examples/compare.sh framework
PHP=/opt/qhturbo/8.5/bin/php bash examples/compare.sh async-io
php examples/05-cpu-jit/cpu.php --compare          # interpreter vs OPcache vs JIT
php examples/06-async/demo.php                     # async patterns, no server needed
php examples/bench.php http://127.0.0.1:8080/ -c 64 -d 10 -p 2
output
== 02-framework  (2 processes each, 64 connections, 5s)
  classic (php -S / FPM)                4,720.4 req/s   p50   11.86 ms   p99    74.91 ms   errors 0
  QHturbo workers (concurrency 1)      18,780.8 req/s   p50    3.28 ms   p99     7.61 ms   errors 0
  => QHturbo is 4.0x the requests/s of classic PHP

Sample run (PHP 8.3.6, shared 4-vCPU container, 2 processes per side, 64 connections, client on the same machine). Treat it as an illustration and measure on your own server:

Kết quả chạy thử (PHP 8.3.6, container dùng chung 4 vCPU, mỗi bên 2 tiến trình, 64 kết nối, công cụ tạo tải cùng máy). Chỉ mang tính minh hoạ, hãy đo trên máy chủ của bạn:

ExampleVí dụClassic (php -S)Truyền thống (php -S)QHturbo workersWorker QHturbo
01 hello14,507 req/s · p50 4.2 ms9,083 req/s · p50 1.4 ms0.6×
02 framework4,720 req/s · p50 11.9 ms18,781 req/s · p50 3.3 ms4.0×
03 async I/O48 req/s · p50 1,321 ms1,618 req/s · p50 40 ms33.7×
05 CPUinterpreter 1.00×thông dịch 1,00×OPcache 1.25× · JIT 1.82×

The MySQL kit on the same container with MariaDB 10.11. The more a route waits on I/O, the bigger the gain; when MySQL itself is saturated (dashboard), async does not help:

Bộ MySQL chạy trên cùng container với MariaDB 10.11. Route càng chờ I/O nhiều thì càng nhanh hơn; khi chính MySQL đã quá tải (dashboard) thì async không giúp được:

Route (04-mysql)Route (04-mysql)PHP-FPM + PDOQHturbo + async MySQLQHturbo + MySQL bất đồng bộ
/products/{id}2,749 req/s5,195 req/s1.9×
/orders/random2,326 req/s3,187 req/s1.4×
/slow (3 × 20 ms)81 req/s493 req/s6.1×
/dashboard16 req/s14 req/s0.9× (MySQL saturated)0.9× (MySQL quá tải)
04-mysql · deploy
# on a test server, from examples/04-mysql
cp .env.example .env && nano .env                  # DB_PASS, WORKERS, CONCURRENCY ...
sudo bash deploy/setup.sh                          # database + test data + systemd worker
sudo cp deploy/nginx-shop.conf /etc/nginx/conf.d/qht-shop.conf && sudo nginx -s reload
bash bench-server.sh http://127.0.0.1/fpm http://127.0.0.1/worker

Hello world gets no faster, which is expected: a worker only wins when there is boot work to skip (02) or I/O to overlap (03, 04). To test your real nginx + PHP-FPM, put an example's fpm.php in a site and run with CLASSIC_URL=http://your-site/fpm.php.

Hello world không nhanh hơn là điều bình thường: worker chỉ thắng khi có phần khởi động để bỏ qua (02) hoặc I/O để chạy chồng lên nhau (03, 04). Để đo với nginx + PHP-FPM thật, đặt fpm.php của ví dụ vào một site rồi chạy với CLASSIC_URL=http://site-cua-ban/fpm.php.

Full instructions: examples/README.md.

Hướng dẫn đầy đủ: examples/README.vi.md.

Example source codeMã nguồn các ví dụ

Every file of the examples/ folder, with the commands to run it. Paths assume the folder sits inside a QHTurbo checkout, next to runtime/. Click a file name to expand it; each block has a copy button.

Toàn bộ file trong thư mục examples/ kèm lệnh chạy. Đường dẫn giả định thư mục nằm trong repo QHTurbo, cạnh runtime/. Bấm vào tên file để mở; mỗi khối code đều có nút sao chép.

The smallest possible app, written both ways. There is nothing to boot, so the worker is not faster here: use it as the baseline and to check that your setup works.

Ứng dụng nhỏ nhất, viết theo cả hai cách. Không có gì để khởi động nên worker không nhanh hơn ở đây: dùng làm mốc và để kiểm tra môi trường đã chạy đúng.

RunChạy
php runtime/bin/qhturbo-serve examples/01-hello/app.php --port=8080 --workers=2
curl localhost:8080/hello
bash examples/compare.sh hello
Source filesMã nguồn · 2
examples/01-hello/fpm.php5 linesdòng
examples/01-hello/fpm.php
<?php
// Classic PHP (PHP-FPM / php -S): this file runs from the top on every request.
header('Content-Type: application/json');
echo json_encode(['hello' => 'world', 'pid' => getmypid()]);
examples/01-hello/app.php8 linesdòng
examples/01-hello/app.php
<?php
// QHturbo Performance: everything above "return" runs once per worker,
// the closure runs per request.
//   php runtime/bin/qhturbo-serve examples/01-hello/app.php --port=8080 --workers=4
use QHTurbo\Runtime\Http\Request;

return static fn (Request $request): array => ['hello' => 'world', 'pid' => getmypid()];

Tips and limitationsMẹo và giới hạn

Apply to your servers todayÁp dụng ngay cho máy chủ

  1. Upgrade to PHP 8.3+ if your app allows it.Nâng lên PHP 8.3+ nếu ứng dụng cho phép.
  2. Size OPcache (memory_consumption, max_accelerated_files); use validate_timestamps=0 only if every deploy reloads FPM.Cấu hình đủ OPcache (memory_consumption, max_accelerated_files); chỉ dùng validate_timestamps=0 nếu mỗi lần deploy đều reload FPM.
  3. Enable JIT for compute-heavy code; measure first for typical web apps.Bật JIT cho code nặng tính toán; với web thông thường hãy đo trước.
  4. Use preload for large frameworks.Dùng preload cho framework lớn.
  5. Most latency is MySQL/Redis/I/O: fix queries, indexes and caching, then consider Performance mode.Phần lớn độ trễ nằm ở MySQL/Redis/I/O: tối ưu truy vấn, index và cache, sau đó cân nhắc chế độ Performance.

Current limitationsGiới hạn hiện tại

  • The built-in server has no TLS, HTTP/2 or chunked request bodies: keep nginx in front.Server tích hợp không có TLS, HTTP/2 hay request body dạng chunked: luôn đặt nginx phía trước.
  • Uploads and responses are held in RAM; let nginx serve large files (X-Accel-Redirect).Upload và response nằm trong RAM; để nginx phục vụ file lớn (X-Accel-Redirect).
  • PDO, Eloquent and Doctrine still block; use the async clients for I/O-heavy paths.PDO, Eloquent và Doctrine vẫn chạy chặn; dùng client bất đồng bộ cho các đoạn nặng I/O.
  • Redis: no Pub/Sub, Cluster or Sentinel yet. MySQL: connect is blocking, no server-side prepares.Redis: chưa có Pub/Sub, Cluster, Sentinel. MySQL: bước kết nối vẫn chặn, chưa có prepare phía server.
  • WordPress and code using exit() for control flow should stay on Compatible.WordPress và code dùng exit() để điều khiển luồng nên giữ ở Compatible.

FAQCâu hỏi thường gặp

Will it break the PHP my panel installed?Nó có làm hỏng PHP mà panel đã cài không?

No. QHturbo installs under /opt/qhturbo with its own socket and service, and refuses to install into system or panel paths. disable switches a site back in seconds.

Không. QHturbo cài dưới /opt/qhturbo với socket và dịch vụ riêng, và từ chối cài vào đường dẫn của hệ thống hay panel. disable đưa site về như cũ trong vài giây.

Can I run several PHP versions at once?Có chạy nhiều phiên bản PHP cùng lúc được không?

Yes. Each version has its own prefix, socket (php74-fpm.sock, php85-fpm.sock…) and systemd unit.

Được. Mỗi phiên bản có prefix, socket (php74-fpm.sock, php85-fpm.sock…) và unit systemd riêng.

Does Performance mode need Swoole or another extension?Chế độ Performance có cần Swoole hay extension khác không?

No. It is pure PHP 8.1+ using Fibers. pcntl/posix are needed only for multiple workers, mysqli only for the MySQL client.

Không. Nó viết thuần PHP 8.1+ dùng Fiber. Chỉ cần pcntl/posix khi chạy nhiều worker, và mysqli khi dùng MySQL client.

How does it compare to Octane, FrankenPHP or RoadRunner?So với Octane, FrankenPHP hay RoadRunner thì sao?

Those are mature options worth considering for large deployments. QHturbo Performance needs no external extension or binary and is small enough to read and control.

Đó là các giải pháp trưởng thành, đáng cân nhắc cho hệ thống lớn. QHturbo Performance không cần extension hay binary bên ngoài và đủ gọn để đọc hiểu và kiểm soát.