2011-01-18 15 views
12

मेरा सर्वर प्रति अनुरोध के आधार पर अपनी प्रतिक्रिया बनाने के लिए आंतरिक वेब सेवा से डेटा का उपयोग करता है। मैं अनुरोध करने के लिए अपाचे एचटीपी क्लाइंट 4.1 का उपयोग कर रहा हूं। प्रत्येक प्रारंभिक अनुरोध के परिणामस्वरूप वेब सेवा के लिए लगभग 30 अनुरोध होंगे। इनमें से 4 - 8 CLOSE_WAIT में फंस गए सॉकेट के साथ समाप्त हो जाएंगे, जो कभी भी रिलीज़ नहीं होते हैं। आखिरकार ये अटक गए सॉकेट मेरे उलझन से अधिक हो जाते हैं और मेरी प्रक्रिया फाइल डिस्क्रिप्टर से बाहर हो जाती है।मैं कैसे सुनिश्चित कर सकता हूं कि मेरा एचटीपी क्लाइंट 4.1 सॉकेट को रिसाव नहीं करता है?

मैं सिर्फ अपना उलिमिट (1024) नहीं उठाना चाहता, क्योंकि इससे समस्या हल हो जाएगी।

कारण मैं एचटीपी क्लाइंट में स्थानांतरित हो गया हूं यह है कि java.net.HttpUrlConnection वैसे ही व्यवहार कर रहा था।

मैंने प्रति अनुरोध एकल क्लाइंट कॉनमैनर पर जाने की कोशिश की है, और क्लाइंट.getकोनक्शन मैनेजर() को बंद कर दिया है। लेकिन सॉकेट अभी भी अटक गया है।

क्या मुझे इसे हल करने की कोशिश करनी चाहिए ताकि मैं 0 खुले सॉकेट के साथ समाप्त हो, जबकि कोई रनिंग अनुरोध नहीं है, या क्या मुझे अनुरोध दृढ़ता और पूलिंग पर ध्यान देना चाहिए?

स्पष्टता के लिए मैं कुछ जानकारी जो प्रासंगिक हो सकता है शामिल कर रहा हूँ:

ओएस: उबंटू 10.10

JRE: 1.6.0_22

भाषा: स्काला 2.8

नमूना कोड:

val cleaner = Executors.newScheduledThreadPool(1) 
private val client = { 
    val ssl_ctx = SSLContext.getInstance("TLS") 
    val managers = Array[TrustManager](TrustingTrustManager) 
    ssl_ctx.init(null, managers, new java.security.SecureRandom()) 
    val sslSf = new org.apache.http.conn.ssl.SSLSocketFactory(ssl_ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) 
    val schemeRegistry = new SchemeRegistry() 
    schemeRegistry.register(new Scheme("https", 443, sslSf)) 
    val connection = new ThreadSafeClientConnManager(schemeRegistry) 
    object clean extends Runnable{ 
     override def run = { 
      connection.closeExpiredConnections 
      connection.closeIdleConnections(30, SECONDS) 
     } 
    } 
    cleaner.scheduleAtFixedRate(clean,10,10,SECONDS) 
    val httpClient = new DefaultHttpClient(connection) 
    httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY), new UsernamePasswordCredentials(username,password)) 
    httpClient 
} 
val get = new HttpGet(uri) 
val entity = client.execute(get).getEntity 
val stream = entity.getContent 
val justForTheExample = IOUtils.toString(stream) 
stream.close() 

टेस्ट: netstat -a | grep {myInternalWebServiceName} | ग्रेप CLOSE_WAIT

(सूचियाँ कि CLOSE_WAIT स्थिति में हैं मेरी प्रक्रिया के लिए सॉकेट)

टिप्पणी पोस्ट चर्चा:

इस कोड को अब सही उपयोग को दर्शाता है।

उत्तर

8

एक करने के लिए की जरूरत है सक्रिय रूप कनेक्शन पूल से समाप्त हो गई/निष्क्रिय कनेक्शन, अवरुद्ध I/O मॉडल कनेक्शन के रूप में मैं/हे घटनाओं जब तक वे से पढ़ा जा रहा है/के लिए लिखा पर कोई प्रतिक्रिया नहीं कर सकते हैं बेदखल। विवरण देखने के लिए

http://hc.apache.org/httpcomponents-client-dev/tutorial/html/connmgmt.html#d4e631

+0

आपके उत्तर के लिए धन्यवाद, मैं सहमत हूं कि दस्तावेज़ीकरण से पता चलता है कि यह एक प्रभावी उपाय होना चाहिए। CLOSE_WAIT में अनाथ सॉकेट की संख्या अभी भी लागू होने वाले ऑफ-थ्रेड क्लीनर के साथ विश्वसनीय रूप से बढ़ती है, इसलिए यह प्रभावी नहीं है। मैंने अपने प्रश्न में कुछ कार्यान्वयन विस्तार जोड़ा है। –

+0

मैं recant। मुझे एहसास नहीं हुआ था कि वास्तविक एप्लिकेशन कोड में मैं व्यावसायिक तर्क करने के लिए पूरक छवि अनुरोध कर रहा था। वे अभी भी HttpClient के परिचय से WS.url विधियों का उपयोग कर रहे थे, और पीछे सॉकेट छोड़ रहे थे। –

+0

टूटा लिंक। (कृपया लिंक के साथ शीर्षक और विवरण शामिल करें।) शायद यह वही जानकारी है? http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html – danorton

2

मैं, सही रूप में ओलेग के जवाब में चिह्नित के रूप में यह HttpClient का कनेक्शन पूलिंग के बारे में एक महत्वपूर्ण उपयोग बिंदु पर प्रकाश डाला गया है।

मेरे विशिष्ट मूल प्रश्न का उत्तर देने के लिए, हालांकि, "क्या मुझे 0 अप्रयुक्त सॉकेट के लिए हल करने की कोशिश करनी चाहिए या पूलिंग को अधिकतम करने की कोशिश करनी चाहिए?"

अब पूलिंग समाधान जगह पर है और सही ढंग से काम कर रहा है एप्लिकेशन थ्रूपुट में लगभग 150% की वृद्धि हुई है। मैं इसे एसटीएल और एकाधिक हैंडशेक से फिर से बातचीत करने के लिए श्रेय देता हूं, इसके बजाय HTTP 1.1 के अनुसार लगातार कनेक्शन का पुन: उपयोग करता हूं।

प्रत्येक अनुरोध आदि के बाद ThreadSafeClientConnManager.shutdown() को कॉल करने के साथ चारों ओर हैक करने की कोशिश करने के बजाय पूलिंग का उपयोग करने के लिए निश्चित रूप से काम करना उचित है।अगर, दूसरी तरफ, आप मनमानी मेजबानों को बुला रहे थे और मार्गों का पुन: उपयोग नहीं कर रहे थे, तो आप आसानी से पाते हैं कि यह हैकरी करने के लिए आवश्यक हो जाता है, क्योंकि JVM आपको CLOSE_WAIT नामित सॉकेट के लंबे जीवन के साथ आश्चर्यचकित कर सकता है आप अक्सर कचरा इकट्ठा नहीं कर रहे हैं।

1

मेरे पास एक ही समस्या थी और इसे यहां दिए गए सुझाव का उपयोग करके हल किया गया: here। लेखक कुछ टीसीपी मूल बातें पर छू लेती है:

जब एक TCP कनेक्शन के बारे में बंद करने के लिए है, इसका अंतिम रूप दिए जाने पर दोनों पक्षों द्वारा बातचीत के जरिए किया जाता है। सभ्य तरीके से अनुबंध तोड़ने के बारे में सोचें। दोनों पक्ष पेपर पर हस्ताक्षर करते हैं और यह सब अच्छा है। गीक टॉक में, यह एफआईएन/एसीके संदेशों के माध्यम से किया जाता है। पार्टी ए सॉकेट को बंद करना चाहता है यह इंगित करने के लिए एक एफआईएन संदेश भेजता है। पार्टी बी एक एसीके भेजता है कि यह संदेश प्राप्त हुआ और मांग पर विचार कर रहा है। पार्टी बी तब साफ हो जाती है और पार्टी ए को पार्टी भेजती है। ए ए के साथ प्रतिक्रिया करता है और हर कोई दूर चलता है।

समस्या में आता है जब बी अपने एफआईएन नहीं भेजता है। ए थोड़ी देर इंतजार कर रहा है। इसमें ने अपना अंतिमकरण अनुक्रम शुरू किया है और ऐसा करने के लिए अन्य पार्टी की प्रतीक्षा कर रहा है।

वह तो RFC 2616, 14.10 का उल्लेख है एक http हेडर की स्थापना इस समस्या को हल करने के लिए सुझाव देने के लिए:

postMethod.addHeader("Connection", "close"); 

ईमानदारी से, मैं वास्तव में इस हेडर की स्थापना के निहितार्थ पता नहीं है। लेकिन यह मेरे यूनिट परीक्षणों पर होने से CLOSE_WAIT को रोक दिया।

संबंधित मुद्दे

 संबंधित मुद्दे