2012-03-09 6 views
6

के साथ यूडीपी सर्वर में खोए गए यूडीपी अनुरोधों के बहुत सारे मैंने नेटटी के साथ एक साधारण यूडीपी सर्वर लिखा जो आसानी से संदेशों (फ्रेम) को लॉग इन करता है। ऐसा करने के लिए, मैंने एक साधारण फ्रेम डिकोडर डिकोडर और एक साधारण संदेश हैंडलर बनाया। मेरे पास एक क्लाइंट भी है जो अनुक्रमिक रूप से और/या समानांतर में एकाधिक अनुरोध भेज सकता है।नेटी

जब मैं अपने क्लाइंट परीक्षक को उदाहरण के लिए कुछ सौ अनुरोधों को अनुक्रमिक रूप से उनके बीच एक छोटी देरी के साथ कॉन्फ़िगर करने के लिए कॉन्फ़िगर करता हूं, तो नेटटी के साथ लिखा गया मेरा सर्वर उन्हें ठीक से प्राप्त करता है। लेकिन फिलहाल मैं अपने क्लाइंट में एक साथ अनुरोधों की संख्या बढ़ाता हूं (उदाहरण के लिए 100) अनुक्रमिक वाले और कुछ दोहराने के साथ, मेरा सर्वर कई अनुरोध खोना शुरू कर देता है। जब मैं उदाहरण के लिए 50000 अनुरोध भेजता हूं, तो मेरे सर्वर को केवल 4 9 000 प्राप्त होते हैं जब केवल सरल चैनल हैंडलर का उपयोग किया जाता है जो प्राप्त संदेश को प्रिंट करता है।

और जब मैं इस हैंडलर के सामने सरल फ्रेम डिकोडर (जो प्रिंट को प्रिंट करता है और इसे अन्य बफर में कॉपी करता है) जोड़ता है, तो सर्वर केवल आधे अनुरोधों को संभालता है !!

मैंने देखा है कि कोई फर्क नहीं पड़ता कार्यकर्ताओं मेरे द्वारा बनाए गए NioDatagramChannelFactory करने के लिए निर्दिष्ट की संख्या, वहाँ हमेशा एक और केवल एक धागा है कि अनुरोधों को प्रबंधित है (मैं सिफारिश Executors.newCachedThreadPool() अन्य पैरामीटर के रूप में उपयोग कर रहा हूँ)।

मैंने जेडीके के साथ आने वाले डेटाग्रामसेट पर आधारित एक और समान सरल यूडीपी सर्वर भी बनाया और यह हर अनुरोध को 0 (शून्य) खोने से पूरी तरह से संभालता है !! जब मैं अपने क्लाइंट में 50000 अनुरोध भेजता हूं (उदाहरण के लिए 1000 धागे के साथ), मुझे अपने सर्वर में 50000 अनुरोध प्राप्त हुए।

क्या मैं नेटटी का उपयोग कर अपने यूडीपी सर्वर को कॉन्फ़िगर करते समय कुछ गलत कर रहा हूं? या शायद नेटटी को ऐसे लोड का समर्थन करने के लिए डिज़ाइन नहीं किया गया है ?? दिए गए कैश थ्रेड पूल द्वारा उपयोग किए जाने वाले केवल एक थ्रेड का उपयोग क्यों किया जाता है (मैंने देखा कि केवल एक धागा और हमेशा जेएमएक्स जेकनसोल में देखकर और आउटपुट लॉग में थ्रेड नाम की जांच करके इसका उपयोग किया जाता है)? मुझे लगता है कि अगर अधिक थ्रेड जहां अपेक्षित थे, तो सर्वर आसानी से ऐसे लोड को संभालने में सक्षम होगा क्योंकि नेटटी का उपयोग न करने पर मैं बिना किसी समस्या के इसे कर सकता हूं!

देखें नीचे मेरी प्रवर्तन कोड:

... 

lChannelfactory = new NioDatagramChannelFactory(Executors.newCachedThreadPool(), nbrWorkers); 
lBootstrap = new ConnectionlessBootstrap(lChannelfactory); 

lBootstrap.setPipelineFactory(new ChannelPipelineFactory() { 
    @Override 
    public ChannelPipeline getPipeline() 
    { 
     ChannelPipeline lChannelPipeline = Channels.pipeline(); 
     lChannelPipeline.addLast("Simple UDP Frame Dump DECODER", new SimpleUDPPacketDumpDecoder(null));    
     lChannelPipeline.addLast("Simple UDP Frame Dump HANDLER", new SimpleUDPPacketDumpChannelHandler(lOuterFrameStatsCollector));    
     return lChannelPipeline; 
    } 
}); 

bindChannel = lBootstrap.bind(socketAddress); 

... 

और मेरे विकोडक में विधि डिकोड() की सामग्री:

protected Object decode(ChannelHandlerContext iCtx, Channel iChannel, ChannelBuffer iBuffer) throws Exception 
{ 
    ChannelBuffer lDuplicatedChannelBuffer = null; 
    sLogger.debug("Decode method called."); 

    if (iBuffer.readableBytes() < 8) return null; 
    if (outerFrameStatsCollector != null) outerFrameStatsCollector.incrementNbrRequests(); 

    if (iBuffer.readable()) 
    {   
     sLogger.debug(convertToAsciiHex(iBuffer.array(), iBuffer.readableBytes()));      
     lDuplicatedChannelBuffer = ChannelBuffers.dynamicBuffer(iBuffer.readableBytes());    
     iBuffer.readBytes(lDuplicatedChannelBuffer); 
    } 

    return lDuplicatedChannelBuffer; 
} 

और messageReceived की सामग्री() मेरे हैंडलर में विधि:

public void messageReceived(final ChannelHandlerContext iChannelHandlerContext, final MessageEvent iMessageEvent) throws Exception 
{ 
    ChannelBuffer lMessageBuffer = (ChannelBuffer) iMessageEvent.getMessage(); 
    if (outerFrameStatsCollector != null) outerFrameStatsCollector.incrementNbrRequests(); 

    if (lMessageBuffer.readable()) 
    {   
     sLogger.debug(convertToAsciiHex(lMessageBuffer.array(), lMessageBuffer.readableBytes()));    
     lMessageBuffer.discardReadBytes(); 
    } 
} 
+0

आप जानते हैं कि यूडीपी कोई वितरण गारंटियों का अधिकार है कर रहे हैं? –

+0

हां, मुझे पता है कि ऐसी कोई डिलीवरी गारंटी नहीं है, लेकिन मेरे लोड परीक्षण स्थानीय रूप से किए जाते हैं और मैं नेटी सामान की बजाय डेटाग्राम सॉकेट का उपयोग करके अपने सरल सर्वर के साथ कुछ भी नहीं खोता हूं। मैं वर्तमान में वायरशर्क के साथ अनुरोधों का विश्लेषण करने के लिए भी पुष्टि कर रहा हूं कि एक मामले में (नेटटी के बिना) कुछ भी नहीं खो गया है और नेटटी का उपयोग करते समय पैकेट खो गए हैं। – The4Summers

+0

@ The4Summers यदि आप देख सकते हैं कि नेटटी के साथ पैकेट खो रहे हैं, नेटटी आने वाले पैकेट को पर्याप्त रूप से पर्याप्त संसाधित नहीं कर रहा है, या आप नहीं हैं, इसलिए सॉकेट प्राप्त बफर भर रहा है, इसलिए आने वाले पैकेट को त्याग दिया जा रहा है, कहीं और नहीं है जाना। अपनी प्राप्त करने की गति बढ़ाएं या अपना प्रेषण धीमा करें। – EJP

उत्तर

7

आपने कनेक्शन रहित बूटस्ट्रैप उदाहरण को ठीक से कॉन्फ़िगर नहीं किया है।

  1. आपको इष्टतम मूल्यों के साथ अनुवर्ती कॉन्फ़िगर करना होगा।

    SO_SNDBUF आकार, SO_RCVBUF आकार और एक ReceiveBufferSizePredictorFactory अधिक जानकारी के लिए

    lBootstrap.setOption("sendBufferSize", 1048576); 
    
    lBootstrap.setOption("receiveBufferSize", 1048576); 
    
    lBootstrap.setOption("receiveBufferSizePredictorFactory", 
    new AdaptiveReceiveBufferSizePredictorFactory(MIN_SIZE, INITIAL_SIZE, MAX_SIZE)); 
    

    जांच DefaultNioDatagramChannelConfig वर्ग।

  2. पाइपलाइन नेटटी वर्क थ्रेड का उपयोग करके सबकुछ कर रही है।यदि कार्यकर्ता थ्रेड ओवरलोड हो गया है, तो यह चयनकर्ता ईवेंट लूप निष्पादन में देरी करेगा और चैनल पढ़ने/लिखने में बाधा होगी। आपको पाइपलाइन में निम्न के रूप में निष्पादन हैंडलर जोड़ना होगा। यह कार्यकर्ता थ्रेड को अपना काम करने के लिए मुक्त कर देगा।

    ChannelPipeline lChannelPipeline = Channels.pipeline(); 
    
    lChannelPipeline.addFirst("execution-handler", new ExecutionHandler(
        new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576)); 
    
    //add rest of the handlers here 
    
+0

बफर आकार विकल्पों के बारे में संकेत के लिए धन्यवाद! हालांकि, निष्पादन हैंडलर के बारे में, मैंने इस पोस्ट के बाद इसे आजमाया और हां, यह थोड़ी मदद करता है, लेकिन जब भी एक डिकोडर और हैंडलर का उपयोग किया जाता है तब भी मैं आधे अनुरोधों को खो देता था। मुझे यकीन है कि बफर बढ़ाना बहुत मदद करेगा। – The4Summers

+0

हालांकि, मुझे अभी भी समझ में नहीं आ रहा है कि अगर हमें कभी भी उपयोग नहीं किया जाता है तो NioDatagramChannelFactory क्लास को तुरंत चालू करते समय हमें थ्रेड पूल निष्पादक और कई श्रमिकों को निर्दिष्ट क्यों करना चाहिए !!?? – The4Summers

+0

मुझे खुशी है कि यह आपके लिए काम करता है। थ्रेड पूल निष्पादकों का उपयोग NioDatagramChannel पाइपलाइनों में कार्यकर्ता धागे बनाने के लिए किया जाता है। गैर कार्यकर्ता पढ़ने/लिखने के लिए एक कार्यकर्ता थ्रेड को डेटाग्राम चैनल में असाइन किया जा सकता है। यदि आपका एप्लिकेशन एक से अधिक बंदरगाहों पर सुन रहा है, तो कई कार्यकर्ता थ्रेड (डिफ़ॉल्ट सीपीयू आकार * 2) बनाया जाएगा और एक राउंड रॉबिन फैशन में डेटाग्राम चैनल को असाइन किया जाएगा। यदि आप अधिक कार्यकर्ता धागे रखना चाहते हैं, तो आप NioDatagramChannelFactory निर्माता में निर्दिष्ट कर सकते हैं। –

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