2015-08-07 19 views
25

Çok hızlı çalışan bir RESTful servisim var. Ben localhost üzerinde test ediyorum. İstemci Spring REST şablonunu kullanıyor. Bu kapalı ve TIME_WAIT asılı olmamak bağlantıları kaynaklanırSpring REST şablonunu kullanarak ya çok fazla bağlantı oluşturuyor ya da yavaş çalışıyor

Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/myservice":No buffer space available (maximum connections reached?): connect; nested exception is java.net.SocketException: No buffer space available (maximum connections reached?): connect 

: Aşağıdaki özel durum alıyorum ben bu istekleri bir sürü yaptığınızda

RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter())); 

Result result = restTemplate.postForObject(url, payload, Result.class); 

: Ben naif bir yaklaşım kullanarak başladı belirtmek, bildirmek. İstisna noktaları geçici olarak bittiğinde istisna başlar. Daha sonra yürütme, bağlantı noktalarının tekrar serbest olmasını bekler. Uzun aralarla en yüksek performansı görüyorum. Aldığım oran neredeyse ihtiyacım olan şey, ama tabi ki bu TIME_WAIT bağlantıları iyi değil. Hem Linux (Ubuntu 14) hem de Windows (7) üzerinde test edilmiş, farklı sonuçlar için farklı zaman aralıklarında benzer sonuçlar elde edilmiştir.

Bu sorunu gidermek için, HttpClientBuilder ile HttpClient uygulamasını Apache Http Components kitaplığından kullanmayı denedim.

RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter())); 
HttpClient httpClient = HttpClientBuilder.create() 
     .setMaxConnTotal(TOTAL) 
     .setMaxConnPerRoute(PER_ROUTE) 
     .build(); 
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)); 

Result result = restTemplate.postForObject(url, payload, Result.class); 

Bu istemci ile hiçbir özel durum göremiyorum. Müşteri şimdi sadece çok sınırlı sayıda geçici bağlantı noktası kullanıyor. Ama kullandığım ayarları (TOTAL ve PER_ROUTE), ihtiyacım olan performansı alamıyorum.

netstat komutunu kullanarak, sunucuya çok fazla bağlantı yapılmadığını görüyorum. Sayıları binlerce kişiye ayarlamayı denedim, ama müşterinin bu kadar fazla kullanmadığı görülüyor.

Çok sayıda bağlantı açmadan performansı artırmak için yapabileceğim bir şey var mı?


GÜNCELLEME: Ben 5000 ve 2500 toplam ve başına rota bağlantı sayısını ayarlama denedim ama istemci (netstat -n | wc -l bakarsak) yüzden fazla yaratmak değil gibi hala görünüyor. REST servisi JAX-RS kullanılarak ve Jetty üzerinde çalışıyor.

UPDATE2: Sunucuyu bazı bellek ayarlarıyla ayarlıyorum ve gerçekten iyi bir iş çıkışı elde ediyorum. Naif yaklaşım hala biraz daha hızlı, ama bence müşteri tarafında havuzun küçük bir yükü.

+0

"Ara bellek alanı yok" hatası, kodunuzla daha az sisteminizle ilişkilidir. TIME_WAIT bağlantılarının birçoğu, bağlantıların havuzlanmadığını gösterir. TIME_WAIT ayarlarını değiştirmeyin, çözdüğünden daha fazla soruna neden olacaktır (http://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux.html). Kullanılabilir arabellek alanı için olağan nedenler, kırık ağ kartları veya Linux'ta küçük bir wmem_max. Yuvalardan çıkmadan (IP dörtgenler) önce aynı bağlantı noktasındaki bir uzak ana bilgisayara en az 50k - 60k arası bağlantılar oluşturabilmeniz gerekir. – mp911de

cevap

31

Aslında Spring Boot bağlantıları sızdırmıyor değil. Burada gördüğünüz, Linux çekirdeğinin (ve her büyük işletim sisteminin) standart davranışıdır. Makineden kapatılan tüm soketler, bir süre boyunca TIME_WAIT durumuna geçer. Bu, bu geçici bağlantı noktasını kullanan bir sonraki soketi, aslında o bağlantı noktasındaki bir önceki yuva için amaçlanan paketleri almaktan korumaktır. İkisi arasında gördüğünüz fark, her birinin aldığı bağlantı havuzu yaklaşımlarının bir sonucudur. Daha özel olarak bağlantı havuzunu varsayılan olarak kullanmaz. Bu, her dinlenme çağrısının yeni bir yerel geçici bağlantı noktası ve sunucuya yeni bir bağlantı açtığı anlamına gelir. Hizmetiniz çok hızlıysa, mevcut yerel port aralığından hiçbir zaman geçmeyecek. Apache HttpClient ile bağlantı havuzundan faydalanıyorsunuz. Bu, uygulamanızın anlattığınız sorunu görmesini engeller. Ancak, hizmetiniz Linux çekirdeğinden daha hızlı yanıt verebildiğinden, bağlantı havuzu TIME_WAIT'dan dışarı çıkmaktadır, bağlantı havuzu, ne yaparsanız yapın istemcinizi yavaşlatacaktır (eğer herhangi bir şeyi yavaşlatmadıysa). Yerel geçici limanların tekrar).

Linux çekirdeğinde TCP yeniden kullanımını etkinleştirmek mümkün olsa da, tehlikeli olabilir (paketler gecikebilir ve anlayamadıkları rastgele paketler alıp, her türlü soruna neden olabilecek geçici portlar alabilirsiniz). Buradaki çözüm, ikinci örnekte olduğu gibi, bağlantı performansının, aradığınız performansa yakın olması için yeterince yüksek sayılarla kullanılmasıdır.

Bağlantı havuzunuzu ayarlamanıza yardımcı olması için, maxConnPerRoute ve maxConnTotal parametrelerini ayarlamayı istersiniz. maxConnPerRoute, tek bir IP: Bağlantı noktası çifti için yapılacak bağlantı sayısını sınırlar ve maxTotal, açılacak toplam bağlantı sayısını sınırlar. Durumunuzda, tüm talepler aynı yere yapıldığı için, bunları aynı (yüksek) değere ayarlayabilirsiniz.

+0

Soruyu ("sızıntı" olmadan) yeniden ifade etmeye çalışacağım. Apache istemcisini daha büyük bir havuz kullanmam için herhangi bir yol var mı? Netstat'ı kontrol ederek, kullandığım ayar ne olursa olsun, belki de yüz port kullanabileceğini düşünüyorum. Sunucuyla ilgili bir şey yapıp yapamayacağımı göreceğim. – sm4

+0

Şu anda "TOTAL" ve "PER_ROUTE" konumunda hangi değerleri kullanıyorsunuz? Bunlar, bağlantı havuzu boyutlarını işlemek için ayarlardır; burada PER_ROUTE, tek bir IP'ye bağlantı sayısını sınırlar: Bağlantı çifti ve "TOPLAM" sınırlar, toplam bağlantı sayısı –

+3

Şimdi her şeyin işe yaradığı bir noktadayım oldukça hızlı. Cevabınızı, bu iki parametrenin açıklamasıyla + herhangi bir olası ek yükün belirtilmesiyle günceller misiniz? Bu şekilde diğer insanlar için daha yararlı olurdu. – sm4