2015-05-20 8 views
18

हमारे पास क्लाइंट सर्वर ऐप, 1 सर्वर, लगभग 10 क्लाइंट हैं। वे कस्टम प्रश्नों का उपयोग कर टीसीपी सॉकेट के माध्यम से संवाद करते हैं।पूर्ण जीसी के बाद सॉकेट कनेक्शन धीमा क्यों हुआ?

प्रणाली की गई कई महीनों के लिए सहज बनाए थे, लेकिन कुछ बिंदु पर, शेड्यूल किए गए दैनिक सर्वर पूर्ण जीसी उस के बारे में 50 के दशक ले लिया के बाद, हम पता लगा है कि ग्राहक द्वारा भेजे गए प्रश्नों और प्रतिक्रियाओं के बीच के समय से प्राप्त सर्वर बड़ा था,> 10-20s। कुछ 3 घंटों के बाद सिस्टम ठीक हो गया, सब ठीक हो रहा था।

समस्या की जांच करते समय हमने पाया: दोनों ग्राहकों पर

  1. कोई कचरा संग्रहण की समस्याओं और सर्वर
  2. क्वेरी प्रसंस्करण समय पर सर्वर छोटा था।
  3. सर्वर पर लोड उच्च था।
  4. नेटवर्क बैंडविड्थ संतृप्त नहीं था।
  5. पूर्ण जीसी के दौरान कनेक्शन रीसेट नहीं किए गए थे (दैनिक पूर्ण जीसी तब तक एक सामान्य घटना थी)
  6. मशीन और ओएस हाल ही में सेंटोस 6 (कर्नेल 2.6.32) से सेंटोस 7 (कर्नेल 3.10.0) में बदल गया है। , लेकिन नई कॉन्फ़िगरेशन का विस्तार किया गया था। ओरेकल जेडीके संस्करण भी 1.7.65 से 1.7.75 में बदल गया।

हम सर्वर पर एक धागा डंप ले लिया:

public int read() throws IOException { 
    return in.read(); 
} 

in हमारे कोड में एक BufferedInputStream है:

java.lang.Thread.State: RUNNABLE 
    at java.io.FilterInputStream.read(FilterInputStream.java:83) 
    at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:293) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745) 

FilterInputStream.read() निम्नलिखित है।

प्रश्न हैं: पूर्ण जीसी विराम के बाद अधिकांश कनेक्शन क्यों धीमा हो गए? स्टैकट्रैक FilterInputStream.read() में क्यों समाप्त होता है? क्या यह BufferedInputStream या सॉकेट इनपुट स्ट्रीम में कहीं खत्म नहीं होना चाहिए? क्या यह सर्वर पर उच्च लोड के लिए पढ़ा जा सकता है?

कोड हम पढ़ने के लिए उपयोग करें:

int constructLength = _socketDIS.readInt(); 
ByteArrayOutputStream constructBOAS = new ByteArrayOutputStream(constructLength); 
for (int i = 0; i != constructLength; i++) 
     constructBOAS.write(_socketDIS.read()); 
constructBOAS.close(); 
byte[] bytes = constructBOAS.toByteArray(); 

जहां:

java.lang.Thread.State: RUNNABLE 
    at java.net.SocketInputStream.socketRead0(Native Method) 
    at java.net.SocketInputStream.read(SocketInputStream.java:152) 
    at java.net.SocketInputStream.read(SocketInputStream.java:122) 
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:235) 
    at java.io.BufferedInputStream.read(BufferedInputStream.java:254) 
    - locked <0x00007f522cbebca8> (a java.io.BufferedInputStream) 
    at java.io.DataInputStream.readInt(DataInputStream.java:387) 
    at util.network.BytesBasedSocketConnection$ReadConnectionRunnable.run(BytesBasedSocketConnection.java:287) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745) 

अद्यतन:

_socketDIS = new DataInputStream(new BufferedInputStream(_socket.getInputStream())); 

यहाँ अच्छी तरह से काम कर रहे ग्राहक कनेक्शन से स्टैकट्रेस है

EJP जवाब के बारे में:

  1. कोई EOS शामिल था, कनेक्शन थे, लेकिन वे बहुत धीमी गति से थे

  2. यहां तक ​​कि अगर वहाँ एक EOS मैं नहीं देख सकते हैं कि कोड स्पिन सकता था ईओएस पर, forconstructLength मूल्य से घिरा हुआ है। लेकिन फिर भी, सुझाया गया सुधार वैध है।

  3. समस्या से स्टैकट्रेस पढ़ने एक DataInputStream ((_socketDIS.read()) पर किया कि FilterInputStream.read() से विरासत में मिला है में समाप्त होता है, इसके बाद के संस्करण कोड देखें। DataInputStream, BufferedInputStreamread() गुम है। यहां FilterInputStream.read() में in.read()BufferedInputStream पर बुलाया गया है, इसकी इसकी read() विधि परिभाषित है। लेकिन स्टैकट्रैक बीच में बंद हो जाता है, BufferedInputStream.read() तक नहीं पहुंच रहा है। क्यूं कर?

उत्तर

3

स्टैक ट्रेस दिखाता है कि आप ScheduledThreadPoolExecutor का उपयोग कर रहे हैं। मैं आपको अनुसूची का अध्ययन करने का सुझाव दूंगा। ऐसा लगता है कि देरी केवल इसलिए होती है क्योंकि पढ़ना किसी प्रकार के शेड्यूल पर होता है - जो मुझे लगता है।

+0

आह, वास्तव में एक 'अनुसूचित थ्रेडपूलएक्ससेलर' गलत तरीके से उपयोग किया जाता है, लेकिन यह कार्य लगातार चल रहा है, यह सिर्फ सॉकेट से प्रश्न पढ़ता है और उन्हें कतार में रखता है। – dcernahoschi

7

एक समय में एक बाइट पढ़ना सीपीयू का अपशिष्ट है। इस को फेंक दें:

int constructLength = _socketDIS.readInt(); 
ByteArrayOutputStream constructBOAS = new ByteArrayOutputStream(constructLength); 
for (int i = 0; i != constructLength; i++) 
     constructBOAS.write(_socketDIS.read()); 
constructBOAS.close(); 
byte[] bytes = constructBOAS.toByteArray(); 

और इस का उपयोग करें:

int constructLength = _socketDIS.readInt(); 
byte[] bytes = new byte[constructLength]; 
_socketDIS.readFully(bytes); 

नायब _socketDIS स्पष्ट रूप से नहीं एक BufferedInputStream लेकिन एक DataInputStream, जो unbuffered है।

संपादित

क्यों स्टैकट्रेस FilterInputStream.read में समाप्त होता है()?

सावधानी से देखो। BufferedInputStream सभी तीन पढ़ने() ओवरलोड को लागू नहीं करता है। उनमें से एक, मैं भूल जाता हूं, जिसे फ़िल्टरइनपुटस्ट्रीम, बेस क्लास में लागू किया गया है, और अन्य दो अधिभार कॉल करते हैं।

यह BufferedInputStream

नहीं में कहीं अंत नहीं करना चाहिए, ऊपर देखें।

या सॉकेट इनपुट स्ट्रीम में?

हां, अगर यह अवरुद्ध हो रहा था, लेकिन ऐसा नहीं है, संभवतः क्योंकि आप अपने खराब कोड के कारण स्ट्रीम के अंत में कताई कर रहे हैं।

क्या यह पढ़ा जा सकता है सर्वर पर उच्च लोड?

हां।

+0

ठीक है, लेकिन अधिकांश समय यह कोड ठीक काम करता है। और निश्चित रूप से '_socketDIS' buffered है। मैं जल्द ही कनेक्शन से एक और स्टैकट्रैक अपलोड करूंगा जो ठीक काम करता है और वह उसी कोड का उपयोग करता है। – dcernahoschi

+0

जो भी हो, लेकिन यह वैसे भी बेहतर कोड है। यह कोने के मामलों का सही ढंग से ख्याल रखता है, उदाहरण के लिए, समयपूर्व ईओएस, जहां आपका सिर्फ स्पिन-लूप होता है। – EJP

+0

धन्यवाद, मैं मानता हूं कि यह बेहतर है, लेकिन यहां मुद्दा नहीं है, कनेक्शन हर समय जिंदा रहता है और कुछ बिंदु पर ठीक हो जाता है, गति सामान्य हो जाती है। – dcernahoschi

1

यह एक विस्तृत टिप्पणी है, लेकिन यह एक टिप्पणी के लिए बहुत लंबा है, इसलिए मैं इसे एक उत्तर में प्रदान करूंगा।

जैसा कि आप ध्यान देते हैं, थ्रेड डंप फ़िल्टरइनपुटस्ट्रीम.read() के बीच में एक थ्रेड दिखा रहा है असामान्य है। हालांकि यह मौका से हो सकता है, जबकि ओवरराइड फ़िल्टरइनपुटस्ट्रीम.read() को BufferedInputStream.read() में हल किया जा रहा है, मौका से हो रहा है बहुत संभावना नहीं है।

यह देखते हुए कि यह एक पूर्ण कचरा संग्रह के बाद हुआ, मुझे लगता है कि फ़िल्टरइनपुटस्ट्रीम कॉल को हल करने में अधिक समय लग रहा था क्योंकि BufferedInputStream क्लास पूर्ण कचरा संग्रह के दौरान स्थानांतरित या अनलोड हो गया था। उदाहरण के लिए, अगर मौके से पूर्ण बुर्ज संग्रह हुआ तो BufferedInputStream ऑब्जेक्ट्स में उपयोग नहीं किया गया था, BufferedInputStream क्लास को अनलोड किया जा सकता था, जब इसकी पढ़ाई() विधि की आवश्यकता होती थी तो कक्षा लोडिंग की आवश्यकता होती थी। यह कम से कम एक बार देखा गया देरी के लिए जिम्मेदार हो सकता है।

कक्षाओं के लिए कुछ स्थितियों में अनलोड हो जाना संभव है जब उनके अंतिम उदाहरण कचरा इकट्ठा होता है, यहां तक ​​कि एक पूर्ण कचरा संग्रह की अनुपस्थिति में भी। यदि BufferedInputStream क्लास किसी भी तरह से प्रत्येक उपयोग के बाद अनलोड हो रहा था और अगली बार इसका उपयोग किया गया था, तो यह आपके द्वारा बताए गए लक्षणों को समझा सकता है, लेकिन मैं आमतौर पर ऐसा होने की उम्मीद नहीं करता।

यह भी संभव है कि BufferedInputStream क्लास वाले मेमोरी पेज को थ्रैशिंग कर रहा हो, शायद क्लास मेमोरी का उपयोग कर रहे थे, तो पूरी कचरा संग्रह के दौरान कक्षा को स्थानांतरित किया गया था। यदि आपके पास इस समय के दौरान स्मृति उपयोग के संबंध में कोई रिकॉर्ड है, तो वे एक नज़र के लायक हो सकते हैं।

+0

धन्यवाद। 'बुफर्डइनपूटस्ट्रीम' उदाहरणों को कचरा नहीं किया जाना चाहिए क्योंकि सॉकेट कनेक्शन जिंदा रहे। नहीं, स्मृति कम बनी हुई है, या तो कोई कचरा नहीं है। – dcernahoschi

-1

मुझे लगता है कि आपको स्ट्रीम में त्रुटियों या धीमे कनेक्शन के बिना स्ट्रीम पढ़ने और लिखने के लिए इसे फ़्लश करने का प्रयास करना चाहिए।

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