2012-09-27 20 views
10

मुझे एक ऐसा सेटअप मिला है जहां टॉरनाडो का उपयोग श्रमिकों के लिए पास-थ्रू के प्रकार के रूप में किया जाता है। टोरनाडो द्वारा अनुरोध प्राप्त किया जाता है, जो एन कार्यकर्ताओं को यह अनुरोध भेजता है, परिणाम एकत्र करता है और इसे वापस ग्राहक को भेजता है। जो ठीक काम करता है, सिवाय इसके कि जब किसी कारण से टाइमआउट — होता है तो मुझे स्मृति रिसाव मिल गया है।गिराए गए कनेक्शन पर टोरनाडो मेमोरी रिसाव

workers = ["http://worker1.example.com:1234/", 
      "http://worker2.example.com:1234/", 
      "http://worker3.example.com:1234/" ...] 

class MyHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    def post(self): 
     responses = [] 

     def __callback(response): 
      responses.append(response) 
      if len(responses) == len(workers): 
       self._finish_req(responses) 

     for url in workers: 
      async_client = tornado.httpclient.AsyncHTTPClient() 
      request = tornado.httpclient.HTTPRequest(url, method=self.request.method, body=body) 
      async_client.fetch(request, __callback) 

    def _finish_req(self, responses): 
     good_responses = [r for r in responses if not r.error] 
     if not good_responses: 
      raise tornado.web.HTTPError(500, "\n".join(str(r.error) for r in responses)) 
     results = aggregate_results(good_responses) 
     self.set_header("Content-Type", "application/json") 
     self.write(json.dumps(results)) 
     self.finish() 

application = tornado.web.Application([ 
    (r"/", MyHandler), 
]) 

if __name__ == "__main__": 
    ##.. some locking code 
    application.listen() 
    tornado.ioloop.IOLoop.instance().start() 

क्या मैं गलत कर रहा हूँ:

मैं जो इस स्यूडोकोड के लिए इसी तरह एक सेटअप मिल गया है? मेमोरी लीक कहां से आती है?

+0

मुझे यह पसंद नहीं है 'अगर लेन (प्रतिक्रियाएं) == लेन (श्रमिक):' - क्या आप सुनिश्चित हैं कि एप्लिकेशन हमेशा यहां मिलता है? अनुरोधों और सफल प्रयासों के बैच बनाने के प्रयासों को लॉग करने का प्रयास करें। –

+0

@ निकोले: दाएं, AFAIK, टोरनाडो सफलता और त्रुटि दोनों के लिए कॉलबैक का उपयोग करता है। इस प्रकार मुझे पूरा यकीन है कि कितने श्रमिक असफल रहे हैं, इस पर ध्यान दिए बिना, यह हमेशा कई प्रतिक्रियाएं प्राप्त करता है। मुझे यकीन नहीं है कि क्या होता है, जब ग्राहक अनुरोध रद्द कर देता है। – vartec

+0

यदि आपके पास 10 से अधिक कर्मचारी हैं, और वे सभी समय-समय पर मर जाते हैं - आपके पास समय अवधि है जब टर्ननाडो नया कनेक्शन नहीं बना सकता - मुझे नहीं पता कि यह इस समय कैसा व्यवहार करता है। 'Max_clients' तर्क के साथ खेलने का प्रयास करें। –

उत्तर

5

मुझे समस्या का स्रोत नहीं पता है, और ऐसा लगता है कि जीसी इसकी देखभाल करने में सक्षम होना चाहिए, लेकिन दो चीजें हैं जो आप कोशिश कर सकते हैं।

पहली विधि संदर्भ के कुछ सरल करने के लिए होगा (ऐसा लगता है कि वहाँ अभी भी responses के लिए संदर्भ हो सकता है जब RequestHandler पूरा करता है):

class MyHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    def post(self): 
     self.responses = [] 

     for url in workers: 
      async_client = tornado.httpclient.AsyncHTTPClient() 
      request = tornado.httpclient.HTTPRequest(url, method=self.request.method, body=body) 
      async_client.fetch(request, self._handle_worker_response) 

    def _handle_worker_response(self, response): 
     self.responses.append(response) 
     if len(self.responses) == len(workers): 
      self._finish_req() 

    def _finish_req(self): 
     .... 

यदि वह काम नहीं करता है, तो आप हमेशा आह्वान कर सकते हैं मैन्युअल रूप से कचरा संग्रहण:

import gc 
class MyHandler(tornado.web.RequestHandler): 
    @tornado.web.asynchronous 
    def post(self): 
     .... 

    def _finish_req(self): 
     .... 

    def on_connection_close(self): 
     gc.collect() 
+0

। 'gc.garbage': ऑब्जेक्ट्स की एक सूची जो कलेक्टर को पहुंच योग्य नहीं पाया गया लेकिन उसे मुक्त नहीं किया जा सका। मैंने देखा कि स्टार्टअप पर यह सूची खाली है, लेकिन प्रत्येक अनुरोध पर जोड़ा गया है। –

1

कोड अच्छा लगता है। रिसाव शायद टोरनाडो के अंदर है।

async_client = tornado.httpclient.AsyncHTTPClient() 

आप इस निर्माता में इन्स्टेन्शियशन जादू के बारे में पता कर रहे हैं:

मैं केवल इस लाइन पर ठोकर खाई? डॉक्स से:

""" 
The constructor for this class is magic in several respects: It actually 
creates an instance of an implementation-specific subclass, and instances 
are reused as a kind of pseudo-singleton (one per IOLoop). The keyword 
argument force_instance=True can be used to suppress this singleton 
behavior. Constructor arguments other than io_loop and force_instance 
are deprecated. The implementation subclass as well as arguments to 
its constructor can be set with the static method configure() 
""" 

तो वास्तव में, आप पाश अंदर ऐसा करने की जरूरत नहीं है। (अन्य हाथ पर, इसे कोई नुकसान नहीं करना चाहिए।) लेकिन CurlAsyncHTTPClient या SimpleAsyncHTTPClient का उपयोग करके आप कौन सा कार्यान्वयन कर रहे हैं?

यदि यह SimpleAsyncHTTPClient है, कोड में इस टिप्पणी के बारे में पता होना:

""" 
This class has not been tested extensively in production and 
should be considered somewhat experimental as of the release of 
tornado 1.2. 
""" 

आप CurlAsyncHTTPClient पर स्विच करके कर सकते हैं। या निकोले फोमिनेह के सुझाव का पालन करें और __callback() को कॉल का पता लगाएं।

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