2012-08-09 11 views
16

मैं nginx + gunicorn + django के शीर्ष पर लागू एक वेब सेवा पर काम कर रहा हूं। ग्राहक स्मार्टफोन अनुप्रयोग हैं। एप्लिकेशन को बाहरी एपीआई (फेसबुक, अमेज़ॅन एस 3 ...) में कुछ लंबी चलने वाली कॉल करने की आवश्यकता है, इसलिए सर्वर बस नौकरी सर्वर पर नौकरी कतार देता है (CeleryRedis से अधिक) का उपयोग कर।एक nginx/gunicorn/django वेब आर्किटेक्चर में लंबे समय तक चलने वाले HTTP कनेक्शन की कुशल हैंडलिंग

जब भी संभव हो, सर्वर ने नौकरी कतारबद्ध कर ली है, तो यह तुरंत वापस आती है, और HTTP कनेक्शन बंद हो जाता है। यह ठीक काम करता है और सर्वर को बहुत अधिक भार बनाए रखने की अनुमति देता है।

client     server     job server 
    .      |      | 
    .      |      | 
    |------HTTP request----->|      | 
    |      |--------queue job------>| 
    |<--------close----------|      | 
    .      |      | 
    .      |      | 

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

संक्षेप में, मैं कुछ भी नहीं कर रहा हूं, कुछ भी नहीं कर रहा हूं (टीसीपी कनेक्शन को जीवित रखने के लिए हर बार एक व्हाइटस्पेस भेजकर, बस like Amazon S3 does), जब तक काम पूरा नहीं हो जाता है, और सर्वर परिणाम देता है।

client     server     job server 
    .      |      | 
    .      |      | 
    |------HTTP request----->|      | 
    |      |--------queue job------>| 
    |<------keep-alive-------|      | 
    |   [...]   |      | 
    |<------keep-alive-------|      | 
    |      |<--------result---------| 
    |<----result + close-----|      | 
    .      |      | 
    .      |      | 

मैं कैसे एक कुशल तरीके से लंबी चलने वाली HTTP कनेक्शन लागू कर सकते हैं, यह मानते हुए सर्वर बहुत अधिक लोड है (यह अभी तक ऐसा नहीं है, लेकिन लक्ष्य उच्चतम संभव लोड बनाए रखने के लिए सक्षम होने के लिए, प्रति सेकंड सैकड़ों या हजारों अनुरोधों के साथ)?

अन्य सर्वरों के लिए वास्तविक नौकरियों को ऑफ़लोड करना सर्वर पर कम CPU उपयोग सुनिश्चित करना चाहिए, लेकिन मैं सभी सर्वर की रैम को बढ़ाने और उपयोग करने से बचने के तरीकों से कैसे बच सकता हूं, या आने वाले अनुरोधों को बहुत से खुले कनेक्शन के कारण छोड़ दिया जा सकता है?

शायद यह ज्यादातर nginx और gunicorn को ठीक से कॉन्फ़िगर करने का विषय है। मैंने async workers based on greenlets in gunicorn के बारे में कुछ पढ़ा है: प्रलेखन का कहना है कि एसिंक श्रमिकों का उपयोग "" लंबे अवरुद्ध कॉल (आईई, बाहरी वेब सेवाओं) "करने वाले अनुप्रयोगों द्वारा किया जाता है, यह सही लगता है। यह भी कहता है "सामान्य रूप से, कोई एप्लिकेशन इन श्रमिक वर्गों का उपयोग करने में सक्षम होना चाहिए जिसमें कोई बदलाव नहीं है"। यह बहुत अच्छा लगता है। इस पर कोई प्रतिक्रिया?

आपकी सलाह के लिए धन्यवाद।

+0

क्या आपने डीजेंगो के लिए AJAX 'लंबे मतदान' समाधानों का शोध किया है? यह मूल रूप से एक ही चीज़ की तरह लगता है। – dgel

+0

हाँ, आप सही हैं, यह शायद वही बात है। AJAX का मतलब क्लाइंट पक्ष पर जावास्क्रिप्ट है, यह वेब ब्राउज़र के बारे में अधिक है, मेरे मामले में ग्राहक एक सॉफ्टफोन एप्लिकेशन है। लेकिन सर्वर की तरफ शायद लगभग एक ही, उत्कृष्ट विचार है। – MiniQuark

उत्तर

28

मैं answering my own question हूं, शायद किसी के पास बेहतर समाधान है।

gunicorn's documentation पढ़ना थोड़ा और आगे eventlet और gevent के बारे में थोड़ा और पढ़ना, मुझे लगता है कि बंदूकधारी मेरे प्रश्न का पूरी तरह से जवाब देती है। Gunicorn एक मास्टर प्रक्रिया है जो श्रमिकों के एक पूल का प्रबंधन करता है। प्रत्येक कार्यकर्ता या तो सिंक्रोनस (सिंगल थ्रेडेड, एक समय में एक अनुरोध को संभालने) या असीमित हो सकता है (प्रत्येक कार्यकर्ता वास्तव में लगभग एक साथ कई अनुरोधों को संभालता है)।

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

तो समाधान डिफ़ॉल्ट कार्यकर्ता प्रकार को सिंक्रोनस से एसिंक्रोनस में बदलना है (ईवेंटलेट या गीवेंट, here's a comparison चुनना)। अब प्रत्येक कर्मचारी कई green threads चलाता है, जिनमें से प्रत्येक बेहद हल्का है। जब भी एक थ्रेड को कुछ I/O के लिए इंतजार करना पड़ता है, तो एक और हरा धागा निष्पादन को फिर से शुरू करता है। इसे cooperative multitasking कहा जाता है। यह बहुत तेज है, और बहुत हल्का है (यदि कोई व्यक्ति I/O की प्रतीक्षा कर रहा है, तो एक भी कर्मचारी हजारों समवर्ती अनुरोधों को संभाल सकता है)। वास्तव में मुझे क्या चाहिए।

मैं सोच रहा था कि मुझे अपना मौजूदा कोड कैसे बदलना चाहिए, लेकिन स्पष्ट रूप से मानक पायथन मॉड्यूल monkey-patched स्टार्टअप (वास्तव में ईवेंटलेट या गीवेंट द्वारा) पर बंदूक से हैं, इसलिए सभी मौजूदा कोड बिना परिवर्तन किए चल सकते हैं और अभी भी अन्य धागे के साथ अच्छी तरह से व्यवहार कर सकते हैं।

मानकों का एक गुच्छा जो gunicorn के worker_connections पैरामीटर, backlog पैरामीटर का उपयोग कर लंबित कनेक्शन की अधिकतम संख्या का उपयोग कर gunicorn में बदलाव किया जा सकता है, उदाहरण के लिए एक साथ ग्राहकों की अधिकतम संख्या, आदि

यह सिर्फ है कर रहे हैं अच्छा, मैं तुरंत परीक्षण शुरू कर दूंगा!

+0

परीक्षण के बाद कोई प्रतिक्रिया या अद्यतन? अपने चरणों में अनुसरण करने के बारे में – dsldsl

+0

हाय dsldsl। मैं अब तक बंदूक और भूगर्भ से बहुत खुश हूं। मैंने कुछ सरल परीक्षण किए, जो संतोषजनक थे, गनिकोर्न व्यवहार करता है जैसा कि यह कहता है: मैंने 1 एकल कार्यकर्ता चलाने के बाद कुछ कनेक्शन खोलने (और बंद नहीं) करने की कोशिश की, और इससे अगले पूर्ण अनुरोध को पार नहीं किया गया। लेकिन अब तक मेरे पास वास्तविक बेंचमार्किंग करने का समय नहीं है। का आनंद लें! – MiniQuark

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