HTTPS 请求内存泄漏与 CurlAsyncHTTPClient
HTTPS request Memory leak with 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
配置文件
tornado.httpclient.AsyncHTTPClient.configure(client, max_clients=1000)
如果我的客户端是"tornado.curl_httpclient.CurlAsyncHTTPClient",那么当我在浏览器中访问我的处理程序时,htop显示内存增加了大约6GB ,只要进程运行,内存使用就不会减少
如果我将 range(200) 设置为 range(500) 或更高,内存使用量会增加
如果我的cline是None,内存几乎没有增加
我发现只获取 https:// 会有内存问题
如何使用 CurlAsyncHTTPClient 解决内存问题?
环境:
Ubuntu 16.10 x64
python2.7.12
Tornado 4.5.1
您看到的引用计数是预期的,因为 max_clients=1000
, Tornado will cache and reuse 1000 pycurl.Curl
instances, each of which may hold a reference to the client’s _curl_header_callback
. You can see it with objgraph.show_backrefs
.
您真的需要 max_clients=1000
— 即最多 1000 个并行请求吗? (我希望他们不像你的例子一样都在同一个服务器上!)
无论如何,Curl
个实例似乎占用了大量内存。
在我的系统 (Ubuntu 16.04) 上,当使用 PycURL linked 针对系统范围的 libcurl3-gnutls 7.47.0 时,我可以重现该问题:
$ /usr/bin/time -v python getter.py
6
207
^C
[...]
Maximum resident set size (kbytes): 4853544
当我 link 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 内存问题的报告:curl issue #1086。
因此,如果您确实需要大型 max_clients
,请尝试使用使用 OpenSSL 后端构建的更新的 libcurl。
我的处理程序文件
# -*- 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",那么当我在浏览器中访问我的处理程序时,htop显示内存增加了大约6GB ,只要进程运行,内存使用就不会减少
如果我将 range(200) 设置为 range(500) 或更高,内存使用量会增加
如果我的cline是None,内存几乎没有增加
我发现只获取 https:// 会有内存问题
如何使用 CurlAsyncHTTPClient 解决内存问题?
环境:
Ubuntu 16.10 x64
python2.7.12
Tornado 4.5.1
您看到的引用计数是预期的,因为 max_clients=1000
, Tornado will cache and reuse 1000 pycurl.Curl
instances, each of which may hold a reference to the client’s _curl_header_callback
. You can see it with objgraph.show_backrefs
.
您真的需要 max_clients=1000
— 即最多 1000 个并行请求吗? (我希望他们不像你的例子一样都在同一个服务器上!)
无论如何,Curl
个实例似乎占用了大量内存。
在我的系统 (Ubuntu 16.04) 上,当使用 PycURL linked 针对系统范围的 libcurl3-gnutls 7.47.0 时,我可以重现该问题:
$ /usr/bin/time -v python getter.py
6
207
^C
[...]
Maximum resident set size (kbytes): 4853544
当我 link 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 内存问题的报告:curl issue #1086。
因此,如果您确实需要大型 max_clients
,请尝试使用使用 OpenSSL 后端构建的更新的 libcurl。