2017-08-04 2 views
1

Mein HandlerHTTPS-Anforderung Speicherleck mit CurlAsyncHTTPClient

# -*- coding:utf-8 -*- 
import sys 
from tornado import gen, web, httpclient 

url = "https://mdetail.tmall.com/templates/pages/desc?id=527485572414" 

class SearchHandler(web.RequestHandler): 
    @gen.coroutine 
    def get(self): 
     async_client = httpclient.AsyncHTTPClient() 
     print sys.getrefcount(async_client) # The first time less than 10, then always bigger than 200 
     req = httpclient.HTTPRequest(url, "GET", headers=headers) 
     req_lists = [async_client.fetch(req) for _ in range(200)] 
     r = yield req_lists 
     print sys.getrefcount(async_client) # always bigger than 200 
     # The longer req_lists, the more memory will be consumed, and never decrease 

configure Datei in broswer

tornado.httpclient.AsyncHTTPClient.configure(client, max_clients=1000) 

, wenn mein Kunde ist "tornado.curl_httpclient.CurlAsyncHTTPClient", Dann, wenn ich Sie auf meiner Handler-Datei , htop zeigt Speichererhöhung um 6GB, solange der Prozess läuft, Speicherverbrauch nie sinken

Wenn ich Bereich eingestellt (200) bis Bereich (500) oder höher, wächst Speicherverbrauch höher

wenn mein Cline Keine ist, kaum Speicher

ich die nur holen gefunden erhöhen https: // wird Speicherproblem haben

Wie kann ich das Momory Problem mit CurlAsyncHTTPClient?

Umwelt:

Ubuntu 16.10 x64 
python2.7.12 
Tornado 4.5.1 

Antwort

1

Die Referenzzähler Sie erwartet sehen, denn mit max_clients=1000 wird Tornado und 1000 pycurl.Curl instances Wiederverwendung zwischenzuspeichern, von denen jeder kann hold a reference an den Kunden _curl_header_callback. Sie können es mit objgraph.show_backrefs sehen.

Benötigen Sie wirklich max_clients=1000 - also bis zu 1000 Anfragen parallel? (Ich hoffe, sie sind nicht alle auf dem gleichen Server, wie in Ihrem Beispiel!)

Wie dem auch sei, die Curl Instanzen scheinen eine Menge Speicher zu belegen.

Auf meinem System (Ubuntu 16.04), kann ich das Problem reproduzieren, wenn pycurl gegen die systemweite libcurl3-gnutls verbunden mit 7.47.0:

$ /usr/bin/time -v python getter.py 
6 
207 
^C 
[...] 
    Maximum resident set size (kbytes): 4853544 

Wenn ich pycurl Link mit einem frisch gebauten Libcurl 7,54 0,1 (noch mit GnuTLS Backend), habe ich ein viel besseres Ergebnis erhalten:

$ LD_LIBRARY_PATH=$PWD/curl-prefix/lib /usr/bin/time -v python getter.py 
6 
207 
^C 
[...] 
    Maximum resident set size (kbytes): 1016084 

Und wenn ich libcurl mit dem OpenSSL-Backend verwenden, ist das Ergebnis noch besser:

Maximum resident set size (kbytes): 275572 

Es gibt andere Berichte von Speicherproblemen mit GnuTLS: curl issue #1086.

Wenn Sie also eine große max_clients benötigen, versuchen Sie es mit einer neueren libcurl, die mit dem OpenSSL-Backend erstellt wurde.

+0

Vielen Dank, aber ich verstehe immer noch nicht, warum nur ** "https: //" ** Anfragen viel Speicherplatz verbrauchen mit ** CurlAsyncHTTPClient **, aber ** "http: //" ** Anfragen do not – zpoint

+0

@zpoint Wie ich schon sagte, scheint die hohe Speicherbelegung mit dem TLS-Backend verwandt zu sein, das von libcurl verwendet wird (GnuTLS vs. OpenSSL). Natürlich wird TLS nur für HTTPS verwendet, nicht für HTTP im Klartext. –

+0

Danke, ich werde die neueste Version von libcurl versuchen – zpoint