Найдите узкое место для применения в колбе

Я написал приложение с флягой. Я нашел это очень медленным, когда я развернул его на удаленном сервере. Итак, я сделал некоторые профилирующие практики. Пожалуйста, взгляните на фотографии ниже:

Код, который я использую для профилирования:

#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 найдено. Weird! enter image description here

Я тоже делал профилирование в оболочке python удаленного сервера с помощью 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? Потому что это замедляет мой веб-сайт, который меня грустно опустил.

Ответ 1

Я просто наткнулся на это сам в приложении Flask, работающем на выделенном ящике из Digital Ocean, поэтому я опубликую решение на случай, если кто-то еще ударит его в будущем.

Я заметил несколько дней назад, что запросы API к GitHub были безумно медленными, иногда занимая от 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

to

nameserver 8.8.4.4
nameserver 8.8.8.8

По какой-то причине 4.2.2.2 (запустил Level3) решил, что он меня ненавидит, но пока я и Google DNS круты.

Обновление: Мой коллега Карл предложил мне пойти и настроить локальный сервер кэширования DNS со связью, чтобы Google DNS не ненавидел меня. Эта ссылка была очень полезна.

Ответ 2

Я считаю, что это вызвано тем, что ваш удаленный хост не кэширует его DNS-запросы или getaddrinfo медленно из-за проблемы с IPv6.

Попробуйте (несколько раз) проверить, что ваши серверы имен кэшируются:

$ time host easylib.gdufslib.org

и проверить, выполняется ли поиск быстрее при форсировании только IPv4:

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

Если это вызвано первым, вы можете установить локальный кеширующий сервер имен или просто исправить, чтобы кеширование существующих серверов имен. Если последнее является причиной, вы можете попытаться исправить ее в своем коде и libs или отключить IPv6 на своем хосте, если вы его не используете.

Ответ 3

У меня была такая же проблема в ближайшем прошлом. Чтобы узнать, что вызывает медленность, я решил посмотреть, какие из моих конечных точек больше запрашиваются, а какие - узкое место. В этой связи я создал инструмент для анализа запросов. это может помочь вам, посмотрите на него https://github.com/muatik/flask-profiler