В последней статье Understand Django мы узнали о командах. Команды — это способ выполнения скриптов, которые взаимодействуют с вашим приложением Django.
В этой статье мы поговорим о производительности. Как сделать ваш Django сайт быстрее? Продолжайте читать, чтобы узнать.
Теория производительности
Есть два способа сделать сайт быстрее:
- Делать больше работы.
- Делать меньше работы.
То, как мы делаем больше работы и меньше работы, зависит от типа работы, которую мы пытаемся решить на сайте.
Когда мы говорим о выполнении большего объема работы, я имею в виду, что часто нам необходимо увеличить пропускную способность сайта. Пропускная способность — это показатель работы за определенное время. Увеличивая пропускную способность, сайт может обслуживать больше пользователей одновременно.
Очень естественным показателем пропускной способности Django-сайта являются запросы в секунду. Просмотр страницы на сайте может содержать несколько запросов, поэтому запросы в секунду не являются идеальным аналогом того, сколько пользователей может обслужить ваш сайт, но это все равно полезный показатель, который поможет вам рассуждать о производительности сайта.
С другой стороны, что значит делать больше работы, а что значит делать меньше работы для повышения производительности?
Самый быстрый код — это отсутствие кода.
Каждая строка кода, которую вы пишете, должна быть обработана компьютером при выполнении. Если ваш код неэффективен или выполняется слишком много, это, естественно, означает, что для получения конечного результата потребуется больше времени.
Время от момента ввода до момента получения результата называется задержкой. Если пользователь нажимает на ссылку на вашем сайте, сколько времени ему потребуется для получения ответа. Эта временная задержка и есть латентность.
Меньше работы не означает, что вы выполняете слишком много кода! Существует множество факторов, которые могут способствовать задержке, и некоторые из них легче оптимизировать, чем другие.
- Неэффективный код — ошибки при разработке могут сделать компьютер медленнее, чем нужно
- Размер данных — отправка большего объема данных требует больше усилий для доставки пользователям
- Географическое положение — скорость света является реальным ограничением для сетевого взаимодействия
- и многое другое!
Если вы можете уменьшить задержку на вашем сайте, вы можете улучшить опыт людей, пользующихся сайтом.
В оставшейся части этой статьи вы узнаете, как можно сделать как больше, так и меньше работы, чтобы создать лучший сайт, который принесет пользу вашим пользователям.
Сначала измерьте
Прежде чем приступить к оптимизации, необходимо определить, какая работа затрачивается на приложение. Другими словами, какие ограничения ресурсов не позволяют приложению работать лучше?
Измерение приложений, особенно тех, которые работают с живым трафиком, может быть непростым занятием. Я думаю, что мы можем рассматривать приложение как с макроуровня, так и с более детальной точки зрения.
Я бы начал свой анализ с осмотра системы в целом на предмет выявления закономерностей. В целом, вы обнаружите, что производительность, как правило, падает на пару основных категорий узких мест:
- связанные с вводом/выводом
- связанный с процессором
Ограничение ввода-вывода означает, что система ограничена (это и есть часть «ограничена») входами и выходами системы. Поскольку это все еще очень расплывчатое утверждение, давайте сделаем его более конкретным. Система с ограниченным вводом-выводом — это система, которая ждет, пока работа станет доступной. Классические примеры включают:
- ожидание ответов от базы данных,
- ожидание содержимого файловой системы,
- ожидание передачи данных по сети,
- и так далее.
Оптимизация системы, связанной с вводом-выводом, сводится к минимизации этих моментов ожидания.
И наоборот, системы с привязкой к процессору — это системы, которые тонут в немедленной работе по вычислению. Центральный процессор компьютера не успевает выполнять все, что от него требуется. Классическими примерами работы с ограниченным процессором являются:
- Вычисления в области науки о данных для машинного обучения
- обработка и рендеринг изображений
- Выполнение тестовых пакетов
Оптимизация системы, привязанной к процессору, в основном направлена на то, чтобы сделать вычисления быстрее и дешевле.
Поскольку мы понимаем, что приложение, которое не справляется с работой, скорее всего, связано с вводом-выводом или процессором, мы можем начать искать эти закономерности в системе. Самым простым начальным сигналом для наблюдения является загрузка процессора. Если процессоры на ваших производственных машинах работают с очень высокой загрузкой ЦП, то это довольно четкий индикатор того, что ваше приложение завязано на ЦП. По моим оценкам, такое редко встречается в веб-приложениях. Большинство веб-приложений с низкой производительностью, скорее всего, связаны с вводом-выводом.
Причина, по которой веб-приложения часто связаны с вводом-выводом, связана с их типичной функцией. Большинство приложений получают данные из базы данных и отображают их пользователю. Здесь нет большого объема вычислений (по сравнению с чем-то вроде машинного обучения), которые приложение должно выполнить. Таким образом, ваше приложение, вероятно, ожидает данных из базы данных.
Если вы заметили, что система не привязана к процессору, то следующее действие — копнуть глубже и найти, где приложение проводит время в ожидании, но как? С философской точки зрения, вы должны хорошо понимать, что нужно искать, но какие инструменты вы можете использовать для выполнения задачи измерения?
Нам нужно немного отмотать назад. Минуту назад я также сделал предположение, что вы знаете, как определить загрузку процессора вашего приложения. Это может оказаться не так.
Самый простой способ отслеживать основную информацию о ресурсах вашего приложения, включая CPU, память, использование диска и многое другое, может исходить от вашего поставщика хостинга. Мой любимый хостинг-провайдер, Heroku, отображает все эти показатели на одной странице, чтобы я мог оценить производительность системы с первого взгляда. Другие поставщики, такие как Digital Ocean или AWS, также предоставляют инструменты для просмотра этой информации.
Если ваш поставщик хостинга не предоставляет эти инструменты, вам придется использовать другие методы. Предположительно, если вы используете виртуальный выделенный сервер (VPS) для хостинга, у вас есть доступ к самому серверу через ssh. На сервере, где запущено ваше приложение, вы можете использовать программу типа top
. Это классическая программа для проверки того, какие процессы используют «верхнее» количество ресурсов. top
покажет список процессов, упорядоченных по тому, какой из них потребляет больше всего CPU, и будет обновлять порядок списка каждую секунду, чтобы обеспечить текущий снимок во времени. (Совет: используйте q
для выхода из top
после его запуска).
Хотя top
полезен и позволяет узнать об использовании процессора, это не самый дружелюбный инструмент. Существуют альтернативы top
, которые могут предложить лучший пользовательский опыт. Я лично считаю top
достаточным, но я знаю, что htop
является популярной альтернативой.
Если у вас нет инструментов от хостинг-провайдера и вы не хотите использовать ssh для входа на сервер, есть и другие варианты. В целом, эта другая категория инструментов называется Мониторинг производительности приложений (APM). Инструменты APM — это поставщики, которые будут следить за работой вашего приложения (вот это да!), если вы установите инструмент вместе с вашим приложением. Производительность приложений очень важна для бизнеса, поэтому в индустрии программного обеспечения есть множество поставщиков с широким спектром возможностей.
Чтобы увидеть, какими могут быть эти инструменты бесплатно, вы можете посмотреть на Datadog, у которого есть бесплатный уровень (Datadog не является спонсором, я просто использовал их сервис, мне понравилось, и я знаю, что он бесплатный для небольшого количества серверов). Другие популярные поставщики включают Scout APM и New Relic.
Наконец, мы достигли точки, где вы можете диагностировать ограничения производительности вашего приложения, используя широкий спектр инструментов или услуг. Давайте посмотрим, как исправить проблемы, с которыми вы можете столкнуться!
Делайте больше
Мы можем решить проблему пропускной способности и сделать больше с помощью нескольких различных ручек.
Когда вы думаете о том, как сделать больше, постарайтесь представить себе систему в двух различных масштабах:
- Горизонтально
- вертикально
Горизонтальное и вертикальное масштабирование — это методы описания того, как сделать больше в программных системах.
Давайте соотнесем это с глупым примером, чтобы дать вам хорошее интуитивное ощущение масштабирования. Представьте, что вам нужно перевезти большие мешки с землей (примерно 40 фунтов / 18 кг на мешок), чтобы посадить огромный сад. Задача состоит в том, чтобы выгрузить сотни мешков из грузовика на ваш воображаемый задний двор. Чтобы справиться с этой задачей, вы привлекаете к работе своих друзей.
Одна из стратегий заключается в том, чтобы привлечь на помощь самых сильных друзей. Возможно, их не так много, но их сила поможет быстро перенести мешки. Это и есть вертикальное масштабирование. Дополнительная сила ваших друзей позволяет им перемещать мешки легче, чем человеку со средним или слабым телосложением.
Другая стратегия заключается в том, чтобы привлечь на помощь много друзей. Возможно, эти друзья не смогут перенести столько мешков, сколько более сильные, но много рук делают легкую работу. Это и есть горизонтальное масштабирование. Увеличение числа людей позволяет группе перенести больше мешков, потому что больше людей могут выполнять работу одновременно.
Мы можем применить это же мышление к компьютерным системам.
Вертикальное масштабирование
Чтобы добиться вертикального масштабирования, необходимо запустить приложение на более мощном компьютере. Поставщики облачных решений предоставляют вам всевозможные инструменты для этого. Выбор более быстрого компьютера, естественно, обойдется вам дороже, поэтому поставщики предоставляют множество вариантов (посмотрите на эту страницу AWS, чтобы увидеть головокружительное количество вариантов).
Когда вам следует задуматься о вертикальном масштабировании? Один из естественных случаев — когда ваше приложение ограничено процессором. Если процессор с трудом справляется с обработкой запросов приложения, более быстрый процессор может помочь. Благодаря более высокой тактовой частоте более быстрого отдельного процессора компьютер сможет быстрее обрабатывать отдельные запросы.
Переход на более мощный компьютер обычно рассматривается как вертикальное масштабирование, но из-за особенностей конструкции современных компьютеров можно добиться горизонтального эффекта при переходе на более мощный компьютер. Сегодня большие компьютеры обычно оснащаются большим количеством центральных процессоров. Каждый отдельный процессор может быть быстрее, чем в конфигурации меньшего компьютера, и на одной машине может быть больше процессоров. Из-за этой особенности вам, скорее всего, придется изменить конфигурацию вашего приложения, чтобы воспользоваться преимуществами дополнительной мощности.
В статье Понять развертывание Django мы обсуждали флаг --workers
в Gunicorn. Напомним, что серверы приложений Python, такие как Gunicorn, работают путем создания главного процесса и набора рабочих процессов. Главный процесс распределяет входящие сетевые соединения между рабочими процессами для обработки фактического трафика на вашем сайте. Если вы вертикально масштабируете серверную машину с 1 CPU до машины с 2, 4 или более CPU и не меняете количество рабочих процессов, то вы будете тратить доступную мощность CPU и не увидите большинства преимуществ от увеличения размера сервера.
Если современное вертикальное масштабирование использует больше CPU при переходе на большую машину, то что же такое горизонтальное масштабирование? Разница заключается, прежде всего, в количестве компьютеров, необходимых для выполнения масштабирования. Вертикальное масштабирование изменяет одну машину для достижения большей пропускной способности. При горизонтальном масштабировании в уравнение включается несколько машин.
Горизонтальное масштабирование
Концептуально, как работает горизонтальное масштабирование? В модели вертикального масштабирования вы можете увидеть четкую связь между пользователями, делающими запрос к домену вашего сайта, и одной машиной, обрабатывающей эти запросы (т.е. главный процесс вашего сервера приложений распределяет запросы). В горизонтальной модели мы теперь обсуждаем несколько компьютеров. Как одно доменное имя справляется с маршрутизацией на несколько компьютеров? С помощью большего количества компьютеров!
Подобно основному процессу, распределяющему запросы, нам нужен центральный узел, способный направлять трафик на различные машины в вашей горизонтально масштабируемой системе. Этот центр обычно называется балансировщиком нагрузки. Балансировщик нагрузки может использоваться для различных целей. Я вижу, что балансировщики нагрузки используются в основном для:
- Маршрутизация трафика к различным серверам приложений в системе.
- Управление сертификатами TLS, что делает возможным использование HTTPS.
Поскольку балансировщик нагрузки не выполняет большую часть работы по обработке запроса, ваша система может увеличить свою пропускную способность за счет увеличения количества серверов приложений. При такой настройке каждый сервер приложений «думает», что он является главным сервером, который обрабатывает запросы. Балансировщик нагрузки ведет себя как клиент, который выполняет запросы от имени реального пользователя. Такая конфигурация называется прокси.
Если вы хотите узнать больше о горизонтальном масштабировании с помощью балансировщика нагрузки, то я предлагаю вам ознакомиться с Nginx (произносится как «движок X»), HAProxy (что означает «прокси высокой доступности») или AWS ALBs (означает «балансировщик нагрузки приложений»). Эти инструменты широко распространены и имеют репутацию сильных балансировщиков нагрузки.
Что лучше?
Каковы компромиссы между горизонтальным и вертикальным масштабированием?
Когда вы добавляете больше частей в систему, вы увеличиваете сложность системы. Таким образом, вертикальное масштабирование может, по крайней мере, на начальном этапе, привести к созданию конструкции с меньшей эксплуатационной сложностью. Лично я, если бы я запускал сервис на каком-нибудь VPS, например Digital Ocean или AWS, скорее всего, сначала выбрал бы вертикальное масштабирование. Большая машина позволила бы мне использовать большее количество параллельных рабочих процессов для увеличения пропускной способности, и я бы избежал сложности развертывания нескольких серверов приложений.
В действительности я запускаю свои побочные проекты на платформе как услуга, Heroku. Когда я выбрал Heroku, сервис по умолчанию уже включает в себя балансировщик нагрузки. Это означает, что я могу тривиально масштабироваться горизонтально, изменив настройки в Heroku, которые запустят несколько серверов приложений.
Хотя вертикальное масштабирование может быть хорошим вариантом, если у вас нет существующего балансировщика нагрузки, этот путь масштабирования имеет свои недостатки.
Во-первых, в мире вертикального масштабирования простой вашего сервера может означать простой вашего сервиса. Доступность или недоступность сайта называется «доступностью» в индустрии программного обеспечения. Если весь ваш сайт привязан к большому вертикально масштабируемому серверу, то в случае возникновения проблем он может стать единой точкой отказа.
Во-вторых, вертикально масштабируемая услуга может быть более затратной для вас. По моему опыту, большинство веб-сайтов имеют высокие и низкие периоды использования в течение дня. Например, мой нынешний работодатель — американская медицинская компания, которая предоставляет услуги телемедицины для людей, которым необходимо виртуально пообщаться с врачом. Когда в США сейчас середина ночи, загрузка сайта, естественно, ниже, поскольку большинство людей спят.
Одним из распространенных способов оптимизации затрат является использование меньшего количества вычислительных ресурсов в периоды низкой загрузки. В вертикально масштабируемом сервисе сложнее быстро изменить размер компьютера. Таким образом, использование вычислительных ресурсов относительно фиксировано, даже если никто не пользуется вашим сервисом. В отличие от этого, горизонтально масштабируемая служба может быть настроена на использование «автомасштабирования».
Автомасштабирование — это идея о том, что размер инфраструктуры может изменяться динамически, в зависимости от использования сайта. В периоды высокой активности можно автоматически добавлять больше компьютеров, чтобы они присоединялись к распределению балансировщика нагрузки и обрабатывали дополнительную нагрузку. Когда активность снижается, эти дополнительные компьютеры могут быть удалены из использования. Эта техника экономии помогает обеспечить, чтобы ваша система использовала только то, что ей необходимо.
Правда заключается в том, что если ваша система достигает достаточно большого размера и масштаба, то выбор горизонтального или вертикального масштабирования является ошибочным. По мере созревания и роста системы вам может понадобиться сочетание двух типов масштабирования, чтобы ваш сервис обладал нужными вам характеристиками (например, доступностью).
Я надеюсь, что помог вам вооружиться некоторыми инструментами ментального моделирования. С помощью этих инструментов вы должны иметь представление о том, как справиться с большим трафиком, когда ваш сайт станет дико популярным. 😄
В этом разделе мы сосредоточились на увеличении пропускной способности путем изменения инфраструктуры вашего сервиса, чтобы он мог выдерживать большую нагрузку. Теперь давайте перейдем от макро- к микро- точке зрения и поговорим о том, как повысить пропускную способность, делая меньше.
Делать меньше
Как сделать так, чтобы ваш Django-сайт выполнял меньше работы? Мы всегда должны измерять, но поскольку я считаю, что большинство веб-сайтов связаны с вводом-выводом, давайте сосредоточимся на методах улучшения в этом аспекте.
Оптимизация запросов к базе данных
Самая распространенная проблема производительности, с которой я сталкивался в приложениях Django, — это ошибка N+1 запросов (некоторые люди называют ее ошибкой 1+N запросов по причинам, которые могут стать очевидными через некоторое время).
Ошибка N+1 возникает, когда код вашего приложения обращается к базе данных в цикле. Сколько запросов в этом выдуманном примере?
from application.models import Movie
movies = Movie.objects.all()
for movie in movies:
print(movie.director.name)
Это вопрос с подвохом, потому что у вас может быть собственный менеджер (например, objects
), но в самом простом сценарии есть один запрос для получения фильмов и один запрос для каждого режиссера.
Причина такого поведения заключается в том, что Django делает ленивую оценку QuerySet
фильмов. ORM не знает, что для получения всех данных необходимо выполнить объединение таблиц фильмов и режиссеров. Первый запрос к таблице фильмов происходит при итерации в цикле Python for
. Когда функция print
пытается получить доступ к внешнему ключу director
, ORM не имеет информации о режиссерах, кэшированной в памяти Python для набора запросов. Django должен получить данные о режиссере в другом запросе к базе данных, чтобы отобразить имя режиссера.
В результате получается:
- 1 запрос к таблице фильмов
- N запросов к таблице директора для каждой итерации цикла
for
.
Отсюда и название, ошибка «N+1» запросов.
Причина, по которой это так плохо, заключается в том, что обращение к базе данных намного медленнее, чем обращение к данным в памяти Python. Кроме того, эта проблема усугубляется, если количество строк для итерации больше (т.е. больше фильмов для обработки и, следовательно, больше режиссеров для индивидуальной выборки).
Способ решить эту проблему — намекнуть Django, что код будет обращаться к данным из более глубоких отношений. Мы можем сделать этот намек для ORM с помощью select_related
. Давайте посмотрим пример с этим изменением.
from application.models import Movie
movies = Movie.objects.select_related("director").all()
for movie in movies:
print(movie.director.name)
В переработанном примере ORM будет «знать», что ему нужно получить данные директора. Благодаря этой дополнительной информации, фреймворк будет получать данные из таблиц movie и director в одном запросе, когда начнется итерация цикла for
.
Под капотом Django выполняет более сложный запрос SELECT
, который включает объединение двух таблиц. База данных отправляет обратно все данные сразу, а Django кэширует их в памяти Python. Теперь, когда выполнение достигает строки print
, атрибут director.name
может быть извлечен из памяти вместо того, чтобы запускать еще один запрос к базе данных.
Экономия производительности здесь может быть значительной, особенно если ваш код работает с большим количеством строк базы данных одновременно.
Хотя select_related
является фантастическим, он работает не для всех сценариев. Другие типы отношений, такие как отношения «многие ко многим», не могут быть найдены в одном запросе. Для таких сценариев вы можете использовать prefetch_related
. С помощью этого метода Django выполнит меньшее количество запросов (обычно 1 на таблицу) и объединит результаты в памяти. На практике, prefetch_related
работает очень похоже на select_related
в большинстве случаев. Посмотрите документацию Django, чтобы понять больше.
Кэширование дорогостоящей работы
Если вы знаете:
- Выполнение, вероятно, будет происходить много раз
- дорого создавать, И
- не будет нуждаться в изменениях
Тогда вы смотрите на работу, которая является очень хорошим кандидатом для кэширования. С помощью кэширования Django может сохранить результаты некоторой дорогостоящей операции в очень быстром кэше и восстановить эти результаты позже.
Хорошим примером может быть новостной сайт. Новостной сайт очень «тяжел для чтения», то есть пользователи чаще используют сайт для просмотра информации, чем для записи и сохранения информации на сайте. Новостной сайт также является хорошим примером, потому что пользователи будут читать одну и ту же статью, и содержание этой статьи имеет фиксированную форму.
Django включает инструменты, упрощающие работу с кэшем для оптимизации контента, как в нашем примере с новостным сайтом.
Самым простым из этих инструментов является декоратор cache_page
. Этот декоратор может кэшировать результаты всего представления Django на определенный период времени. Когда страница не имеет никакой персонализации, это может быть быстрым и эффективным способом предоставления HTML результатов из представления. Вы можете найти этот декоратор в django.views.decorators.cache
.
Вам может понадобиться более низкий уровень детализации, чем целая страница. Например, на вашем сайте может быть какой-то зарегистрированный пользователь и настроенная панель навигации с изображением профиля или что-то подобное. В этом случае вы не можете кэшировать всю страницу и предоставлять ее нескольким пользователям, поскольку другие пользователи будут видеть настроенную панель навигации первого пользователя, сделавшего запрос. Если вы находитесь в подобной ситуации, то тег шаблона cache
может быть лучшим инструментом для вас.
Вот пример использования тега шаблона cache
.
{% load cache %}
Hi {{ user.username }}, this part won't be cached.
{% cache 600 my_cache_key_name %}
Everything inside of here will be cached.
The first argument to `cache` is how long this should be cached
in seconds. This cache fragment will cache for 10 minutes.
Cached chunks need a key name to help the cache system
find the right cache chunk.
This cache example usage is a bit silly because this is static text
and there is no expensive computation in this chunk.
{% endcache %}
При такой схеме все дорогостоящие вычисления, которые выполняет ваш шаблон, будут кэшироваться. Будьте осторожны с этим тегом! Этот тег полезен, если вычисления происходят во время рендеринга, но если вы выполняете оценку и выборку внутри представления, а не во время рендеринга шаблона, то вы вряд ли получите желаемые преимущества.
Наконец, есть возможность использовать интерфейс кэша напрямую. Вот основная схема использования:
# application/views.py
from django.core.cache import cache
from application.complex import calculate_expensive_thing
def some_view(request):
expensive_result = cache.get("expensive_computation")
if expensive_result is None:
expensive_result = calculate_expensive_thing()
cache.set("expensive_computation", expensive_result)
# Handle the rest of the view.
...
При первом запросе к этому представлению expensive_result
не будет в кэше, поэтому представление вычислит результат и сохранит его в кэше. При последующих запросах дорогой результат может быть извлечен из кэша. В этом примере я использую таймаут по умолчанию для кэша, но вы можете управлять значениями таймаута, если вам нужно больше контроля. Система кэширования имеет множество других замечательных возможностей, поэтому ознакомьтесь с ней в документации.
Предупреждаем, что кэширование часто требует дополнительных инструментов и настроек. Django работает с очень популярными инструментами кэширования, такими как Redis и Memcached, но вам придется настроить один из инструментов самостоятельно. Документация Django поможет вам, но будьте готовы к тому, что вам придется потрудиться.
Оптимизация баз данных и кэширование — это техники оптимизации. Когда вы оптимизируете, как вы узнаете, что делаете это правильно? Какие результаты вы получаете? Давайте рассмотрим некоторые инструменты, которые позволят вам ответить на эти вопросы.
Инструменты для измерения изменений
Мы рассмотрим инструменты с возрастающим уровнем сложности. Первый инструмент — это инструмент, который очень полезен при разработке на Django. Остальные инструменты — это инструменты более общего назначения, но о них все равно стоит знать, чтобы знать, когда к ним обращаться.
Каждый из этих инструментов помогает вам получить реальные данные о производительности. Измеряя «до» и «после» ваших изменений, вы можете узнать, действительно ли эти изменения дают тот прирост, которого вы ожидаете или надеетесь достичь.
Панель инструментов отладки Django
Django Debug Toolbar — это важный инструмент, который я добавляю в свои проекты. Панель инструментов действует как накладка на ваш сайт, которая открывается, чтобы предоставить вам лоток с различными категориями диагностической информации о ваших представлениях.
Каждая категория информации сгруппирована в «панель», и вы можете выбирать между различными панелями, чтобы найти информацию, которая поможет вам в работе по оптимизации.
Вы найдете такие панели, как:
- SQL
- Шаблоны
- Запрос
- Время
Панель SQL — это то место, где я провожу почти все свое время при оптимизации. На этой панели отображаются все запросы, которые запрашивает страница. Для каждого запроса можно узнать, какой код вызвал запрос к базе данных, и даже получить точный SQL SELECT
. Вы также можете получить EXPLAIN
о запросе, если вам действительно нужны подробные сведения о том, что делает база данных.
Немного потренировав зрение, вы научитесь обнаруживать ошибки в N+1 запросах, потому что вы увидите, как определенные запросы повторяются снова и снова и «каскадируют», как водопад.
Я часто тестирую с помощью панели отладки, когда пытаюсь добавить select_related
, чтобы визуально подтвердить, что я уменьшил количество запросов на странице. Панель инструментов отладки имеет открытый исходный код и является отличным бесплатным ресурсом. Панель инструментов полностью стоит того, чтобы потратиться на ее настройку для вашего следующего проекта Django.
hey / ab
Есть два очень похожих инструмента, которые я использую, когда мне нужно получить грубую оценку производительности сайта. Это инструменты hey и ab (Apache Bench). Оба эти инструмента представляют собой генераторы нагрузки, предназначенные для оценки основных характеристик производительности сайта.
На практике я предпочитаю hey
, но я упоминаю ab
, потому что это хорошо известный инструмент в этой области, с которым вы, скорее всего, столкнетесь, если будете исследовать тему генераторов нагрузки.
Управление таким инструментом тривиально:
$ hey https://www.example.com
В этом примере hey попытается открыть большое количество одновременных соединений с URL и сделать кучу запросов. Когда инструмент закончит работу, он сообщит о том, сколько запросов было успешным, а также о некоторой связанной с этим временной информации и статистике. Использование такого генератора нагрузки позволяет синтезировать трафик, чтобы узнать, как будет работать ваш сайт.
Я бы посоветовал вам быть осторожными с тем, где вы используете эти инструменты. Если вы не будете осторожны, вы можете вызвать атаку типа «отказ в обслуживании» на свои собственные машины. Поток запросов может сделать ваш сайт недоступным для других пользователей, поскольку он будет потреблять все ресурсы вашего сервера. Подумайте дважды, прежде чем направлять это на ваш живой сайт!
Саранча
Предыдущие инструменты генератора нагрузки, которые я упоминал, действуют как несколько грубые измерения, потому что вы ограничены тестированием одного URL за раз. Что же делать, если вам нужно смоделировать трафик, который соответствует реальным моделям использования сайта пользователями? На помощь приходит Locust. Locust — это не тот инструмент, который я бы взял в руки случайно, но он очень крут и о нем стоит знать.
Цель Locust — провести нагрузочное тестирование вашего сайта реалистичным способом. Это означает, что ваша задача — смоделировать ожидаемое поведение ваших пользователей в понятной для машины форме. Если вы хорошо знаете своих пользователей (а я надеюсь, что это так), то вы можете представить себе потоки, которым они могут следовать при работе с вашим сайтом.
В Locust вы кодируете модели поведения, которые вас интересуют, а затем запускаете Locust для моделирования большого количества пользователей, которые будут вести себя так, как вы ожидаете (со случайностью в придачу, чтобы сделать тест похожим на реальность).
Расширенное нагрузочное тестирование — это то, что вам, возможно, никогда не понадобится для вашего сайта, но очень приятно знать, что Python поможет вам, если вам нужно понять производительность и ограничения вашего сайта на таком глубоком уровне.
Мониторинг производительности приложений (APM)
Ранее в этой статье я упоминал, что инструменты мониторинга производительности приложений могут показать вам загрузку процессора и памяти вашего сайта. Обычно это лишь верхушка айсберга.
Инструмент APM часто выходит далеко за рамки измерения аппаратных ресурсов. Мне нравится думать об APM как об усовершенствованной версии панели инструментов отладки.
Во-первых, APM обычно используется на живых сайтах. Инструмент собирает данные о реальных запросах. Это позволит вам узнать о реальных проблемах производительности на сайте, которые влияют на реальных пользователей.
Например, New Relic собирает данные о медленных запросах в «трассы». Эти трассировки объединяются в набор, чтобы показать вам, какие страницы на вашем сайте работают хуже всего. Вы можете углубиться в этот список, просмотреть отдельные трассы и изучить проблему.
Может быть, у вас ошибка N+1. Возможно, в одной из таблиц вашей базы данных отсутствует индекс для важного поля, и база данных сканирует слишком много записей во время операторов SELECT
. Эти трассировки (или как они называются в других службах) помогут вам определить приоритеты, что нужно исправить.
Фактически, APM подчеркивает истинную ценность измерений. Если я могу оставить вас с мыслью об оптимизации, подумайте вот о чем: оптимизируйте там, где это важно.
Вот простой мысленный эксперимент, иллюстрирующий то, что я имею в виду. У вас есть идеализированная система, которая многократно выполняет две задачи:
- Одна задача (А) составляет 90% всей активности на сайте.
- Другая задача (B) — это оставшиеся 10%.
Если вам нужно выбрать цель для оптимизации, поскольку производительность системы недостаточна, какую из них вы выберете?
Предположим, что вы знаете оптимизацию для каждого типа задач, которая может привести к тому, что задача будет выполняться за 50% времени. Если реализация каждой оптимизации требует одинакового уровня усилий, то в вопросе о том, какую задачу следует оптимизировать, есть явный победитель. Вы можете либо:
- Оптимизировать A на 90% * 50% для общей экономии системы в 45%.
- Оптимизировать B на 10% * 50% для общей экономии системы в 5%.
При большинстве обстоятельств, потратьте свои усилия по оптимизации на ту область, которая будет иметь наибольшее влияние (т.е. выберите задачу А, насколько это возможно). Иногда сложнее всего определить, какая задача относится к A, а какая — к B. Инструменты мониторинга, такие как APM, помогут вам увидеть, где находятся самые худшие нарушители, чтобы вы могли направить свое ограниченное время в нужное русло.
Резюме
В этой статье мы рассмотрели, как сделать приложения Django быстрыми. Мы увидели:
- Ментальную модель для размышлений об оптимизации производительности
- Различные типы узких мест в производительности
- Как заставить вашу систему делать больше с помощью горизонтального или вертикального масштабирования
- Как заставить ваше приложение выполнять меньше работы, оптимизируя запросы к базе данных и кэширование.
- Инструменты, которые помогут вам в этой работе по оптимизации.
В следующей статье мы рассмотрим вопросы безопасности. Вы узнаете о:
- Как Django помогает вам быть более безопасным благодаря некоторым особенностям дизайна.
- Что означают эти различные предупреждения из
./manage.py check --deploy
. - Фундаментальные вещи, которые следует учитывать для обеспечения безопасности вашего сайта.
Если вы хотите следить за этой серией статей, пожалуйста, подпишитесь на мою рассылку, в которой я анонсирую все свои новые материалы. Если у вас есть другие вопросы, вы можете связаться со мной в Twitter, где я @mblayman.