paint-brush
Spring WebFlux İş Parçacığı Modeline Girişile@vladimirf
16,383 okumalar
16,383 okumalar

Spring WebFlux İş Parçacığı Modeline Giriş

ile Vladimir Filipchenko7m2023/04/30
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Spring WebFlux, Java'da reaktif programlamayı uygulamak için Reactor kitaplığını kullanan, reaktif, engellemeyen bir web çerçevesidir. WebFlux'un iş parçacığı modeli, birçok eşzamanlı web çerçevesinde kullanılan geleneksel istek başına iş parçacığı modelinden farklıdır. WebFlux, az sayıda iş parçacığının çok sayıda isteği karşılayabildiği, engellemeyen, olaya dayalı bir model kullanır. Bu, görevler arka planda yürütülürken iş parçacığının diğer istekleri işlemeye devam etmesine olanak tanır. Paralel zamanlayıcı kullanmak, birden fazla görevin farklı iş parçacıklarında aynı anda yürütülmesine izin vererek performansı ve ölçeklenebilirliği artırabilir.
featured image - Spring WebFlux İş Parçacığı Modeline Giriş
Vladimir Filipchenko HackerNoon profile picture
0-item

Spring WebFlux, Java'da modern, ölçeklenebilir web uygulamaları oluşturmaya yönelik reaktif, engellemeyen bir web çerçevesidir. Spring Framework'ün bir parçasıdır ve Java'da reaktif programlamayı uygulamak için Reactor kütüphanesini kullanır.


WebFlux ile çok sayıda eş zamanlı isteği ve veri akışını işleyebilen yüksek performanslı, ölçeklenebilir web uygulamaları oluşturabilirsiniz. Basit REST API'lerinden gerçek zamanlı veri akışına ve sunucu tarafından gönderilen olaylara kadar çok çeşitli kullanım örneklerini destekler.


Spring WebFlux, reaktif akışlara dayalı bir programlama modeli sağlar; bu, eş zamanlı olmayan ve engellemeyen işlemleri veri işleme aşamalarından oluşan bir işlem hattında birleştirmenize olanak tanır. Ayrıca reaktif veri erişimi, reaktif güvenlik ve reaktif test desteği de dahil olmak üzere reaktif web uygulamaları oluşturmaya yönelik zengin bir dizi özellik ve araç sağlar.


Resmi Bahar belgesinden :

"Reaktif" terimi, G/Ç olaylarına tepki veren ağ bileşenleri, fare olaylarına tepki veren kullanıcı arayüzü denetleyicileri ve diğerleri gibi değişime tepki verme etrafında oluşturulan programlama modellerini ifade eder. Bu anlamda engellememe tepkiseldir, çünkü artık engellenmek yerine, işlemler tamamlandığında veya veriler kullanılabilir hale geldikçe bildirimlere tepki verme modundayız.

Diş açma modeli

Reaktif programlamanın temel özelliklerinden biri, birçok eşzamanlı web çerçevesinde kullanılan geleneksel istek başına iş parçacığı modelinden farklı olan iş parçacığı modelidir.


Geleneksel modelde, gelen her isteği işlemek için yeni bir iş parçacığı oluşturulur ve bu iş parçacığı, istek işlenene kadar engellenir. Bu, yüksek hacimli isteklerle uğraşırken ölçeklenebilirlik sorunlarına yol açabilir; istekleri işlemek için gereken iş parçacığı sayısı çok artabilir ve iş parçacığı bağlamı değiştirme bir darboğaz haline gelebilir.


Buna karşılık WebFlux, az sayıda iş parçacığının çok sayıda isteği karşılayabildiği, engellemeyen, olaya dayalı bir model kullanır. Bir istek geldiğinde, mevcut iş parçacıklarından biri tarafından işlenir ve bu iş parçacığı daha sonra gerçek işlemeyi bir dizi eşzamansız göreve devreder. Bu görevler engelleyici olmayan bir şekilde yürütülür ve görevler arka planda yürütülürken iş parçacığının diğer istekleri işlemeye devam etmesine olanak tanır.


Spring WebFlux'ta (ve genel olarak engellemeyen sunucularda), uygulamaların engellemediği varsayılır. Bu nedenle, engellemeyen sunucular, istekleri işlemek için küçük, sabit boyutlu bir iş parçacığı havuzu (olay döngüsü çalışanları) kullanır.


Klasik bir Servlet Container'ın basitleştirilmiş iş parçacığı modeli şuna benzer:

WebFlux istek işleme biraz farklı olsa da:

Kaputun altında

Devam edelim ve parlak teorinin arkasında ne olduğunu görelim.

Spring Initializr tarafından oluşturulan oldukça minimalist bir uygulamaya ihtiyacımız var. Kod GitHub deposunda mevcuttur.


İş parçacığıyla ilgili tüm konular CPU'ya oldukça bağımlıdır. Genellikle istekleri işleyen işlem parçacıklarının sayısı CPU çekirdeği sayısıyla ilişkilidir . Eğitim amaçlı olarak, Docker kapsayıcısını çalıştırırken CPU'ları sınırlayarak bir havuzdaki iş parçacığı sayısını kolayca değiştirebilirsiniz:

 docker run --cpus=1 -d --rm --name webflux-threading -p 8081:8080 local/webflux-threading

Bir havuzda hâlâ birden fazla iş parçacığı görüyorsanız sorun değil. WebFlux tarafından belirlenen varsayılanlar olabilir.

Uygulamamız basit bir falcıdır. /karma endpoint'i çağırdığınızda, balanceAdjustment ile 5 kayıt alacaksınız. Her ayarlama, size verilen karmayı temsil eden bir tam sayıdır. Evet, çok cömertiz çünkü uygulama yalnızca pozitif sayılar üretiyor. Artık kötü şans yok!

Varsayılan işleme

Çok basit bir örnekle başlayalım. Sonraki denetleyici yöntemi, 5 karma öğesi içeren bir Flux döndürür.


 @GetMapping("/karma") public Flux<Karma> karma() { return prepareKarma() .map(Karma::new) .log(); } private Flux<Integer> prepareKarma() { Random random = new Random(); return Flux.fromStream( Stream.generate(() -> random.nextInt(10)) .limit(5)); }


log yöntemi burada çok önemli bir şeydir. Tüm Reaktif Akış sinyallerini gözlemler ve bunları INFO düzeyindeki günlüklere kadar takip eder.


curl localhost:8081/karma günlük çıktısı aşağıdaki gibidir:


Görebildiğimiz gibi, IO iş parçacığı havuzunda işlem yapılıyor. Konu adı ctor-http-nio-2 reactor-http-nio-2 anlamına gelir. Görevler, onları gönderen iş parçacığında hemen yürütüldü. Reactor bunları başka bir havuza planlamak için herhangi bir talimat görmedi.

Geciktirme ve paralel işleme

Bir sonraki işlem, yayılan her öğeyi 100 ms geciktirecek (diğer bir deyişle veritabanı emülasyonu)


 @GetMapping("/delayedKarma") public Flux<Karma> delayedKarma() { return karma() .delayElements(Duration.ofMillis(100)); }


Orijinal karma() çağrısında zaten bildirilmiş olduğundan buraya log yöntemini eklememize gerek yok.


Günlüklerde bir sonraki resmi görebiliriz:


Bu sefer IO iplik reactor-http-nio-4 yalnızca ilk eleman alındı. Geri kalan 4'ünün işlenmesi parallel bir iş parçacığı havuzuna ayrıldı.


delayElements Javadoc'u bunu doğrular:

Sinyaller geciktirilir ve paralel varsayılan Zamanlayıcıda devam eder


Çağrı zincirinin herhangi bir yerinde .subscribeOn(Schedulers.parallel()) komutunu belirterek aynı etkiyi gecikmeden elde edebilirsiniz.


parallel zamanlayıcının kullanılması, birden fazla görevin farklı iş parçacıklarında aynı anda yürütülmesine izin vererek performansı ve ölçeklenebilirliği artırabilir; bu, CPU kaynaklarını daha iyi kullanabilir ve çok sayıda eşzamanlı isteği işleyebilir.


Bununla birlikte, kod karmaşıklığını ve bellek kullanımını da artırabilir ve maksimum çalışan iş parçacığı sayısı aşılırsa potansiyel olarak iş parçacığı havuzunun tükenmesine yol açabilir. Bu nedenle parallel iş parçacığı havuzunu kullanma kararı, uygulamanın özel gereksinimlerine ve değiş tokuşlarına dayanmalıdır.


Alt zincir

Şimdi daha karmaşık bir örneğe bakalım. Kod hala oldukça basit ve anlaşılır ancak çıktı çok daha ilginç.


flatMap kullanacağız ve falcıyı daha adil hale getireceğiz. Her Karma örneği için, orijinal ayarlamayı 10 ile çarpacak ve zıt ayarlamaları üreterek, orijinali telafi eden dengeli bir işlemi etkili bir şekilde yaratacaktır.


 @GetMapping("/fairKarma") public Flux<Karma> fairKarma() { return delayedKarma() .flatMap(this::makeFair); } private Flux<Karma> makeFair(Karma original) { return Flux.just(new Karma(original.balanceAdjustment() * 10), new Karma(original.balanceAdjustment() * -10)) .subscribeOn(Schedulers.boundedElastic()) .log(); }


Gördüğünüz gibi makeFair's Flux'u boundedElastic bir Elastik iş parçacığı havuzuna abone olmalıdır. İlk iki Karma için kayıtlarımızda neler olduğuna bir göz atalım:


  1. Reactor, IO iş parçacığındabalanceAdjustment balanceAdjustment=9 ile ilk öğeye abone olur


  2. Daha sonra, boundedElastic havuzu boundedElastic-1 iş parçacığında 90 ve -90 ayarlamalar yayarak Karma adaleti üzerinde çalışır


  3. İlkinden sonraki öğeler paralel iş parçacığı havuzuna abone olur (çünkü zincirde hâlâ delayedElements öğeler var)


boundedElastic zamanlayıcı nedir ?

İş yüküne bağlı olarak çalışan iş parçacıklarının sayısını dinamik olarak ayarlayan bir iş parçacığı havuzudur. Veritabanı sorguları ve ağ istekleri gibi G/Ç bağlantılı görevler için optimize edilmiştir ve çok fazla iş parçacığı oluşturmadan veya kaynak israfına yol açmadan çok sayıda kısa süreli görevi gerçekleştirecek şekilde tasarlanmıştır.


Varsayılan olarak, boundedElastic iş parçacığı havuzunun maksimum boyutu, kullanılabilir işlemci sayısının 10 ile çarpılmasıyla bulunur , ancak gerekirse farklı bir maksimum boyut kullanacak şekilde yapılandırabilirsiniz.


boundedElastic gibi eşzamansız bir iş parçacığı havuzu kullanarak, iş parçacıklarını ayırmak için görevleri boşaltabilir ve diğer istekleri işlemek için ana iş parçacığını serbest bırakabilirsiniz. İş parçacığı havuzunun sınırlı yapısı, iş parçacığı açlığını ve aşırı kaynak kullanımını önleyebilir; havuzun esnekliği ise iş yüküne bağlı olarak çalışan iş parçacığı sayısını dinamik olarak ayarlamasına olanak tanır.


Diğer iş parçacığı havuzu türleri

Kullanıma hazır Scheduler sınıfı tarafından sağlanan iki tür havuz daha vardır:


  • single : Bu, eşzamanlı yürütme için tasarlanmış tek iş parçacıklı, serileştirilmiş bir yürütme bağlamıdır. Bir görevin sırayla yürütüldüğünden ve iki görevin aynı anda yürütülmediğinden emin olmanız gerektiğinde kullanışlıdır.


  • immediate : Bu, herhangi bir iş parçacığı değişimi olmadan çağıran iş parçacığında görevleri hemen yürüten bir zamanlayıcının önemsiz, işlemsiz bir uygulamasıdır.


Çözüm

Spring WebFlux'taki iş parçacığı modeli, engellemesiz ve eşzamansız olacak şekilde tasarlanmıştır ve minimum kaynak kullanımıyla çok sayıda isteğin verimli bir şekilde işlenmesine olanak tanır. WebFlux, bağlantı başına özel iş parçacıklarına güvenmek yerine, gelen istekleri işlemek ve işi çeşitli iş parçacığı havuzlarından çalışan iş parçacıklarına dağıtmak için az sayıda olay döngüsü iş parçacığı kullanır.


Ancak iş parçacığının tükenmesini önlemek ve sistem kaynaklarının verimli kullanımını sağlamak için kullanım durumunuz için doğru iş parçacığı havuzunu seçmeniz önemlidir.