Usługi

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.