HTTPS请求使用CurlAsyncHTTPClient进行内存泄漏

时间:2017-08-04 04:56:56

标签: python python-2.7 curl tornado pycurl

我的处理程序文件

# -*- 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

配置文件

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

如果我的客户端“tornado.curl_httpclient.CurlAsyncHTTPClient”,那么当我在broswer中访问我的处理程序时, htop 显示内存增加大约6GB,只要该过程运行,内存使用从不减少

如果我将范围(200)设置为范围(500)或更高,则内存使用量会增加

如果我的cline ,则内存几乎不会增加

我发现仅提取 https:// 会有内存问题

如何用 CurlAsyncHTTPClient 解决这个问题呢?

环境:

Ubuntu 16.10 x64
python2.7.12
Tornado 4.5.1

1 个答案:

答案 0 :(得分:1)

您看到的引用计数是预期的,因为使用max_clients=1000,Tornado会缓存并重用1000 pycurl.Curl instances,每个hold a reference可能objgraph.show_backrefs到客户端的_curl_header_callback。您可以使用curl issue #1086查看。

您真的需要max_clients=1000 - 也就是说,并行最多1000个请求? (我希望它们不是全部都在同一个服务器上,就像你的例子一样!)

无论如何,Curl实例似乎占用了大量内存。

在我的系统(Ubuntu 16.04)上,我可以在使用PycURL链接到系统范围的libcurl3-gnutls 7.47.0时重现该问题:

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

当我将PycURL与新构建的libcurl 7.54.1(仍然使用GnuTLS后端)链接时,我得到了更好的结果:

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

如果我将libcurl与OpenSSL后端一起使用,结果仍然更好:

    Maximum resident set size (kbytes): 275572

还有其他关于GnuTLS内存问题的报告:{{3}}。

因此,如果您确实需要大max_clients,请尝试使用使用OpenSSL后端构建的较新的libcurl。