Nginx vs. FrankenPHP (Worker vs. Thread)

Performance Benchmark on a Sylius Application

Test Environment

Compute Server

Scaleway DEV1-S (2 vCPUs, 2 GB RAM)

Application

Sylius Standard (PHP 8.3)

Database Server

Scaleway DB-DEV-S (2 vCPUs, 2 GB RAM, MySQL)

Benchmark Tool

wrk on a separate DEV1-S instance

Configurations

Nginx + PHP-FPM: pm.max_children = 15

FrankenPHP (Worker Mode): worker.num = 36

FrankenPHP (Thread Mode): num_threads = 36

Warmup Procedure

Before each 30-second benchmark, a warmup phase was executed. This involved calling the API endpoint with `curl` to ensure application caches were primed, followed by a preliminary 10-second `wrk` run with 100 connections.

Requests per Second

Average Latency (ms)

Latency Distribution @ 100 Connections

Latency Distribution @ 200 Connections

Benchmark Summary

The benchmarks reveal a stark difference in performance between the server configurations, particularly highlighting the strength of FrankenPHP's worker mode.

  • FrankenPHP Worker Mode Leads Significantly: This configuration vastly outperformed the others, handling nearly 3x more requests per second and showing dramatically lower latency across both 100 and 200 connection tests.
  • Nginx vs. FrankenPHP Thread Mode: The performance difference between the traditional Nginx/PHP-FPM setup and FrankenPHP's thread-based mode is negligible.
  • Performance Under Pressure: FrankenPHP in worker mode was the only configuration that handled the increased load from 100 to 200 connections gracefully, maintaining high throughput. In contrast, both Nginx and FrankenPHP's thread mode saw latency skyrocket to unusable levels, with throughput remaining flat.

Raw `wrk` Results


### FrankenPHP (Thread Mode, num_threads = 36) ###

# 100 Connections
root@attacker:~# wrk -t4 -c100 -d30s --latency --timeout 20s http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
Running 30s test @ http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.56s   852.58ms   5.99s    87.38%
    Req/Sec    10.15      9.58    50.00     75.00%
  Latency Distribution
     50%    4.72s
     75%    5.10s
     90%    5.29s
     99%    5.78s
  610 requests in 30.05s, 1.95MB read
Requests/sec:     20.30
Transfer/sec:     66.30KB

# 200 Connections
root@attacker:~# wrk -t4 -c200 -d30s --latency --timeout 20s http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
Running 30s test @ http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
  4 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.34s     2.52s   10.68s    82.23%
    Req/Sec    14.31     14.70    90.00     85.53%
  Latency Distribution
     50%    9.58s
     75%    9.78s
     90%    9.97s
     99%   10.31s
  602 requests in 30.05s, 1.91MB read
Requests/sec:     20.03
Transfer/sec:     65.11KB

---

### Nginx + PHP-FPM ###

# 100 Connections
root@attacker:~# wrk -t4 -c100 -d30s --latency --timeout 20s http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
Running 30s test @ http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.27s   901.33ms   4.98s    89.83%
    Req/Sec    14.72     10.81    50.00     74.57%
  Latency Distribution
     50%    4.54s
     75%    4.63s
     90%    4.72s
     99%    4.87s
  649 requests in 30.05s, 2.06MB read
Requests/sec:     21.60
Transfer/sec:     70.35KB

# 200 Connections
root@attacker:~# wrk -t4 -c200 -d30s --latency --timeout 20s http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
Running 30s test @ http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
  4 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     7.77s     2.46s    9.45s    83.08%
    Req/Sec    15.02     10.39    60.00     78.49%
  Latency Distribution
     50%    9.04s
     75%    9.11s
     90%    9.18s
     99%    9.30s
  656 requests in 30.06s, 2.09MB read
Requests/sec:     21.82
Transfer/sec:     71.09KB

---

### FrankenPHP (Worker Mode, worker.num = 36) ###

# 100 Connections
root@attacker:~# wrk -t4 -c100 -d30s --latency --timeout 20s http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
Running 30s test @ http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.69s   321.95ms   2.57s    71.90%
    Req/Sec    20.57     19.25   131.00     80.33%
  Latency Distribution
     50%    1.65s
     75%    1.93s
     90%    2.11s
     99%    2.36s
  1733 requests in 30.06s, 5.46MB read
Requests/sec:     57.65
Transfer/sec:   186.07KB

# 200 Connections
root@attacker:~# wrk -t4 -c200 -d30s --latency --timeout 20s http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
Running 30s test @ http://51.159.157.40/api/v2/shop/products/Summer_Picnic_Charm
  4 threads and 200 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.92s   577.77ms   3.89s    78.93%
    Req/Sec    24.44     26.24   200.00     88.45%
  Latency Distribution
     50%    3.02s
     75%    3.28s
     90%    3.50s
     99%    3.71s
  1932 requests in 30.05s, 6.09MB read
Requests/sec:     64.29
Transfer/sec:   207.51KB