Laravel Octane to rozszerzenie, które pozwala uruchomić aplikację Laravel na serwerach asynchronicznych, eliminując koszt uruchamiania frameworka przy każdym żądaniu. Dwa najpopularniejsze tryby – Swoole i RoadRunner – różnią się pod względem architektury, wymagań środowiskowych i charakterystyki wydajności. W tym artykule przeprowadzimy porównanie Laravel Octane Swoole i RoadRunner, podamy konkretne przykłady konfiguracji oraz omówimy pułapki przy użyciu Swoole w Laravel i optymalizację pamięci Laravel Octane.
Architektura Swoole vs RoadRunner
Swoole jest rozszerzeniem PHP napisanym w C, które uruchamia własny event‑loop i zarządza połączeniami TCP/HTTP na poziomie systemu operacyjnego. Działa jako serwer wielowątkowy, w którym każdy worker posiada własny proces PHP‑FPM‑like, ale utrzymuje pamięć pomiędzy żądaniami. RoadRunner natomiast jest pośrednikiem opartym na Go. Odbiera żądania HTTP, przekazuje je do procesu PHP (worker) i po zakończeniu zwraca wynik, po czym worker pozostaje w pamięci, gotowy na kolejne wywołania.
Kluczowa różnica polega na tym, że Swoole zarządza zarówno warstwą sieciową, jak i wykonywaniem kodu PHP, co pozwala na coroutine i niskie opóźnienia I/O. RoadRunner deleguje obsługę sieci do Go, co skutkuje mniejszą liczbą zależności w środowisku PHP, ale wprowadza dodatkową warstwę komunikacji między procesami.
Dlaczego wybrać Octane?
Tradycyjny PHP‑FPM tworzy nową instancję aplikacji przy każdym żądaniu. To generuje znaczący narzut – ładowanie plików, rejestracja usług, kompilacja kontenerów. Octane eliminuje ten koszt, utrzymując aplikację w pamięci, co w praktyce przekłada się na 2‑3‑krotne przyspieszenie czasu odpowiedzi przy typowych obciążeniach API.
Jednak korzyści te przychodzą z nowymi wyzwaniami: pamięć nie jest zwalniana po każdym żądaniu, a niektóre komponenty Laravel (np. sesje oparte na plikach) nie są domyślnie przystosowane do długotrwałego życia procesu. Dlatego tak ważne jest zrozumienie kompromisów wydajnościowych i architektonicznych przed wdrożeniem.
Konfiguracja w praktyce – Swoole
composer require laravel/octane
php artisan octane:install --server=swoole
# plik .env
OCTANE_SERVER=swoole
OCTANE_WORKERS=8
OCTANE_MAX_REQUESTS=500
OCTANE_MAX_EXECUTION_TIME=30
Po instalacji najważniejsze parametry to OCTANE_WORKERS – liczba procesów workerów, oraz OCTANE_MAX_REQUESTS, które definiują, po ilu żądaniach worker zostanie zrestartowany, aby zwolnić zużytą pamięć. Dla aplikacji z intensywnym użyciem cache’u w pamięci, warto ustawić niższą wartość, aby uniknąć wycieków.
Konfiguracja w praktyce – RoadRunner
# composer require spiral/roadrunner laravel/octane
php artisan octane:install --server=roadrunner
# plik .rr.yaml
rpc:
listen: tcp://127.0.0.1:6001
http:
address: 0.0.0.0:8080
workers:
command: "php worker.php"
relay: "pipes"
pool:
numWorkers: 8
maxJobs: 500
RoadRunner wymaga osobnego pliku konfiguracyjnego .rr.yaml. Parametr numWorkers odpowiada liczbie procesów PHP, a maxJobs pełni analogiczną rolę do OCTANE_MAX_REQUESTS w Swoole. Dodatkowo, RoadRunner oferuje wbudowane wsparcie dla static files i gzip, co może odciążyć aplikację.
Kiedy używać Swoole, a kiedy RoadRunner?
- Swoole – idealny, gdy potrzebujesz niskich opóźnień I/O, obsługi WebSocketów i coroutine. Sprawdza się w mikroserwisach, real‑time API oraz aplikacjach wymagających wysokiej przepustowości.
- RoadRunner – lepszy wybór, gdy chcesz minimalizować zależności systemowe (brak rozszerzenia Swoole), masz już infrastrukturę Go lub potrzebujesz prostego deploymentu w kontenerach Docker.
Oba rozwiązania działają świetnie w środowiskach Kubernetes, ale Swoole wymaga dodatkowego kroku instalacji rozszerzenia (pecl install swoole) w obrazie kontenera, co może wydłużyć CI/CD.
Pułapki przy użyciu Swoole w Laravel
Najczęstsze problemy to:
- Nieodpowiednie zarządzanie połączeniami do bazy – połączenia nie są automatycznie zamykane po żądaniu, co prowadzi do wyczerpania puli. Rozwiązanie: w
AppProvidersAppServiceProvider::boot()zarejestruj listenerOctane::terminatingi wywołajDB::disconnect(). - Cache w pamięci (
arraydriver) nie jest współdzielony między workerami, co może powodować niespójności. Używajredislubmemcached. - Statyczne zmienne globalne i singletony nie są resetowane po restartach workerów, co może prowadzić do starych danych w pamięci.
Rozwiązania obejmują dokładne czyszczenie stanu w hooku Octane::restarting oraz ograniczenie użycia statycznych właściwości.
Optymalizacja pamięci Laravel Octane
Kluczowe techniki:
- Ustaw
OCTANE_MAX_REQUESTSna wartość 300‑500, aby regularnie odświeżać pamięć workerów. - Włącz
opcache.preloadwphp.ini, aby przyspieszyć ładowanie klas przy starcie workerów. - Używaj
php artisan config:cacheiroute:cache– Octane korzysta z już zbuforowanych plików, co redukuje zużycie CPU.
Monitoruj zużycie pamięci przy pomocy top lub htop oraz narzędzi takich jak Octane::stats(), które zwracają informacje o liczbie aktywnych workerów i zużyciu pamięci.
„Wydajność to nie tylko liczby – to zdolność utrzymania stabilności przy rosnącym obciążeniem.”
Checklist – wdrożenie Laravel Octane w produkcji
# 1. Wybór serwera
# - Swoole: potrzebne rozszerzenie, lepsze I/O
# - RoadRunner: brak rozszerzeń, prostszy Docker
# 2. Konfiguracja środowiska
OCTANE_SERVER=swoole # lub roadrunner
OCTANE_WORKERS=8
OCTANE_MAX_REQUESTS=400
OCTANE_MAX_EXECUTION_TIME=30
# 3. Bezpieczne połączenia DB
use Laravel\Octane\Facades\Octane;
Octane::terminating(function () {
DB::disconnect();
});
# 4. Cache i sesje
CACHE_DRIVER=redis
SESSION_DRIVER=redis
# 5. Optymalizacje
php artisan config:cache
php artisan route:cache
php artisan view:cache
# 6. Monitoring
php artisan octane:stats --watch
Po zastosowaniu powyższej checklisty, aplikacja powinna działać stabilnie przy wysokim współczynniku RPS. Pamiętaj, aby regularnie testować max_requests w środowisku staging, ponieważ różnice w danych produkcyjnych mogą wpływać na zużycie pamięci.
Typowe błędy i kompromisy
Wdrożenie Octane często prowadzi do fałszywego poczucia, że „wydajność jest już maksymalna”. W rzeczywistości:
- Użycie
session: filepowoduje blokady plików w długotrwałych workerach – przełącz na Redis. - Rozbudowane eventy w
boot()mogą być wywoływane przy każdym żądaniu, mimo że nie powinny – przenieś je doOctane::bootinglubOctane::reloading. - Nie wszystkie pakiety są kompatybilne z długotrwałymi procesami (np. niektóre biblioteki SOAP). Testuj je w izolacji.
Kompromisy obejmują zwiększone zużycie pamięci (każdy worker trzyma pełny kontener Laravel) w zamian za niższe czasy odpowiedzi. W środowiskach z ograniczoną pamięcią lepszy może być mniejszy liczba workerów i częstsze restartowanie.
Podsumowując, wybór między Swoole a RoadRunner zależy od specyfiki Twojego projektu – potrzeby real‑time, dostępność zasobów i preferencje operacyjne. Oba rozwiązania znacząco podnoszą Laravel Octane wydajność, pod warunkiem właściwej konfiguracji i świadomości pułapek produkcyjnych.
Jeśli potrzebujesz pomocy przy migracji do Octane, optymalizacji pamięci lub budowie skalowalnej architektury, skontaktuj się z zespołem Coderia.it – wspólnie przyspieszymy Twój kod.



