Статьи

Шаблоны производительности Django 1: измерение производительности

По мере взросления Django его используют для больших и больших проектов. В то же время все больше людей быстро создают относительно простые приложения. У каждого приложения разные, но держу пари, что у подавляющего большинства из них есть ряд общих проблем с производительностью. Зачастую производительность — это то, с чем только большие команды тратят время, чтобы действительно разобраться. Иногда это происходит из-за того, что меньшие проекты не могут позволить себе время, или чаще всего, вероятно, все считается достаточно быстрым .

Одним из преимуществ использования фреймворка является совместное использование общих решений общих проблем, возникающих в форме сообщества. В этой серии статей мы надеемся рассказать о некоторых простых вещах, которые каждый может сделать для повышения производительности приложений. Шаблоны обычно применимы, но я собираюсь сосредоточиться на примерах Django.

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

Измерение производительности

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

Мы начнем с рассмотрения нескольких инструментов, которые полезны при рассмотрении подхода к анализу производительности. Они обычно игнорируют влияние нагрузки на систему, но из-за этого, как правило, их легче понять и прочитать.

Django Debug Toolbar

Надеемся, что большинство разработчиков Django уже будут использовать превосходную панель отладки . Он имеет ряд функций, относящихся к нашему текущему квесту, но наиболее интересным является количество запросов. Меньше запросов почти всегда лучше. Это колоссальное обобщение, но поиск ненужных запросов, дублированных запросов или особенно медленных запросов — отличный способ ускорить работу вашего приложения. ORM делает это довольно легко закончить с querysplosion , если вы не обращали внимания.

Это очень просто установить:

pip install django-debug-toolbar

В разделе запросов показано количество запросов, сами запросы и время, затраченное на них. Он предназначен для работы в режиме отладки, поэтому фактическое время запросов, вероятно, будет ниже в производственном процессе, но запрос, который занимает много времени в разработке, вероятно, все еще будет медленным, когда вы начнете работать.

Панель отладки Django

YSlow

YSlow — это расширение браузера для Firefox и Chrome, которое предоставляет информацию и рекомендации по ряду основных проблем HTTP , CSS или javascript, которые могут возникнуть на отдельных страницах. Это даст вам оценку, а также предложения по улучшению:

YSlow показывает балл 96

Также полезно сократить количество HTTP- запросов и влияние заполненного кэша на загрузку страницы.

YSlow показывает разбивку http-запросов

Профилирование Middleware

Иногда вы хотите знать вызовы очень низкого уровня, которые используются при создании страницы. Для этого вам нужно взглянуть на инструменты профилирования. В вики Django есть полезная страница по профилированию, которая хороша, если уныло читать.

Django Snippets имеет несколько промежуточных программ для профилирования, одна из которых упакована в превосходный Django Snippetscream . Мы можем установить это так:

pip install django-snippetscream

Просто включите промежуточное ПО в вашу среду отладки:

MIDDLEWARE_CLASSES = MIDDLEWARE_CLASSES + ('snippetscream.ProfileMiddleware',)

Затем вы можете добавить? Prof к любому из ваших URL, и вместо просмотра вы увидите что-то вроде следующего:

Профилирование

Посмотрите, где ваш код тратит время и повторяли ли вы вызовы одних и тех же методов и функций. Иногда опускаться до такого уровня детализации — это самый простой способ найти узкое место в вашем приложении.

Nginx Logging

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

Файлы журналов — замечательные вещи, и Nginx имеет довольно мощный синтаксис для добавления дополнительной информации в файлы журналов . Обратите внимание на последнюю строку в определении ниже.

log_format timed_combined '$remote_addr - $remote_user [$time_local]  '
      '"$request" $status $body_bytes_sent '
      '"$http_referer" "$http_user_agent" '
      '$request_time $upstream_response_time $gzip_ratio';

Мы добавляем все время запроса, время, необходимое для ответа вышестоящему серверу (в моем случае gunicorn), а также соотношение gzip. Это действительно удобно, если вы оптимизируете приложение, уже находящееся в производстве. Собрав здесь эти данные, можно легко анализировать журналы и извлекать такие вещи, как медленные URL-адреса или ресурсы, которые не будут эффективно сжаты.

Джанго Timelog

Очень похоже на вышеописанное ведение журнала nginx, но реализовано как приложение django 1.3 (так что его можно использовать и в разработке) — это один из моих проектов, django-timelog . Помимо регистрации времени, затраченного на каждый запрос, django-timelog предоставляет команду управления для анализа полученного файла журнала. Он производит выходные данные, которые могут в совокупности отображать среднее время ответа либо просмотров, либо отдельных URL-адресов.

+--------------------------+--------+--------+-------+---------+---------+-------+-------+
| view                     | method | status | count | minimum | maximum | mean  | stdev |
+--------------------------+--------+--------+-------+---------+---------+-------+-------+
| boxes.viewsBoxDetailView | GET    | 200    | 9430  | 0.14    | 0.28    | 0.21  | 0.070 |
+--------------------------+--------+--------+-------+---------+---------+-------+-------+
| boxes.viewsBoxListView   | GET    | 200    | 66010 | 0.17    | 0.28    | 0.232 | 0.045 |
+--------------------------+--------+--------+-------+---------+---------+-------+-------+
| django.views.staticserve | GET    | 200    | 61295 | 0.00    | 0.02    | 0.007 | 0.006 |
+--------------------------+--------+--------+-------+---------+---------+-------+-------+

Он упакован, поэтому установка должна быть простой.

pip install django-timelog

Опять же, это можно использовать в производственной среде или локально при разработке. Вы также можете использовать инструменты нагрузочного тестирования, как описано ниже, для генерации трафика, который затем регистрируется.

Нагрузочное тестирование

В основном я ищу инструмент, который может легко генерировать HTTP- трафик по объему, посылая приличное количество одновременных запросов к вашему приложению и возвращая некоторые полезные результаты. Я в основном обращаюсь к ab ( Apache bench ), потому что он доступен везде и очень прост в использовании.

Например, давайте попадем на сайт с 100 запросами, причем запросы отправляются партиями по 5.

ab -c 5 -n 100 http://www.vagrantbox.es/12/

Это напечатает что-то вроде следующего. Для наших целей мы в основном заинтересованы в количестве запросов в секунду и среднем времени запроса.

Concurrency Level:      5
Time taken for tests:   1.981 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      328300 bytes
HTML transferred:       297400 bytes
Requests per second:    50.47 [#/sec] (mean)
Time per request:       99.064 [ms] (mean)
Time per request:       19.813 [ms] (mean, across all concurrent requests)
Transfer rate:          161.82 [Kbytes/sec] received

Нагрузочное тестирование — довольно большая тема. Например, даже с приведенным выше простым примером, как мы узнаем, достаточно ли 100 запросов? (это не так.) Или полезно ли параллелизм 5? Часто вас интересует, где ваше приложение начинает насыщаться или где начинается ошибка. Но даже не увязая в деталях, простой тест, подобный этому, может показать, что изменения имели положительный или отрицательный эффект. Я покажу примеры этого, когда мы исследуем методы оптимизации.

Если вы работаете над большим проектом, надеюсь, у вас будет время изучить и другие подходы. Я довольно фанат использования производственных журналов для воспроизведения запросов, например, и использования Funkload для запуска сценариев под нагрузкой. Надеюсь, я напишу больше о них позже. Я слышал хорошие вещи о Цунге , а также, HTTPerf отлично и JMeter имеет много поклонников. Я использую ab в качестве примера, потому что он наведен, и вы, вероятно, уже установили его, не зная.

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