w , ,

Tomcat vs Jetty vs Netty – Różnice w Obsłudze Żądań i Zarządzaniu Wątkami

Wydajność Twojej aplikacji nie zależy wyłącznie od kodu – kluczowy jest sposób, w jaki kontener webowy zarządza żądaniami i wątkami.

Przybliżę Ci różnice między Tomcatem, Jetty i Netty – trzema popularnymi serwerami, które znacząco różnią się podejściem do obsługi ruchu.

🔍Tomcat – klasyczny model blokujący

Tomcat to najbardziej rozpowszechniony serwer aplikacyjny w ekosystemie Java.

Domyślnie: Tomcat konfiguruje pulę 200 wątków roboczych (maxThreads=200). Każde przychodzące żądanie HTTP przypisuje do wolnego wątku.

Parametry zarządzania wątkami:

  • maxThreads – maksymalna liczba wątków, które mogą równocześnie obsługiwać przychodzące żądania HTTP. Gdy liczba żądań przekracza tę wartość, kolejne trafiają do kolejki oczekujących.
    🔹 Domyślnie: 200.
  • minSpareThreads – minimalna liczba wątków utrzymywanych w stanie gotowości, nawet gdy są bezczynne. Dzięki temu serwer może szybko zareagować na nowe żądania bez konieczności tworzenia wątków „na żądanie”. Pozostałe wątki pozostają w puli w stanie bezczynności (aby nie zużywać niepotrzebnie zasobów), gotowe do ponownego użycia.
    🔹 Domyślnie: 10.
  • acceptCount – maksymalna liczba żądań, które mogą oczekiwać w kolejce, gdy wszystkie maxThreads są zajęte. Jeśli limit ten zostanie przekroczony (np. 200 aktywnych wątków + 100 w kolejce), każde kolejne żądanie (np. 301.) zostaje odrzucone, co skutkuje błędem lub timeoutem.
    🔹 Domyślnie: 100.

Jak działa request flow:

  1. Klient wysyła request (np. GET /users/1).
  2. Gniazdo (socket) akceptowane jest przez AcceptorThread.
  3. Trafia do Executor, który pobiera wątek z puli.
  4. Wątek obsługuje request: np. odczytuje dane z DB, renderuje widok.
  5. Odpowiedź wysyłana, wątek wraca do puli.

🔴 Jeśli wszystkie 200 wątków są zajęte – kolejne requesty czekają w kolejce (acceptCount=100), a potem… są odrzucane.

🌀 Jetty – lekki i elastyczny serwer

Jetty również operuje na modelu wątków per request, ale z bardziej elastyczną konfiguracją i mniejszym narzutem. Jest częściej używany tam, gdzie liczy się niska latencja i możliwość dostosowania.

Jetty pozwala też na konfigurację hybrydową – częściowo nieblokującą, dzięki adnotacji @WebServlet(asyncSupported = true) oraz metodzie startAsync().

Nie jest to jednak pełnoprawny reactive stack – nadal sporo zależy od architektury Twojej aplikacji.

Jak działa request flow w Jetty (blokująco):

  1. Request trafia do QueuedThreadPool.
  2. Wątek obsługuje całość, analogicznie do Tomcat.
  3. Możliwość ręcznego „zawieszenia” przetwarzania i zwolnienia wątku (startAsync()).

Z asynchronicznym API:

  • Wątek może wrócić do puli zanim response zostanie wygenerowany.
  • Odpowiedź może być przekazana np. przez callback lub event.

✅ Jetty lepiej znosi bursty i scenariusze WebSocketowe, choć nadal to nie w pełni reaktywny model.

⚡Netty – w pełni asynchroniczny, event-driven

Netty działa na zupełnie innym poziomie. Netty nie oferuje gotowego serwera HTTP jak Tomcat czy Jetty – zamiast tego udostępnia niskopoziomowy model, który pozwala zbudować serwer HTTP z pełną kontrolą nad ruchem i zdarzeniami sieciowymi.

Netty działa w modelu Event Loop. Domyślnie ma:

  • 1–2 wątki akceptujące – boss group (domyślnie 1),
  • liczba rdzeni CPU × 2 wątków przetwarzających (worker group).

Jak dział request flow:

  1. Połączenie akceptowane przez bossGroup.
  2. Trafia do workerGroup, gdzie zarządzane jest przez selektory.
  3. Wszystko przetwarzane asynchronicznie, przez zdarzenia (channelRead, write, flush, itd.) a dane przekazywane są w postaci obiektów Netty (np. ByteBuf, FullHttpRequest).
  4. Callbacki reagują na zakończenie operacji (np. dostęp do bazy przez CompletableFuture lub Mono).

✅ Jeden wątek Netty może obsłużyć tysiące połączeń, bo nie blokuje IO.

📊 Porównanie: obsługa wątków i przetwarzanie

CechaTomcatJettyNetty
ModelBlokującyBlokujący / HybrydowyW pełni nieblokujący
Wątek per requestTakTak (z opcją async)Nie – Event Loop
Domyślna pula wątków200 (maxThreads)250 (QueuedThreadPool)2 × liczba dostępnych rdzeni CPU + 1 bossGroup
SkalowalnośćOgraniczona pulą wątkówŚrednia, ale lepsza od TomcatWysoka
KonfiguracjaProstaElastycznaZłożona, niskopoziomowa (Spring Boot zapewnia konfiguracje za nas)
Idealny use caseKlasyczne aplikacje weboweLightweight REST, WebSocketReactive, event-driven apps

🎯Kiedy wybrać który?

Tomcat i Jetty to świetne rozwiązania dla klasycznych aplikacji – łatwe w konfiguracji, sprawdzone. Ale w sytuacji, gdy liczba requestów rośnie wykładniczo, wątek per request przestaje być opłacalny.

Netty oferuje zupełnie inny poziom: w pełni reaktywna obsługa, która minimalizuje zużycie zasobów. Wymaga jednak więcej wysiłku – zarówno od strony konfiguracyjnej jak i zasad implementacji rozwiązania, które na nim działa.

🔹 Tomcat – dla większości klasycznych aplikacji Spring MVC, kiedy nie przewidujesz gigantycznego ruchu.

🔹 Jetty – gdy chcesz więcej kontroli i elastyczności przy mniejszym narzucie, np. w microservices.

🔹 Netty – jeśli tworzysz system wymagający maksymalnej wydajności i kontroli nad ruchem – API gateway, serwer HTTP/2, websockety, broker wiadomości.

Co z wirtualnymi wątkami?

Od JDK 21 wchodzą w grę wirtualne wątki (Project Loom) – przełom, który może zmienić podejście do serwerów opartych na wątkach per request. Umożliwiają one obsługę milionów requestów bez zmiany architektury na reaktywną.

Ważne – wirtualne wątki zmieniają model wykonania, ale nie rozwiązują wszystkiego – nadal wymagają przemyślanej współpracy z blokującymi zasobami (np. I/O, bazy danych).

🎬 Zobacz, jak wirtualne wątki przyspieszają aplikacje – pełne szkolenie!

Sprawdź mój materiał na YouTube, w którym krok po kroku pokazuję, jak uruchomić wirtualne wątki w Spring Boot. Live coding, praktyczne przykłady i porównanie wydajności – wszystko, czego potrzebujesz, aby wynieść swoje API na wyższy poziom!

Napisane przez Przemysław Bykowski

Aktywny programista i energiczny trener. Specjalizuje się w Spring Boot i uczę go w ramach AkademiaSpring.pl. Po godzinach udzielam się na YouTubach. Więcej o mnie.

Dodaj komentarz

Test-driven development

Dlaczego TDD Jest Zgubne i Traci Na Znaczeniu?

ci-cd

CI/CD dla Java Developerów w GitLabie – Kompletny Scenariusz w 6 Krokach