Как оптимизировать производительность приложения Flask

0 Акции
0
0
0
0

Введение

Flask — это лёгкий и гибкий веб-фреймворк для разработки небольших и средних приложений. Он широко используется в проектах от простых личных блогов до более сложных приложений, таких как REST API, SaaS-платформы, сайты электронной коммерции и информационные панели, управляемые данными.

Однако по мере увеличения трафика или сложности вашего приложения вы можете столкнуться с проблемами производительности. Независимо от того, разрабатываете ли вы систему управления контентом (CMS), API для мобильного приложения или инструмент визуализации данных в реальном времени, оптимизация производительности Flask имеет решающее значение для обеспечения отзывчивого и масштабируемого пользовательского опыта.

В этом руководстве вы изучите методы и передовые практики оптимизации производительности приложения Flask.

Предпосылки
  • Сервер под управлением Ubuntu, пользователь без прав root с правами sudo и включённым брандмауэром. Инструкции по настройке см. в нашем руководстве «Начало работы с сервером». Убедитесь, что вы используете поддерживаемую версию Ubuntu.
  • Знакомство с командной строкой Linux. Для получения вводных или освежающих знаний о командной строке вы можете обратиться к данному руководству Linux Command Line Primer.
  • Базовые знания программирования на Python.
  • В вашей системе Ubuntu установлен Python 3.7 или более поздней версии. Чтобы узнать, как запускать скрипты Python в Ubuntu, ознакомьтесь с нашим руководством по запуску скриптов Python в Ubuntu.

Настройка среды Flask

Ubuntu 24.04 по умолчанию поставляется с Python 3. Откройте терминал и выполните следующую команду, чтобы проверить установку Python 3:

root@ubuntu:~# python3 --version
Python 3.12.3

Если Python 3 уже установлен на вашем компьютере, указанная выше команда вернет текущую версию Python 3. Если она не установлена, вы можете выполнить следующую команду и получить установленный Python 3:

root@ubuntu:~# sudo apt install python3

Далее вам необходимо установить установщик пакета pip в вашей системе:

root@ubuntu:~# sudo apt install python3-pip

После установки pip давайте установим Flask.

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

root@ubuntu:~# python3 -m venv myprojectenv
root@ubuntu:~# source myprojectenv/bin/activate
root@ubuntu:~# pip install Flask

Создать приложение Flask

Следующий шаг — написать код Python для приложения Flask. Чтобы создать новый скрипт, перейдите в каталог по вашему выбору:

root@ubuntu:~# cd ~/path-to-your-script-directory

В этом каталоге создайте новый файл Python app.py и импортируйте Flask. Затем инициализируйте приложение Flask и создайте корневой путь.

root@ubuntu:~# nano app.py

Откроется пустой текстовый редактор. Напишите здесь свою логику или скопируйте код ниже:

from flask import Flask, jsonify, request
app = Flask(__name__)
# Simulate a slow endpoint
@app.route('/slow')
def slow():
import time
time.sleep(2) # to simulate a slow response
return jsonify(message="This request was slow!")
# Simulate an intensive database operation
@app.route('/db')
def db_operation():
# This is a dummy function to simulate a database query
result = {"name": "User", "email": "[email protected]"}
return jsonify(result)
# Simulate a static file being served
@app.route('/')
def index():
return "<h1>Welcome to the Sample Flask App</h1>"
if __name__ == '__main__':
app.run(debug=True)

Теперь запустим приложение Flask:

root@ubuntu:~# flask run

Вы можете протестировать конечные точки с помощью следующих команд curl:

Протестируйте конечную точку / (возвращает статическое содержимое):

root@ubuntu:~# curl http://127.0.0.1:5000/
[secondary_lebel Output]
<h1>Welcome to the Sample Flask App</h1>%

Тест конечной точки/медленно (имитирует медленный ответ):

root@ubuntu:~# time curl http://127.0.0.1:5000/db

Для проверки этой медленной конечной точки мы используем команду time в Linux. Команда time используется для измерения времени выполнения конкретной команды или программы. Она предоставляет три основных вида информации:

  1. Реальное время: фактическое время, прошедшее с начала до конца команды.
  2. Пользовательское время: количество процессорного времени, проведенного в пользовательском режиме.
  3. Системное время: количество процессорного времени, проведенного в режиме ядра.

Это поможет нам измерить фактическое время, затраченное нашей медленной конечной точкой. Вывод может выглядеть примерно так:

Output
{"message":"This request was slow!"}
curl http://127.0.0.1:5000/slow 0.00s user 0.01s system 0% cpu 2.023 total

Для ответа на этот запрос требуется около 2 секунд, поскольку вызов time.sleep(2) имитирует медленный ответ.

Давайте проверим конечную точку /db (симулирует операции с базой данных):

root@ubuntu:~# curl http://127.0.0.1:5000/db
Output
{"email":"[email protected]","name":"User"}

Протестировав эти конечные точки с помощью curl, вы можете убедиться, что ваше приложение Flask работает правильно и ответы соответствуют ожидаемым.

В следующем разделе вы научитесь оптимизировать производительность приложений, используя различные методы.

Используйте готовый к использованию сервер WSGI

Встроенный сервер разработки Flask не предназначен для производственной среды. Для эффективной обработки параллельных запросов следует использовать готовый к эксплуатации WSGI-сервер, например Gunicorn.

Установка и запуск Gunicorn

Давайте установим Gunicorn.

root@ubuntu:~# pip install gunicorn

Запустите приложение Flask с помощью Gunicorn с 4 рабочими процессами:

root@ubuntu:~# gunicorn -w 4 -b 0.0.0.0:8000 app:app
Output
% /Library/Python/3.9/bin/gunicorn -w 4 -b 0.0.0.0:8000 app:app
[2024-09-13 18:37:24 +0530] [99925] [INFO] Starting gunicorn 23.0.0
[2024-09-13 18:37:24 +0530] [99925] [INFO] Listening at: http://0.0.0.0:8000 (99925)
[2024-09-13 18:37:24 +0530] [99925] [INFO] Using worker: sync
[2024-09-13 18:37:24 +0530] [99926] [INFO] Booting worker with pid: 99926
[2024-09-13 18:37:25 +0530] [99927] [INFO] Booting worker with pid: 99927
[2024-09-13 18:37:25 +0530] [99928] [INFO] Booting worker with pid: 99928
[2024-09-13 18:37:25 +0530] [99929] [INFO] Booting worker with pid: 99929
[2024-09-13 18:37:37 +0530] [99925] [INFO] Handling signal: winch
^C[2024-09-13 18:38:51 +0530] [99925] [INFO] Handling signal: int
[2024-09-13 18:38:51 +0530] [99927] [INFO] Worker exiting (pid: 99927)
[2024-09-13 18:38:51 +0530] [99926] [INFO] Worker exiting (pid: 99926)
[2024-09-13 18:38:51 +0530] [99928] [INFO] Worker exiting (pid: 99928)
[2024-09-13 18:38:51 +0530] [99929] [INFO] Worker exiting (pid: 99929)
[2024-09-13 18:38:51 +0530] [99925] [INFO] Shutting down: Master

Вот преимущества использования Gunicorn:

  • Одновременная обработка запросов: Gunicorn позволяет обрабатывать несколько запросов одновременно, используя несколько рабочих процессов.
  • Балансировка нагрузки: балансирует входящие запросы между рабочими процессами и обеспечивает оптимальное использование ресурсов сервера.
  • Асинхронные исполнители: с помощью асинхронных исполнителей, таких как gevent, можно эффективно выполнять длительные задачи, не блокируя другие запросы.
  • Масштабируемость: Gunicorn может масштабироваться горизонтально, увеличивая количество рабочих процессов для обработки большего количества одновременных запросов.
  • Отказоустойчивость: Автоматически заменяет неотвечающие или неисправные рабочие процессы, обеспечивая высокую доступность.
  • Готовность к производству: в отличие от сервера разработки Flask, Gunicorn оптимизирован для производственных сред и обладает улучшенными характеристиками безопасности, стабильности и производительности.

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

Включите кэширование для снижения нагрузки.

Кэширование — один из лучших способов повысить производительность Flask за счёт снижения накладных расходов. В данном случае вы добавляете Flask-Caching для кэширования результатов выполнения медленного пути.

Установка и настройка Flask-Caching с Redis

Установите необходимые пакеты:

root@ubuntu:~# pip install Flask-Caching redis

Обновите app.py, чтобы добавить кэш в slow/path.

Откройте редактор и обновите файл app.py с помощью следующей команды:

root@ubuntu:~# nano app.py
from flask_caching import Cache
app = Flask(__name__)
# Configure Flask-Caching with Redis
app.config['CACHE_TYPE'] = 'redis'
app.config['CACHE_REDIS_HOST'] = 'localhost'
app.config['CACHE_REDIS_PORT'] = 6379
cache = Cache(app)
@app.route('/slow')
@cache.cached(timeout=60)
def slow():
import time
time.sleep(2) # Simulate a slow response
return jsonify(message="This request was slow!")

После первого запроса к /slow последующие запросы обслуживаются из кэша в течение 60 секунд, минуя функцию time.sleep(). Это снижает нагрузку на сервер и увеличивает скорость ответа.

Примечание: В этом руководстве мы используем localhost в качестве хоста Redis. Однако в производственной среде рекомендуется использовать управляемый сервис Redis, например, DigitalOcean Managed Redis. Это обеспечивает лучшую масштабируемость, надежность и безопасность для ваших потребностей в хранении данных. Подробнее об интеграции DigitalOcean Managed Redis в приложение производственного уровня см. в этом руководстве «Использование хранилища DigitalOcean Redis на платформе приложений».

 

Чтобы проверить, кэшируются ли данные, мы запускаем следующие команды для конечной точки /slow.

Это первый запрос к конечной точке /slow. После завершения этого запроса результат маршрута /slow кэшируется.

root@ubuntu:~# time curl http://127.0.0.1:5000/slow
Output
{"message":"This request was slow!"}
curl http://127.0.0.1:5000/slow 0.00s user 0.01s system 0% cpu 2.023 total

Это последующий запрос к конечной точке /slow в течение 60 секунд:

root@ubuntu:~# time curl http://127.0.0.1:5000/slow
Output
{"message":"This request was slow!"}
curl http://127.0.0.1:5000/slow 0.00s user 0.00s system 0% cpu 0.015 total

Оптимизация запросов к базе данных

Запросы к базе данных часто могут стать узким местом производительности. В этом разделе вы смоделируете оптимизацию запросов к базе данных с помощью SQLAlchemy и объединения пулов.

Моделирование запроса к базе данных с агрегацией соединений

Для начала давайте установим SQLAlchemy.

root@ubuntu:~# pip install Flask-SQLAlchemy

Обновите app.py, чтобы настроить интеграцию соединения.

rom flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
# Simulate an intensive database operation
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_POOL_SIZE'] = 5 # Connection pool size
db = SQLAlchemy(app)
@app.route('/db1')
def db_operation_pooling():
# Simulate a database query
result = db.session.execute(text('SELECT 1')).fetchall()
return jsonify(result=str(result))

Теперь, когда мы выполним curl-запрос к пути db1, мы должны увидеть следующий вывод:

root@ubuntu:~# curl http://127.0.0.1:5000/db1 
output
{"result":"[(1,)]"}

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

Конфигурация SQLALCHEMY_POOL_SIZE, установленная нами ранее, ограничивает количество подключений в пуле. Это значение следует настроить в рабочей среде в соответствии с вашими конкретными потребностями и возможностями сервера. Кроме того, вы можете рассмотреть другие параметры интеграции, такие как SQLALCHEMY_MAX_OVERFLOW, чтобы разрешить дополнительные подключения при заполнении пула, и SQLALCHEMY_POOL_TIMEOUT, чтобы указать, как долго запрос должен ожидать подключения.

Помните, что хотя в нашем примере для простоты используется SQLite, в реальной ситуации вы, вероятно, используете более надёжную базу данных, например, PostgreSQL или MySQL. Эти базы данных имеют собственные механизмы организации пулов соединений, которые можно использовать вместе с интеграцией SQLAlchemy для повышения производительности.

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

Включить сжатие Gzip

Сжатие ответов может значительно сократить объем данных, передаваемых между сервером и клиентами, и повысить производительность.

Установка и настройка Flask-Compress

Давайте установим пакет Flask-compress.

root@ubuntu:~# pip install Flask-Compress

Далее обновим app.py, чтобы включить сжатие.

from flask_compress import Compress
# This below command enables Gzip compression for the Flask app
# It compresses responses before sending them to clients,
# reducing data transfer and improving performance
Compress(app)
@app.route('/compress')
def Compress():
return "<h1>Welcome to the optimized Flask app !</h1>"

Это автоматически сжимает ответы размером более 500 байт, сокращая время передачи больших ответов.

В производственной среде сжатие Gzip может значительно сократить объем данных, передаваемых между сервером и клиентами, особенно для текстового контента, такого как HTML, CSS и JavaScript.

Сокращение объёма передаваемых данных приводит к ускорению загрузки страниц, улучшению пользовательского опыта и снижению затрат на полосу пропускания. Кроме того, многие современные веб-браузеры автоматически поддерживают сжатие Gzip, что делает его полностью совместимым методом оптимизации. Включив сжатие Gzip, вы можете эффективно повысить производительность и масштабируемость своего приложения Flask без необходимости внесения каких-либо изменений на стороне клиента.

Загрузка интенсивных задач в Celery

Ресурсоёмкие операции, такие как отправка электронных писем или обработка больших наборов данных, лучше всего перенести в фоновые задачи с помощью Celery. Это предотвратит блокировку входящих запросов длительными задачами.

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

Основные преимущества использования сельдерея:

  1. Улучшить время ответа на запросы пользователей
  2. Лучшая масштабируемость и управление ресурсами
  3. Возможность выполнять сложные и трудоемкие задачи, не блокируя основную программу
  4. Встроенная поддержка планирования задач и повторного выполнения невыполненных задач
  5. Простая интеграция с различными брокерами сообщений, такими как RabbitMQ или Redis

Используя Celery, вы можете быть уверены, что ваше приложение Flask будет оставаться отзывчивым даже при выполнении задач с интенсивными вычислениями или задачами, связанными с вводом-выводом.

Настройте Celery для фоновых задач

Давайте установим Celery.

root@ubuntu:~# pip install Celery

Далее обновим app.py, чтобы настроить Celery для асинхронных задач:

from celery import Celery
celery = Celery(app.name, broker='redis://localhost:6379/0')
@celery.task
def long_task():
import time
time.sleep(10) # Simulate a long task
return "Task Complete"
@app.route('/start-task')
def start_task():
long_task.delay()
return 'Task started'

В отдельном терминале запустите Celery Worker:

root@ubuntu:~# celery -A app.celery worker --loglevel=info
Output
------------- celery@your-computer-name v5.2.7 (dawn-chorus)
--- ***** ----- 
-- ******* ---- Linux-x.x.x-x-generic-x86_64-with-glibc2.xx 2023-xx-xx
- *** --- * --- 
- ** ---------- [config]
- ** ---------- .> app: app:0x7f8b8c0b3cd0
- ** ---------- .> transport: redis://localhost:6379/0
- ** ---------- .> results: disabled://
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. app.long_task
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] Connected to redis://localhost:6379/0
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] mingle: searching for neighbors
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] mingle: all alone
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] celery@your-computer-name ready.

Теперь выполните команду curl, чтобы перейти к пути /start-task, вывод будет следующим:

root@ubuntu:~# curl http://127.0.0.1:5000/start-task
Output
Task started

Это почти сразу вернет сообщение «Задача запущена», даже если фоновое задание все еще выполняется.

Функция start_task() выполняет две функции:

  • Вызывает функцию long_task.delay(), которая запускает задачу Celery асинхронно. Это означает, что задача ставится в очередь на выполнение в фоновом режиме, но функция не дожидается её завершения.
  • Он немедленно возвращает строку «Задача запущена».

Важно отметить, что реальная длительная задача (симулируемая 10-секундным сном) выполняется Celery асинхронно. Маршрут Flask не дожидается завершения этой задачи, прежде чем ответить на запрос.

Таким образом, если вы нарушите эту конечную точку, вы немедленно получите ответ «задание запущено», в то время как фактическое задание продолжит выполняться в фоновом режиме в течение 10 секунд.

Через 10 секунд после завершения фонового задания вы должны увидеть следующее сообщение-отчет:

Вывод будет примерно таким:

[2024-xx-xx xx:xx:xx,xxx: INFO/MainProcess] Task app.long_task[task-id] received
[2024-xx-xx xx:xx:xx,xxx: INFO/ForkPoolWorker-1] Task app.long_task[task-id] succeeded in 10.xxxs: 'Task Complete'

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

В производственной среде запуск Celery включает в себя следующее:

  1. Использование надежного брокера сообщений, такого как RabbitMQ
  2. Использование собственного бэкэнда результатов (например, PostgreSQL)
  3. Управление работниками с помощью систем контроля процессов (например, супервайзер)
  4. Внедрить инструменты мониторинга (например, цветы). Улучшить обработку ошибок и ведение журнала.
  5. Улучшенная обработка ошибок и ведение журнала
  6. Используйте приоритизацию задач
  7. Масштабирование с несколькими работниками на разных машинах
  8. Обеспечение соответствующих мер безопасности

Результат

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может понравиться