【问题标题】:Find bottleneck of flask application找到flask应用的瓶颈
【发布时间】:2013-06-18 20:33:12
【问题描述】:

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

我用来分析的代码是:

#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

图2

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

图3

有时,即使在远程服务器中,也没有发现瓶颈。未找到 _socket.getaddrinfo。诡异的!

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

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 被调用?因为它减慢了我的网站速度,这让我很伤心。

【问题讨论】:

  • Werkzeug 似乎不会调用getaddrinfo,除非你有一个非常旧的版本。也许它是您正在使用的扩展之一。我的建议是在 pdb 下运行应用程序,并在此函数上设置断点。当断点命中时,您可以获得堆栈跟踪以确定谁在进行调用。
  • 你是如何在远程服务器上运行你的 webapp 的? gunicorn + nginx、cgi、...?
  • @MarkusUnterwaditzer Gunicorn + Nginx

标签: networking dns flask cprofile


【解决方案1】:

我自己在 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.

与 Digital Ocean 支持合作,并怀疑这是一个 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 运营)认为它讨厌我,但目前我和 Google 的 DNS 都很酷。

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

【讨论】:

    【解决方案2】:

    我认为这是由于您的远程主机没有缓存它的 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。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2011-04-02
        • 1970-01-01
        • 1970-01-01
        • 2018-08-29
        • 1970-01-01
        • 2019-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多