Skip to content

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:

text
* soft nofile 65535
* hard nofile 65535

Apply immediately to your session:

bash
ulimit -n 65535

For systemd services, add to the [Service] block:

ini
LimitNOFILE=65535

TCP Backlog ​

For high-concurrency deployments, increase the kernel connection queue:

bash
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_max_syn_backlog=65535

Persist in /etc/sysctl.conf:

text
net.core.somaxconn=65535
net.ipv4.tcp_max_syn_backlog=65535

PHP OPCache Optimization ​

In production, disable file modification checks entirely to eliminate disk syscalls on every request.

Edit php.ini:

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=128M

Cache config and routes:

bash
php nexphant cache:config
composer dump-autoload -o

Memory Limit ​

Nexphant workers are long-lived. Set a generous but bounded memory limit:

ini
memory_limit=512M

Monitor 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:

php
gc_collect_cycles();

Disable refcount-based GC entirely only if you have confirmed zero circular references and are comfortable managing memory manually:

ini
zend.enable_gc=0

DB Connection Pooling ​

Traditional PHP opens and closes connections per request. Nexphant maintains persistent pools:

php
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_timeout to 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.

php
$app->workers((int) env('APP_WORKERS', 4));

Tune based on pressure metrics:

bash
curl http://localhost:8080/api/metrics | grep pressure
  • pressure > 0.8 consistently → add workers or increase max_accept_per_tick
  • pressure < 0.2 consistently → reduce workers to free OS resources

Runtime Mode ​

php
$app->runtimeMode('throughput'); // 'throughput' | 'balanced' | 'latency'
ModeUse Case
throughputHigh-volume APIs, batch endpoints
balancedGeneral-purpose (default)
latencyReal-time, WebSocket, SSE

Event Loop Backend ​

php
$app->eventLoop('ev'); // 'auto' | 'ev' | 'event' | 'native'

Install ext-ev for best performance:

bash
pecl install ev

auto selects the best available backend automatically.


Checklist ​

  • [ ] opcache.validate_timestamps=0
  • [ ] opcache.jit=tracing
  • [ ] ulimit -n 65535 (or LimitNOFILE in systemd)
  • [ ] composer dump-oa-claude-sonnet-4.6load -o
  • [ ] php nexphant cache:config
  • [ ] ext-ev installed
  • [ ] DB max_connections sized for all pools
  • [ ] supervisor(true) enabled

Next Steps ​

Released under the MIT License.