找到烧瓶应用的瓶颈

时间:2013-06-21 16:14:41

标签: networking dns flask cprofile

我写了一个烧瓶应用程序。当我在远程服务器中部署它时,我发现它非常慢。 所以,我用它做了一些分析实践。 请看下面的图片:

我用于分析的代码是:

#coding: utf-8
from werkzeug.contrib.profiler import ProfilerMiddleware
from app import app

app.config['PROFILE'] = True
app.wsgi_app = ProfilerMiddleware(app.wsgi_app, restrictions = [30])
app.run(debug = True)

图片1

远程服务器中的分析。 也许瓶颈是_socket.getaddrinfo

enter image description here

图片2

在本地计算机中进行分析。 没有发现瓶颈。

enter image description here

图3

有时,即使在远程服务器中,也没有发现瓶颈。找不到_socket.getaddrinfo。奇怪的! enter image description here

我使用cProfile在远程服务器python shell中进行了分析。 看看这个:


In [10]: cProfile.run("socket.getaddrinfo('easylib.gdufslib.org', 80, 0, 0, socket.SOL_TCP)")
         3 function calls in 8.014 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    8.014    8.014 :1()
        1    8.014    8.014    8.014    8.014 {_socket.getaddrinfo}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}



In [11]: cProfile.run("socket.getaddrinfo('easylib.gdufslib.org', 80, 0, 0, socket.SOL_TCP)")
         3 function calls in 8.009 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    8.009    8.009 :1()
        1    8.009    8.009    8.009    8.009 {_socket.getaddrinfo}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


也许有一个事实是,做一些dns resolve工作需要花费很多时间,而我自己也无法改变这一点。

任何人都可以告诉我:为什么_socket.getaddrinfo被调用,为什么有时不被调用? 如何阻止调用_socket.getaddrinfo?因为它减慢了我的网站,让我感到悲伤。

3 个答案:

答案 0 :(得分:7)

我刚刚在Digital Ocean的一个专用盒子上运行的Flask应用程序中遇到了这个问题,所以我会发布解决方案以防其他人在将来遇到这个问题。

我几天前注意到,对GitHub的API请求疯狂慢,有时需要10到20秒。但在本地运行我的应用程序没有任何问题。我描述了我的应用,socket.getaddrinfo确实是罪魁祸首:

1 15058.431 15058.4310 15058.431 15058.4310 {_socket.getaddrinfo}
1 26.545 26.5450 26.545 26.5450 {_ssl.sslwrap}
1 23.246 23.2460 23.246 23.2460 {built-in method do_handshake}
4 22.387 5.5968 22.387 5.5968 {built-in method read}
1 7.632 7.6320 7.632 7.6320 {method 'connect' of '_socket.socket' objects}
103 4.995 0.0485 7.131 0.0692 <s/werkzeug/urls.py:374(url_quote)>
2 2.459 1.2295 2.578 1.2890 <ssl.py:294(close)>
36 1.495 0.0415 10.548 0.2930 <s/werkzeug/routing.py:707(build)>
859 1.442 0.0017 1.693 0.0020 {isinstance}
.... etc.

使用数字海洋支持,并怀疑它在某种程度上是一个DNS问题,工作解决方案是改变(在/etc/resolv.conf

nameserver 4.2.2.2
nameserver 8.8.8.8

nameserver 8.8.4.4
nameserver 8.8.8.8

无论出于何种原因,4.2.2.2(由Level3运行)决定它讨厌我,但暂时我和谷歌的DNS很酷。

更新:我的同事Karl建议我继续设置一个带有bind的本地DNS缓存服务器,以防止Google的DNS也讨厌我。 This link was super helpful.

答案 1 :(得分:1)

我认为这是由于远程主机没有缓存它的DNS查找或由于IPv6的问题而导致getaddrinfo缓慢所致。

尝试此(几次)来测试您的名称服务器是否正在缓存:

$ time host easylib.gdufslib.org

并测试在强制使用IPv4时查找是否更快:

import socket
socket.getaddrinfo("easylib.gdufslib.org", 80, socket.AF_INET, 0, socket.SOL_TCP)

如果它是由第一个引起的,您可以安装本地缓存名称服务器,或者只修复现有的名称服务器缓存。如果后者是原因,您可以尝试在代码和库中修复它,或者如果不使用它,则在主机上禁用IPv6。

答案 2 :(得分:0)

我在近期遇到过同样的问题。为了看看导致缓慢的原因,我决定看看哪些端点更多被请求以及哪些端点是瓶颈。为此,我创建了一个分析请求的工具。它也可以帮助你,看看它https://github.com/muatik/flask-profiler