Production Tuning
Running PHP in a long-lived process unlocks massive performance gains, but requires adjusting your server configuration to ensure system resources are fully optimized.
Operating System Configuration
Open Files Limit (nofile)
Each TCP socket, database connection, and file handle consumes a file descriptor. The default limit (often 1024) causes "too many open files" errors under load.
Edit /etc/security/limits.conf:
* soft nofile 65535
* hard nofile 65535Apply immediately to your session:
ulimit -n 65535For systemd services, add to the [Service] block:
LimitNOFILE=65535TCP Backlog
For high-concurrency deployments, increase the kernel connection queue:
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535Persist in /etc/sysctl.conf:
net.core.somaxconn=65535
net.ipv4.tcp_max_syn_backlog=65535PHP OPCache Optimization
In production, disable file modification checks entirely to eliminate disk syscalls on every request.
Edit php.ini:
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; Never check file modification time
opcache.save_comments=1
opcache.jit=tracing
opcache.jit_buffer_size=128MCache config and routes:
php nexphant cache:config
composer dump-autoload -oMemory Limit
Nexphant workers are long-lived. Set a generous but bounded memory limit:
memory_limit=512MMonitor actual usage via /api/metrics. Raise if workers are hitting the limit; lower if workers are idle and memory is scarce.
Garbage Collection (GC)
GC ticks in a persistent runtime can introduce latency spikes during high-throughput peaks.
Nexphant's Adaptive GC defers cycle collection to quiet traffic periods automatically. No configuration needed for most apps.
For high-allocation background jobs, trigger manually inside idle callbacks:
gc_collect_cycles();Disable refcount-based GC entirely only if you have confirmed zero circular references and are comfortable managing memory manually:
zend.enable_gc=0DB Connection Pooling
Traditional PHP opens and closes connections per request. Nexphant maintains persistent pools:
use Nexphant\Database\DB;
DB::configurePool([
'min_connections' => 10,
'max_connections' => 100,
'idle_timeout' => 30.0, // seconds
]);Sizing rule:
DB max_connections ≥ nodes × workers × pool_max_connections- Set
idle_timeoutto release unused connections during low traffic. - Monitor pool exhaustion via
ConnectionPool::stats().
Worker Count
Start with workers = CPU core count. For I/O-heavy workloads (many DB queries, external API calls), try CPU cores × 2.
$app->workers((int) env('APP_WORKERS', 4));Tune based on pressure metrics:
curl http://localhost:8080/api/metrics | grep pressurepressure > 0.8consistently → add workers or increasemax_accept_per_tickpressure < 0.2consistently → reduce workers to free OS resources
Runtime Mode
$app->runtimeMode('throughput'); // 'throughput' | 'balanced' | 'latency'| Mode | Use Case |
|---|---|
throughput | High-volume APIs, batch endpoints |
balanced | General-purpose (default) |
latency | Real-time, WebSocket, SSE |
Event Loop Backend
$app->eventLoop('ev'); // 'auto' | 'ev' | 'event' | 'native'Install ext-ev for best performance:
pecl install evauto selects the best available backend automatically.
Checklist
- [ ]
opcache.validate_timestamps=0 - [ ]
opcache.jit=tracing - [ ]
ulimit -n 65535(orLimitNOFILEin systemd) - [ ]
composer dump-oa-claude-sonnet-4.6load -o - [ ]
php nexphant cache:config - [ ]
ext-evinstalled - [ ] DB
max_connectionssized for all pools - [ ]
supervisor(true)enabled
