.Net 4.5'ten gelen async HttpClient, yoğun yük uygulamaları için kötü bir seçim mi?


130

Kısa bir süre önce, klasik bir çok iş parçacıklı yaklaşıma kıyasla zaman uyumsuz bir şekilde üretilebilen HTTP çağrı verimini test etmek için basit bir uygulama oluşturdum.

Uygulama, önceden tanımlanmış sayıda HTTP çağrısı gerçekleştirebilir ve sonunda bunları gerçekleştirmek için gereken toplam süreyi görüntüler. Testlerim sırasında, tüm HTTP çağrıları yerel IIS sunucuma yapıldı ve küçük bir metin dosyası (boyut olarak 12 bayt) aldılar.

Eşzamansız uygulama için kodun en önemli kısmı aşağıda listelenmiştir:

public async void TestAsync()
{
    this.TestInit();
    HttpClient httpClient = new HttpClient();

    for (int i = 0; i < NUMBER_OF_REQUESTS; i++)
    {
        ProcessUrlAsync(httpClient);
    }
}

private async void ProcessUrlAsync(HttpClient httpClient)
{
    HttpResponseMessage httpResponse = null;

    try
    {
        Task<HttpResponseMessage> getTask = httpClient.GetAsync(URL);
        httpResponse = await getTask;

        Interlocked.Increment(ref _successfulCalls);
    }
    catch (Exception ex)
    {
        Interlocked.Increment(ref _failedCalls);
    }
    finally
    { 
        if(httpResponse != null) httpResponse.Dispose();
    }

    lock (_syncLock)
    {
        _itemsLeft--;
        if (_itemsLeft == 0)
        {
            _utcEndTime = DateTime.UtcNow;
            this.DisplayTestResults();
        }
    }
}

Çoklu okuma uygulamasının en önemli kısmı aşağıda listelenmiştir:

public void TestParallel2()
{
    this.TestInit();
    ServicePointManager.DefaultConnectionLimit = 100;

    for (int i = 0; i < NUMBER_OF_REQUESTS; i++)
    {
        Task.Run(() =>
        {
            try
            {
                this.PerformWebRequestGet();
                Interlocked.Increment(ref _successfulCalls);
            }
            catch (Exception ex)
            {
                Interlocked.Increment(ref _failedCalls);
            }

            lock (_syncLock)
            {
                _itemsLeft--;
                if (_itemsLeft == 0)
                {
                    _utcEndTime = DateTime.UtcNow;
                    this.DisplayTestResults();
                }
            }
        });
    }
}

private void PerformWebRequestGet()
{ 
    HttpWebRequest request = null;
    HttpWebResponse response = null;

    try
    {
        request = (HttpWebRequest)WebRequest.Create(URL);
        request.Method = "GET";
        request.KeepAlive = true;
        response = (HttpWebResponse)request.GetResponse();
    }
    finally
    {
        if (response != null) response.Close();
    }
}

Testleri çalıştırmak, çok iş parçacıklı sürümün daha hızlı olduğunu ortaya çıkardı. 10.000 istek için tamamlanması yaklaşık 0.6 saniye sürerken, zaman uyumsuz olanın aynı miktarda yükleme için tamamlanması yaklaşık 2 saniye sürdü. Bu biraz şaşırtıcıydı, çünkü asenkron olanın daha hızlı olmasını bekliyordum. Belki de HTTP aramalarımın çok hızlı olmasından kaynaklanıyordu. Sunucunun daha anlamlı bir işlem gerçekleştirmesi gereken ve ayrıca bir miktar ağ gecikmesi olması gereken gerçek dünya senaryosunda, sonuçlar tersine çevrilebilir.

Bununla birlikte, beni gerçekten endişelendiren, HttpClient'in yük arttığında nasıl davranacağıdır. 10.000 mesaj iletmek yaklaşık 2 saniye sürdüğü için, mesaj sayısının 10 katı kadar mesaj göndermenin yaklaşık 20 saniye süreceğini düşündüm, ancak testi çalıştırmak, 100.000 mesajı iletmek için yaklaşık 50 saniyeye ihtiyacı olduğunu gösterdi. Ayrıca, 200.000 mesajın teslim edilmesi genellikle 2 dakikadan uzun sürer ve genellikle birkaç bin mesaj (3-4k) aşağıdaki istisna dışında başarısız olur:

Bir soket üzerinde işlem, sistemde yeterli arabellek alanı olmadığından veya bir kuyruk dolu olduğundan gerçekleştirilemedi.

IIS günlüklerini kontrol ettim ve başarısız olan işlemler sunucuya hiç ulaşmadı. Müşteri içinde başarısız oldular. Testleri, varsayılan geçici bağlantı noktası aralığı 49152 ila 65535 olan bir Windows 7 makinesinde çalıştırdım. Netstat'ı çalıştırmak, testler sırasında yaklaşık 5-6 bin bağlantı noktasının kullanıldığını gösterdi, bu nedenle teoride çok daha fazla kullanılabilir olması gerekirdi. Bağlantı noktalarının olmaması gerçekten istisnaların nedeni ise, bu, ya netstat'ın durumu düzgün bir şekilde rapor etmediği ya da HttClient'in yalnızca maksimum sayıda bağlantı noktası kullandığı ve ardından istisnaları atmaya başladığı anlamına gelir.

Bunun tersine, HTTP çağrıları oluşturmanın çok iş parçacıklı yaklaşımı oldukça tahmin edilebilir davrandı. 10.000 mesaj için yaklaşık 0.6 saniye, 100.000 mesaj için yaklaşık 5.5 saniye ve 1 milyon mesaj için yaklaşık 55 saniye bekledim. Mesajların hiçbiri başarısız oldu. Dahası, çalışırken hiçbir zaman 55 MB'den fazla RAM kullanmadı (Windows Görev Yöneticisine göre). Eşzamansız olarak mesaj gönderirken kullanılan bellek, yük ile orantılı olarak büyüdü. 200k mesaj testleri sırasında yaklaşık 500 MB RAM kullandı.

Yukarıdaki sonuçların iki ana nedeni olduğunu düşünüyorum. Birincisi, HttpClient'in sunucuyla yeni bağlantılar oluşturmada çok açgözlü görünmesi. Netstat tarafından bildirilen çok sayıda kullanılan bağlantı noktası, HTTP'nin canlı tutma özelliğinden büyük olasılıkla yararlanmadığı anlamına gelir.

İkincisi, HttpClient'in bir azaltma mekanizmasına sahip olmadığıdır. Aslında bu, zaman uyumsuz işlemlerle ilgili genel bir sorun gibi görünüyor. Çok fazla sayıda işlem yapmanız gerekiyorsa, bunların tümü aynı anda başlatılacak ve mevcut olduklarında devamları yürütülecektir. Teoride bu tamam olmalıdır, çünkü asenkron işlemlerde yük harici sistemlerdedir, ancak yukarıda kanıtlandığı gibi durum tamamen böyle değildir. Aynı anda çok sayıda isteğin başlatılması, bellek kullanımını artıracak ve tüm yürütmeyi yavaşlatacaktır.

Basit ama ilkel bir gecikme mekanizmasıyla maksimum eşzamansız istek sayısını sınırlayarak daha iyi sonuçlar, bellek ve yürütme süresi elde etmeyi başardım:

public async void TestAsyncWithDelay()
{
    this.TestInit();
    HttpClient httpClient = new HttpClient();

    for (int i = 0; i < NUMBER_OF_REQUESTS; i++)
    {
        if (_activeRequestsCount >= MAX_CONCURENT_REQUESTS)
            await Task.Delay(DELAY_TIME);

        ProcessUrlAsyncWithReqCount(httpClient);
    }
}

HttpClient, eşzamanlı isteklerin sayısını sınırlamak için bir mekanizma eklemiş olsaydı gerçekten yararlı olurdu. Task sınıfı (.Net iş parçacığı havuzuna dayalı) kullanılırken, eşzamanlı iş parçacığı sayısı sınırlandırılarak azaltma otomatik olarak gerçekleştirilir.

Tam bir genel bakış için, HttpClient yerine HttpWebRequest'e dayalı bir zaman uyumsuz test sürümü de oluşturdum ve çok daha iyi sonuçlar elde etmeyi başardım. Bir başlangıç ​​için, eşzamanlı bağlantıların sayısına (ServicePointManager.DefaultConnectionLimit ile veya config aracılığıyla) bir sınır koymaya izin verir; bu, bağlantı noktalarının hiçbir zaman bitmediği ve hiçbir istekte asla başarısız olmadığı anlamına gelir (HttpClient, varsayılan olarak, HttpWebRequest'e dayanır. , ancak bağlantı sınırı ayarını yok sayıyor gibi görünüyor).

Eşzamansız HttpWebRequest yaklaşımı hala çok iş parçacıklı olandan yaklaşık% 50 - 60 daha yavaştı, ancak öngörülebilir ve güvenilirdi. Tek dezavantajı, büyük yük altında büyük miktarda bellek kullanmasıydı. Örneğin 1 milyon istek göndermek için yaklaşık 1,6 GB gerekiyordu. Eşzamanlı isteklerin sayısını sınırlandırarak (yukarıda HttpClient için yaptığım gibi) kullanılan belleği sadece 20 MB'ye düşürmeyi ve çoklu okuma yaklaşımından yalnızca% 10 daha yavaş bir yürütme süresi elde etmeyi başardım.

Bu uzun sunumdan sonra sorularım: .Net 4.5'ten gelen HttpClient sınıfı, yoğun yük uygulamaları için kötü bir seçim mi? Onu kısmanın bir yolu var mı, bahsettiğim sorunları çözen hangisi? HttpWebRequest'in eşzamansız özelliği nasıl olur?

Güncelleme (teşekkürler @Stephen Cleary)

Görünüşe göre, HttpClient, tıpkı HttpWebRequest gibi (varsayılan olarak dayalıdır), aynı ana bilgisayarda ServicePointManager.DefaultConnectionLimit ile sınırlı eşzamanlı bağlantı sayısına sahip olabilir. Garip olan şu ki, MSDN'ye göre bağlantı limiti için varsayılan değer 2'dir. Ayrıca bunu benim tarafımda, aslında 2'nin varsayılan değer olduğunu gösteren hata ayıklayıcıyı kullanarak kontrol ettim. Ancak, ServicePointManager.DefaultConnectionLimit'e açıkça bir değer ayarlamadıkça, varsayılan değer yok sayılacak gibi görünüyor. HttpClient testlerim sırasında bunun için açıkça bir değer belirlemediğimden, bunun göz ardı edildiğini düşündüm.

ServicePointManager.DefaultConnectionLimit'i 100 HttpClient olarak ayarladıktan sonra güvenilir ve öngörülebilir hale geldi (netstat yalnızca 100 bağlantı noktasının kullanıldığını doğrular). Halen eşzamansız HttpWebRequest'ten daha yavaştır (yaklaşık% 40), ancak garip bir şekilde daha az bellek kullanır. 1 milyon istek içeren test için, asenkron HttpWebRequest'teki 1,6 GB'ye kıyasla maksimum 550 MB kullandı.

Dolayısıyla, ServicePointManager.DefaultConnectionLimit kombinasyonundaki HttpClient güvenilirliği sağlıyor gibi görünse de (en azından tüm çağrıların aynı ana bilgisayara doğru yapıldığı senaryo için), yine de performansı uygun bir azaltma mekanizmasının eksikliğinden olumsuz etkileniyor gibi görünüyor. Eşzamanlı istek sayısını yapılandırılabilir bir değerle sınırlayacak ve gerisini bir sıraya koyacak bir şey, yüksek ölçeklenebilirlik senaryoları için onu çok daha uygun hale getirecektir.


4
HttpClientsaygı duymalı ServicePointManager.DefaultConnectionLimit.
Stephen Cleary

2
Gözlemleriniz araştırılmaya değer görünüyor. Yine de beni rahatsız eden bir şey var: Bence aynı anda binlerce eşzamansız IO yayınlamak son derece uydurulmuş. Bunu üretimde asla yapmam. Asenkron olmanız, çeşitli kaynakları tüketerek delirebileceğiniz anlamına gelmez. (Microsofts resmi örnekleri bu konuda da biraz yanıltıcıdır.)
usr

1
Yine de zaman gecikmeleriyle boğulmayın. Deneysel olarak belirlediğiniz sabit bir eşzamanlılık düzeyinde kısın. Basit bir çözüm SemaphoreSlim.WaitAsync olabilir, ancak bu da keyfi olarak büyük miktarlarda görevler için uygun olmayacaktır.
usr

1
@FlorinDumitrescu Kısma için SemaphoreSlim, daha önce belirtildiği gibi veya ActionBlock<T>TPL Dataflow'dan kullanabilirsiniz.
svick

1
@svick, önerileriniz için teşekkürler. Kısma / eşzamanlılık sınırlaması için manuel olarak bir mekanizma uygulamakla ilgilenmiyorum. Bahsedildiği gibi, soruma dahil edilen uygulama sadece bir teoriyi test etmek ve doğrulamak içindi. Üretime geçemeyeceği için geliştirmeye çalışmıyorum. İlgilendiğim şey, .Net çerçevesinin zaman uyumsuz GÇ işlemlerinin eşzamanlılığını (HttpClient dahil) sınırlandırmak için yerleşik bir mekanizma sunup sunmadığıdır.
Florin Dumitrescu

Yanıtlar:


64

Soruda bahsedilen testlerin yanı sıra, kısa süre önce çok daha az HTTP çağrısı içeren (daha önce 1 milyona kıyasla 5000), ancak yürütülmesi çok daha uzun süren isteklerde (önceki 1 milisaniyeye kıyasla 500 milisaniye) yeni testler oluşturdum. Her iki test uygulaması, eşzamanlı olarak çok iş parçacıklı olan (HttpWebRequest'e dayalı) ve eşzamansız G / Ç (HTTP istemcisine dayalı) benzer sonuçlar üretti: CPU'nun yaklaşık% 3'ü ve 30 MB bellek kullanılarak yürütülmesi yaklaşık 10 saniye. İki test cihazı arasındaki tek fark, çok iş parçacıklı olanın yürütmek için 310 iş parçacığı kullanırken, eşzamansız olanın yalnızca 22 iş parçacığını kullanmasıydı.

Testlerimin bir sonucu olarak, çok hızlı isteklerle uğraşırken zaman uyumsuz HTTP çağrıları en iyi seçenek değildir. Bunun arkasındaki neden, eşzamansız bir G / Ç çağrısı içeren bir görev çalıştırılırken, görevin başlatıldığı iş parçacığı, eşzamansız çağrı yapılır yapılmaz sonlandırılır ve görevin geri kalanı bir geri arama olarak kaydedilir. Daha sonra, G / Ç işlemi tamamlandığında, geri arama kullanılabilir ilk iş parçacığında yürütülmek üzere sıraya alınır. Tüm bunlar, hızlı G / Ç işlemlerinin, onları başlatan iş parçacığı üzerinde yürütüldüğünde daha verimli olmasını sağlayan bir ek yük oluşturur.

Eşzamansız HTTP çağrıları, uzun veya potansiyel olarak uzun G / Ç işlemleriyle uğraşırken iyi bir seçenektir çünkü G / Ç işlemlerinin tamamlanmasını beklerken hiçbir iş parçacığını meşgul etmez. Bu, bir uygulama tarafından kullanılan toplam iş parçacığı sayısını azaltır ve CPU'ya bağlı işlemler için daha fazla CPU zamanı harcanmasına izin verir. Ayrıca, yalnızca sınırlı sayıda iş parçacığı ayıran uygulamalarda (web uygulamalarında olduğu gibi), eşzamansız G / Ç, eşzamanlı olarak G / Ç çağrıları gerçekleştirildiğinde meydana gelebilecek iş parçacığı havuzu iş parçacığı tükenmesini önler.

Bu nedenle, zaman uyumsuz HttpClient, yoğun yük uygulamaları için bir darboğaz değildir. Doğası gereği çok hızlı HTTP istekleri için pek uygun değildir, bunun yerine uzun veya potansiyel olarak uzun olanlar için idealdir, özellikle de yalnızca sınırlı sayıda iş parçacığı bulunan uygulamalarda. Ayrıca, ServicePointManager.DefaultConnectionLimit aracılığıyla eşzamanlılığı iyi bir paralellik düzeyi sağlayacak kadar yüksek ancak geçici bağlantı noktası tükenmesini önleyecek kadar düşük bir değerle sınırlamak iyi bir uygulamadır. Bu soru için sunulan testler ve sonuçlar hakkında daha fazla ayrıntıyı burada bulabilirsiniz .


3
"Çok hızlı" ne kadar hızlıdır? 1 ms? 100ms? 1,000ms?
Tim P.

Windows'ta dağıtılan bir WebLogic web sunucusundaki bir yükü yeniden oynatmak için "eşzamansız" yaklaşımınız gibi bir şey kullanıyorum, ancak oldukça hızlı bir şekilde ephemical port tükenmesi sorunu yaşıyorum. ServicePointManager.DefaultConnectionLimit'e dokunmadım ve her istekte her şeyi (HttpClient ve yanıt) düzenleyip yeniden oluşturuyorum. Bağlantıların açık kalmasına ve bağlantı noktalarını tüketmesine neyin sebep olabileceği hakkında bir fikriniz var mı?
Iravanchi

@TimP. Testlerim için, yukarıda belirtildiği gibi, "çok hızlı" tamamlanması yalnızca 1 milisaniye süren isteklerdi. Gerçek dünyada bu her zaman öznel olacaktır. Benim bakış açıma göre, yerel bir ağ veritabanındaki küçük bir sorguya eşdeğer bir şey hızlı olarak düşünülebilirken, internet üzerinden bir API çağrısına eşdeğer bir şey yavaş veya potansiyel olarak yavaş kabul edilebilir.
Florin Dumitrescu

1
@Iravanchi, "asenkron" yaklaşımlarda, istek gönderme ve yanıt işleme ayrı ayrı gerçekleştirilir. Çok sayıda aramanız varsa, tüm istekler çok hızlı gönderilecek ve yanıtlar geldiklerinde işleme alınacaktır. Bağlantıları yalnızca yanıtları geldikten sonra atabileceğiniz için, çok sayıda eşzamanlı bağlantı geçici bağlantı noktalarınızı biriktirebilir ve tüketebilir. ServicePointManager.DefaultConnectionLimit kullanarak maksimum eşzamanlı bağlantı sayısını sınırlamalısınız.
Florin Dumitrescu

1
@FlorinDumitrescu, ayrıca ağ çağrılarının doğası gereği tahmin edilemez olduğunu da ekledim. Zamanın% 90'ında 10 ms'de çalışan şeyler, diğer% 10'luk bir zaman diliminde bu ağ kaynağı tıkandığında veya kullanılamadığında engelleme sorunlarına neden olabilir.
Tim P.

27

Sonuçlarınızı etkileyebileceğini göz önünde bulundurmanız gereken bir şey, HttpWebRequest ile ResponseStream'i almadığınız ve bu akışı tüketmediğinizdir. HttpClient ile, varsayılan olarak ağ akışını bir bellek akışına kopyalayacaktır. HttpClient'i şu anda HttpWebRquest kullandığınız şekilde kullanmak için yapmanız gereken

var requestMessage = new HttpRequestMessage() {RequestUri = URL};
Task<HttpResponseMessage> getTask = httpClient.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead);

Diğer bir şey de, iş parçacığı açısından gerçek farkın ne olduğundan emin değilim, aslında test ediyorsun. HttpClientHandler'ın derinliklerine inerseniz, zaman uyumsuz bir istek gerçekleştirmek için Task.Factory.StartNew yapar. İş parçacığı davranışı, eşitleme bağlamına, HttpWebRequest örneğinizle tam olarak aynı şekilde temsil edilir.

Şüphesiz, HttpClient, varsayılan olarak taşıma kitaplığı olarak HttpWebRequest'i kullandığından bazı ek yükler ekler. Böylece, HttpClientHandler kullanırken doğrudan bir HttpWebRequest ile her zaman daha iyi performans elde edebilirsiniz. HttpClient'in getirdiği avantajlar, HttpResponseMessage, HttpRequestMessage, HttpContent gibi standart sınıflar ve güçlü yazılmış tüm üstbilgilerdir. Kendi içinde mükemmel bir optimizasyon değildir.


(eski cevap, ama) HttpClientkullanımı kolay görünüyor ve eşzamansızın gitmenin yolu olduğunu düşündüm, ancak bunun etrafında birçok "ama ve eğer" var gibi görünüyor. Belki de HttpClientkullanımı daha sezgisel olacak şekilde yeniden yazılmalıdır? Veya dokümantasyonun onu en verimli şekilde nasıl kullanacağına dair önemli şeyleri gerçekten vurguladığını mı?
mortb

@mortb, Flurl.Http flurl.io , HttpClient'in sarmalayıcısını kullanmak için daha sezgisel
Michael Freidgeim

1
@MichaelFreidgeim: Teşekkürler, şimdiye kadar HttpClient ile yaşamayı öğrenmiş olmama rağmen ...
mortb

17

Bu, OP'nin sorusunun 'eşzamansız' kısmını doğrudan yanıtlamasa da, bu, kullandığı uygulamadaki bir hatayı ele alır.

Uygulamanızın ölçeklenmesini istiyorsanız, örnek tabanlı HttpClients kullanmaktan kaçının. Aradaki fark BÜYÜK! Yüke bağlı olarak çok farklı performans rakamları göreceksiniz. HttpClient, istekler arasında yeniden kullanılmak üzere tasarlanmıştır. Bu, onu yazan BCL ekibindeki adamlar tarafından onaylandı.

Yakın zamanda yaptığım bir proje, çok büyük ve tanınmış bir çevrimiçi bilgisayar perakendecisinin bazı yeni sistemler için Kara Cuma / tatil trafiğini ölçeklendirmesine yardımcı olmaktı. HttpClient kullanımıyla ilgili bazı performans sorunlarıyla karşılaştık. O aletlerin yana IDisposable, Devs normalde bir örneğini yaratma ve iç yerleştirerek yapacağını yaptım using()açıklamada. Yük testine başladığımızda, uygulama sunucuyu dizlerinin üstüne getirdi - evet, sunucu sadece uygulama değil. Bunun nedeni, her HttpClient örneğinin sunucuda bir G / Ç Tamamlama Bağlantı Noktası açmasıdır. GC'nin deterministik olmayan sonlandırması ve birden çok OSI katmanına yayılan bilgisayar kaynakları ile çalışmanız nedeniyle , ağ bağlantı noktalarını kapatmak biraz zaman alabilir. Aslında Windows işletim sisteminin kendisibir bağlantı noktasını kapatmak 20 saniyeye kadar sürebilir (Microsoft başına). Bağlantı noktalarını kapatılabileceklerinden daha hızlı açıyorduk - CPU'yu% 100'e çeken sunucu bağlantı noktası tükenmesi. Benim düzeltmem, HttpClient'i sorunu çözen statik bir örneğe dönüştürmekti. Evet, tek kullanımlık bir kaynaktır, ancak herhangi bir ek yük, performans farkı nedeniyle büyük ölçüde ağır basmaktadır. Uygulamanızın nasıl davrandığını görmek için bazı yük testleri yapmanızı tavsiye ederim.

Aşağıdaki bağlantıda da cevaplandı:

Bir WebAPI istemcisinde arama başına yeni bir HttpClient oluşturmanın ek yükü nedir?

https://www.asp.net/web-api/overview/advanced/calling-a-web-api-from-a-net-client


İstemcide TCP bağlantı noktasının tükenmesine neden olan aynı sorunu buldum. Çözüm, HttpClient örneğini yinelemeli çağrıların yapıldığı uzun süreler boyunca kiralamaktı, her çağrı için oluşturmak ve elden çıkarmak değil. Vardığım sonuç, "Dispose'u uyguladığı için, bu onu Dispose etmenin ucuz olduğu anlamına gelmiyor" oldu.
PhillipH

öyleyse, HttpClient statikse ve sonraki istekte bir üstbilgiyi değiştirmem gerekiyorsa, bu ilk isteğe ne yapar? Statik olduğundan HttpClient'i değiştirmenin herhangi bir zararı var mı - örneğin bir HttpClient.DefaultRequestHeaders.Accept.Clear (); ? Örneğin, belirteçler aracılığıyla kimlik doğrulaması yapan kullanıcılarım varsa, bu belirteçlerin farklı belirteçler olan API'ye yönelik istek üzerine başlıklar olarak eklenmesi gerekir. Statik olarak HttpClient'e sahip olmak ve sonra bu başlığı HttpClient üzerinde değiştirmenin olumsuz etkileri olmaz mı?
crizzwald

Başlıklar / tanımlama bilgileri gibi HttpClient örnek üyelerini kullanmanız gerekiyorsa, statik bir HttpClient kullanmamalısınız. Aksi takdirde, örnek verileriniz (başlıklar, çerezler) her istek için aynı olacaktır - kesinlikle istediğiniz şey DEĞİL.
Dave Black

çünkü durum bu olduğundan ... yukarıda yazdıklarınızda anlattıklarınızı - yüke karşı nasıl engellersiniz? yük dengeleyici ve ona daha fazla sunucu atabilir mi?
crizzwald

@crizzwald - Yazımda kullanılan çözümü not ettim. Statik bir HttpClient örneği kullanın. Bir HttpClient üzerinde başlık / tanımlama bilgisi kullanmanız gerekirse, bir alternatif kullanmayı tercih ederim.
Dave Black
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.