Rust dla firm — usługi wysokiej wydajności
Gdy liczy się przepustowość i niskie opóźnienia, obok głównej aplikacji stawiamy osobne usługi w Rust (Axum, SeaORM) — bez przepisywania całego systemu.
Większość aplikacji biznesowych nie potrzebuje Rusta — dobrze zaprojektowany Laravel z kolejkami i cache wystarcza z zapasem. Są jednak miejsca, w których liczy się każda milisekunda i każde żądanie na sekundę: przyjmowanie dużego strumienia zdarzeń, obliczenia na dużych zbiorach danych, API odpytywane tysiące razy na minutę. Tam stawiamy osobne usługi w Rust.
Rust obok Laravela, nie zamiast niego
Nie przepisujemy całego systemu. Główna aplikacja zostaje w Laravelu, gdzie najszybciej dowozimy logikę biznesową, panele i integracje. Wąskie gardło wydzielamy do osobnej usługi w Rust, która komunikuje się z resztą przez API albo kolejkę (RabbitMQ, Kafka) i korzysta z tej samej bazy PostgreSQL.
Nasz stack w Rust
- Axum — asynchroniczny framework HTTP do budowy szybkich API.
- SeaORM — warstwa dostępu do danych w PostgreSQL.
- Asynchroniczne przetwarzanie — obsługa wielu jednoczesnych połączeń i strumieni zdarzeń przy niskim zużyciu pamięci.
- Docker i CI — usługi wdrażamy tak samo jak resztę systemu, z testami przy każdym pull requeście i monitoringiem na produkcji (zobacz DevOps i utrzymanie serwerów).
Co daje Rust w takich usługach
- Przewidywalne opóźnienia — brak garbage collectora oznacza brak nagłych przestojów pod obciążeniem.
- Niskie zużycie pamięci i CPU — ta sama praca na mniejszych serwerach, co przy stałym, dużym ruchu przekłada się na niższe rachunki za infrastrukturę.
- Bezpieczeństwo pamięci — kompilator wyłapuje całe klasy błędów, które w innych językach wychodzą dopiero na produkcji.
- Jeden plik wykonywalny — usługa w Rust to mały obraz Dockera bez zależności uruchomieniowych, łatwy do wdrożenia i skalowania.
Kiedy Rust ma sens
- endpoint lub proces, który po optymalizacji w PHP nadal jest wąskim gardłem,
- przetwarzanie dużych strumieni danych, np. z urządzeń IoT albo systemów zdarzeniowych,
- usługi, w których koszt serwerów rośnie szybciej niż ruch.
Jak wygląda wydzielenie usługi
Zaczynamy od pomiaru: które żądania albo procesy są wolne i dlaczego. Jeśli problem da się rozwiązać w istniejącej aplikacji, robimy to tam. Jeśli nie, projektujemy usługę z jasno określonym kontraktem (API albo format komunikatów w kolejce), piszemy ją w Rust, testujemy pod obciążeniem narzędziem k6 i wdrażamy obok istniejącego systemu. Ruch przełączamy stopniowo, więc w razie problemu można wrócić do poprzedniej ścieżki.
Zanim zaproponujemy Rust, sprawdzamy, czy problemu nie rozwiąże optymalizacja istniejącej aplikacji — indeksy, cache, kolejki albo Laravel Octane. Dopiero gdy to nie wystarcza, wydzielamy usługę. Więcej o stacku, w którym powstaje główna aplikacja, na stronie Laravel.
Najczęściej zadawane pytania
Czy muszę przepisać aplikację na Rust, żeby była szybsza?
Nie. Najpierw szukamy wąskiego gardła i optymalizujemy istniejący kod. Rust stosujemy punktowo, jako osobną usługę obok głównej aplikacji.
Jak usługa w Rust komunikuje się z aplikacją w Laravelu?
Przez API HTTP albo kolejkę komunikatów (RabbitMQ, Kafka). Obie aplikacje mogą korzystać z tej samej bazy PostgreSQL.
Kto utrzymuje usługę w Rust po wdrożeniu?
My, w ramach tego samego utrzymania co resztę systemu: monitoring, aktualizacje i rozwój. Kod i dostępy są Twoje.
Czy cała aplikacja webowa może być napisana w Rust?
Może, ale rzadko się to opłaca. Panele, formularze, uprawnienia i integracje szybciej i taniej powstają w Laravelu, a ich wydajność zwykle wystarcza z zapasem. Rust zostawiamy na te fragmenty systemu, w których naprawdę liczy się przepustowość.
Skąd wiadomo, że usługa w Rust faktycznie pomogła?
Przed zmianą i po niej mierzymy to samo: czas odpowiedzi, liczbę obsłużonych żądań i zużycie zasobów, a usługę testujemy pod obciążeniem w k6. Wynik porównujemy z pomiarem wyjściowym, zanim przełączymy na nią cały ruch.