WebFlux ve Event Loop — Bloklayan Tek Satır Neyi Durdurur?
Önce şunu oku: Virtual Threads vs Platform Threads , @Async ve Thread Havuzu — Max Neden Hiç Dolmuyor?
30 saniyede özet
WebFlux birkaç işçiyle binlerce isteği taşıyabilir, ama yalnızca hiçbir işçi bir yerde beklemediği sürece. Tek bir bekleyen veritabanı çağrısı herkesi durdurur. Bekleyen kodun çoksa virtual thread daha basit bir yoldur.
Dört garsonlu bir restoran kırk masaya yetişebilir; yeter ki hiçbir garson mutfak kapısında beklemesin.
-
Bayt: Servisi WebFlux'a taşıdık. Birkaç thread, binlerce istek!
-
Sen: Yük testi nasıl geçti?
-
Bayt: Tuhaf: işlemci neredeyse boştu, ama her şey durmuştu.
-
Bayt: Dört garsonlu restoranda garsonlar mutfak kapısında beklemeye başlarsa ne olur?
Servis WebFlux’a taşındı ve ilk yük testinde tuhaf bir şey oldu: işlemci neredeyse boşken uygulama tıkandı.
İki farklı garson
Spring MVC her isteğe bir thread verir. Thread, aşağı akış cevabını beklerken de o isteğe bağlı kalır.
WebFlux’ta az sayıda event loopAz sayıda thread'in, beklemeden olaydan olaya geçerek çok sayıda bağlantıyı taşıdığı model. WebFlux'ta Reactor Netty çekirdek başına bir loop kullanır.Sözlükte gör → thread’i vardır, genellikle çekirdek sayısı kadar. Beklemezler: isteği bir non-blocking I/OCevap beklenirken thread'i tutmayan G/Ç. Thread başka işe geçer, cevap gelince bir geri çağrı ya da sinyal işi sürdürür. WebClient ve R2DBC böyledir; JDBC değildir.Sözlükte gör → çağrısına bırakır ve cevap gelince devam ederler.
Kafam karıştı, daha basit anlat
MVC’de her masaya bir garson düşer, mutfak beklenirken garson masada durur. WebFlux’ta birkaç garson vardır, siparişi mutfağa verip hemen başka masaya geçerler.
Spring MVC ile WebFlux arasındaki temel fark hangisi?
Aşağıdaki kod çalıştırılınca ne olur? Mono<Order> order = orderClient.fetch(id); log.info("hazır");
Bir garson beklerse
WebFlux, 4 event loop. Her istek JPA ile bir sorgu yapıyor ve 12 istek aynı anda geldi. /actuator/health ne yapar? Cevabı göster
Bekler. JDBC bloklayan bir çağrıdır: event loop thread’i sorgu bitene kadar durur. Dört sorgu dört loop’u tutar; health probe da sırasını bekler.
Adım adım oku
- Dört event loop thread'i, dört garson gibi, çok sayıda isteğe hızla hizmet eder; kimse beklemez.
- Her istek bloklayan bir JPA sorgusu yapınca garsonların dördü de mutfak kapısında beklemeye başlar.
- Artık hiçbir masa, sağlık kontrolü bile, cevap alamaz; Kubernetes pod'u ölü sanar.
- Bloklayan iş boundedElastic gibi ayrı bir ekibe verilince garsonlar masalara döner.
MVC’de bloklamak bir thread’i tutar. WebFlux’ta ise yüzlerce isteği taşıyan bir loop’u durdurur. Bu yüzden bloklayan kod WebFlux’ta MVC’dekinden daha pahalıdır.
Kaçınılmaz bir bloklayan çağrı Mono.fromCallable(...) ile sarılır ve subscribeOn(Schedulers.boundedElastic()) ile ayrı, sınırlı bir havuza gönderilir.
Kafam karıştı, daha basit anlat
WebFlux garsonlarından biri mutfağın önünde beklemeye başlarsa, onun baktığı bütün masalar da bekler. Bu yüzden orada bekleyen kod çok daha pahalıdır.
WebFlux controller'ında JPA repository'si ile veritabanı sorgusu yapıldı. Yük altında /actuator/health bile timeout alıyor. Neden?
WebFlux uygulamasında, bloklamayan bir alternatifi olmayan eski bir SOAP istemcisini çağırman gerekiyor. Doğru yol hangisi?
Kendin gör
Event loop'u kim durdurdu?
Tohum 470156Event loop thread'leri
Henüz istek yok.
Biten istek: 0/12
Oynat ya da adımla.
Şu an ne oldu?
WebFlux (4 event loop)
Her istek bir kez aşağı akış servisini bekliyor. Beklerken thread'i kim tutuyor?
Görevler0/3
Health probe'u event loop'ta takılı bırakaçık
İpucu
WebFlux'ta JDBC çağır.
Bloklayan kodu WebFlux'ta tek turda bitiraçık
İpucu
İşi event loop'tan başka bir havuza gönder.
Bloklayan kodu reaktif yazmadan tek turda bitiraçık
İpucu
MVC'de kalıp thread türünü değiştir.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. WebFlux + JDBC: üç tur, health probe takıldı.
- “subscribeOn(boundedElastic)“i aç. Tek tur, loop’lar serbest.
- Offload’u kapat, çağrıyı “Bloklamayan” yap. Tek tur, 4 thread 12 isteği taşıdı.
- Yığını “MVC (8 platform thread)” yap, çağrıyı “Bloklayan” yap. Havuz doldu.
- “MVC + virtual thread” seç. Aynı bloklayan kod, tek tur.
Bu WebFlux uç noktası ilk istekte 'block() are blocking, which is not supported in thread reactor-http-nio-2' hatası veriyor. Hatalı satır hangisi?
Her servisi, en uygun yığına göre ayır.
Tuzaklar
Tembel zincir. Mono biri subscribe olana kadar çalışmaz. Controller zinciri döndürmeli; ortada .subscribe() çağırmak hataları kaybettirir.
Mono ile sarılmış JPA. İmza reaktif görünür, altındaki JDBC yine bloklar. Uçtan uca reaktif için R2DBC gerekir.
ThreadLocal bağlam. MDC ve SecurityContextHolder thread’e bağlıdır; reaktif zincir thread değiştirir. Reactor Context ve context-propagation kullanılır.
Yanlış sebeple geçiş. Thread havuzu doluyorsa önce virtual thread’leri dene. WebFlux’un asıl kazancı gateway’ler, uzun bağlantılar ve backpressure isteyen akışlardır.
Kafam karıştı, daha basit anlat
Mono bir tariftir, yemeğin kendisi değil. Biri “pişir” diyene kadar hiçbir şey olmaz.
WebFlux'a geçtikten sonra log'larda traceId ve kullanıcı id'si rastgele eksik ya da yanlış görünüyor. Neden?
Aşağıdaki örnek bir bankanın mobil uygulamasının açılış ekranından; WebFlux uç noktası uçtan uca bloklamadan kuruluyor. Kaçınılmaz tek bloklayan çağrı ayrı havuza gönderiliyor, test de event loop’ta bloklamayı yakalıyor.
Derinleş · Mobil bankacılık hesap özeti: uçtan uca reaktif 6 dosya · ~110 satır · ilk okumada atlayabilirsin
Kendini sına
WebFlux'ta birkaç event loop thread'i çok sayıda isteği taşıyabilir.
JPA kullanan, bloklayan bir MVC servisi yüksek eşzamanlılıkta thread havuzunu dolduruyor. WebFlux'a geçmek yerine ilk denenecek şey ne olmalı?
Aklında kalacak üç şey
- 1 WebFlux'ta birkaç event loop thread'i bütün istekleri taşır. Birini bekletmek, o thread'deki her isteği durdurur.
- 2 Bekleyen bir çağrı kaçınılmazsa subscribeOn(Schedulers.boundedElastic()) ile ayrı bir havuza gönderilir.
- 3 Bekleyen kütüphanelerle çalışan bir servis için virtual thread, her şeyi reaktif yeniden yazmaktan ucuzdur. WebFlux'un asıl kazancı baştan sona beklemeyen akışlardadır.
5 kart sonraki derste seni bekliyor