Laravel Octane benchmark comparing Swoole, OpenSwoole, RoadRunner, FrankenPHP
terrylinooo
Performance Engineer · 2024-01-14
I made a Laravel Octane benchmark comparing Swoole, OpenSwoole, RoadRunner, FrankenPHP, and PHP-FPM. Report: terrylinooo.github.io/laravel-octane-benchmark The benchmark compares p99 latency, memory, CPU overhead, DB workload, I/O workload, and different concurrency levels. My main takeaway: Octane is not a simple turn it on and everything is faster solution. It depends a lot
Laravel Octane supercharges applications by persisting the framework in memory between requests, but the server backend you choose dramatically changes outcomes. This post distills benchmark findings and provides practical guidance for selecting among Swoole, OpenSwoole, RoadRunner, FrankenPHP, and traditional PHP-FPM based on workload type, operational constraints, and team expertise.
Benchmark Methodology
The benchmark measures p99 latency, requests per second, memory usage, CPU overhead, database throughput, and I/O behavior under varying concurrency. Tests run on consistent hardware with identical application code to minimize noise. Each backend is configured with production-like tuning, including worker counts, reload intervals, and task workers where applicable.
Swoole and OpenSwoole
Swoole delivers very high throughput and low latency when applications are CPU-bound and benefit from single-process event loops. OpenSwoole, maintained by an independent community, offers similar performance with a focus on long-term support and compatibility. Both run well with Octane, but they require careful task and channel configuration when handling blocking I/O.
RoadRunner
RoadRunner uses a Go-based process manager with PHP workers, giving excellent resilience and simple deployment. It handles HTTP and queue workloads in a single binary. Latency is competitive, though slightly higher than Swoole at low concurrency because of the process supervisor boundary. Teams with Go infrastructure often prefer RoadRunner for operational simplicity.
FrankenPHP
FrankenPHP embeds PHP into the Caddy server, producing a single static binary with automatic HTTPS and worker mode. Benchmarks show strong performance on I/O-bound workloads, but higher memory usage at scale. It is attractive when you want modern HTTP handling and easy deployment to edge or container environments.
Operational Guidance
Choosing a backend depends on whether your application is I/O or CPU bound. For database-heavy workloads, connection pooling and worker count matter more than raw HTTP latency. Watchdog reload policies must be tuned to avoid unnecessary restarts. Combine this operational focus with insights from Difficulty scaling Laravel Horizon across multiple instances (ECS / Auto Scaling), which examines how distributed job consumers behave with persistent runtimes.
Conclusion
Octane is powerful but not universally faster. Test your actual traffic patterns, measure memory and p99 latency under realistic concurrency, and expect to tune worker counts and reload behavior before declaring a winner in production.
Related Posts
- Difficulty scaling Laravel Horizon across multiple instances (ECS / Auto Scaling)
- Get Inserted Id from DB::insert()
- Laravel Octane benchmark comparing Swoole, OpenSwoole, RoadRunner, FrankenPHP
These related posts cover deployment scaling, database throughput, and persistent runtime performance in Laravel.
Configuring Laravel Octane for Production
Production Octane setups require attention to process management, signal handling, and graceful restarts. With Swoole or OpenSwoole, configure worker_count based on CPU cores, set max_request to prevent memory leaks, and enable task_worker_num for async tasks. FrankenPHP uses a different configuration model: workers are managed internally, and you tune concurrency via environment variables or CLI flags. RoadRunner uses a .rr.yaml file where you define the number of HTTP and task workers.
Regardless of engine, use supervisor or systemd to keep the Octane process alive. For zero-downtime deploys, implement rolling restarts: stop old workers after they finish current requests, then start new ones. FrankenPHP supports this via the graceful flag. OpenSwoole offers reload signals. RoadRunner has a built-in HTTP server that supports graceful shutdown.
When Octane May Not Be Worth It
If your application is I/O light and relies heavily on third-party SDKs that aren't thread-safe or connection-safe, Octane's in-memory model can introduce subtle bugs. The same Laravel instance handles every request, so global state persists between requests. Avoid modifying globals, static properties, or the container singleton state during request handling. Be careful with temporary file handling: ensure files are cleaned up, as subsequent requests may inherit the same process state.
See Get Inserted Id from DB::insert() for data-heavy workloads where raw PDO may complement Octane, and Difficulty scaling Laravel Horizon across multiple instances (ECS / Auto Scaling) for containerized deployments.
Benchmarking Methodology
To benchmark Octane fairly, pin your PHP version, opcache settings, and Laravel configuration across engines. Use wrk or autocannon with consistent concurrency (e.g., 50, 100, 200 connections) and duration. Warm up the application before measurement to fill opcache. Measure latency percentiles (p50, p95, p99), throughput (requests per second), and memory usage via top or /proc. Include cold-start measurements for each engine.
RoadRunner often shows the lowest p99 latency under high concurrency because its goroutine scheduler handles many simultaneous connections efficiently. Swoole excels at raw throughput but may suffer from memory leaks if workers are not recycled. FrankenPHP's HTTP/3 support is attractive for mobile clients on 5G, where connection setup is a large fraction of latency. OpenSwoole balances features and stability for teams migrating from traditional PHP-FPM.
Operational Considerations
Octane changes how you deploy. CI pipelines must build the Octane binary or ensure the PECL extension is installed. Logging, monitoring, and debugging tools must attach to long-running processes. Laravel Telescope works with Octane but may require configuration to handle worker restarts. Use a process manager like Supervisor for resilience, and configure automatic restarts for memory thresholds.
See Get Inserted Id from DB::insert() for optimizing data imports under Octane, and Difficulty scaling Laravel Horizon across multiple instances (ECS / Auto Scaling) for container orchestration considerations.