Разные проекты на Python Django./ Протоколы для веб-приложений wsgi и asgi.

Протоколы для веб-приложений wsgi и asgi.

Протокол wsgi

WSGI (англ. Web Server Gateway Interface) — стандарт взаимодействия между Python-программой, выполняющейся на стороне сервера, и самим веб-сервером, например Nginx.

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

WSGI предоставляет простой и универсальный интерфейс между большинством веб-серверов и веб-приложениями или фреймворками.

Принцип работы.

login angular form

Для того, чтобы запустить приложение в режиме wsgi необходима программа-загрузчик.

uWSGI

Это загрузчик, написанный на С. Поэтому требует следующего для сборки.

apt-get install build-essential python-dev
pip install wheel

Он не зависит от языка программирования.

Установка.

pip install uwsgi

Простой запуск говорит о том, чего нехватает.

login angular form

Простейшее WSGI приложение start.py.

def application(env, start_response):
    start_response('200 OK', [('Content-Type','text/html')])
    return [b"Hello World"]

Запускаем.

uwsgi --http :9090 --wsgi-file start.py

По умолчанию загрузчик ищет функцию application, но это можно поменять.

 uwsgi --http :9090 --wsgi-file start.py --callable myapp

Использование –http делает из загрузчика еще и веб-сервер (роутер HTTP). Но при использовании отдельного вебсервера например nginx запуск проводится на сокете –http-socket и из него проксируется внутри nginx.

Паралелизм.

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

uwsgi --http :9090 --wsgi-file start.py --master --processes 4 --threads 2

Это породит 4 процесса (каждый по 2 потока).

–master - будет рестартить их в случае обрушения

Мониторинг.

uwsgi --http :9090 --wsgi-file  start.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191

Используя telnet можно получить статистику.

telnet 127.0.0.1 9191

login angular form

Telnet - самый простой способ глянуть открытый порт.

Если хочется увидеть в браузере то добавляем –stats-http

 uwsgi --http :9090 --wsgi-file  start.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191 --stats-http

uwsgitop

Продвинутый инструмент мониторинга.

pip install uwsgitop

Запуск.

uwsgitop http://127.0.0.1:9191

login angular form

Установка загрузчика за реальным веб-сервером.

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

uwsgi --socket 127.0.0.1:3031 ...

При этом появляется возможность проксировать внутри виртуального хоста nginx.

location / {
    include uwsgi_params;
    uwsgi_pass 127.0.0.1:9090;
}

При этом каждый запрос будет переправлятся загрузчику на 9090 порт

При проксировании по http протоколу можно указать в загрузчике так

uwsgi --http-socket 127.0.0.1:9090 ...

Деплой Django проекта.

В Django мы имеем стартовый файл для wsgi.

login angular form

Прирост производительности для wsgi около 20-30% против ./manage.py runserver

Пример файла для теста.

import requests
import time
startTime = time.time()

for i in range(1,1000):
    res = requests.get('http://localhost:8000')

executionTime = (time.time() - startTime)
print('Execution time in seconds: ' + str(executionTime))

Используем его.

uwsgi --socket 127.0.0.1:9090 --chdir /home/zdimon/Desktop/sgi/prj --wsgi-file prj/wsgi.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191

–chdir - меняем каталог т.к. джанге нужен путь для импорта модульков

Использование настроечного файла.

Мы можем создать настроечный файл для укорочения команды wsgi.conf

[uwsgi]
socket = 127.0.0.1:9090
chdir = /home/zdimon/Desktop/sgi/prj
wsgi-file = prj/wsgi.py
processes = 4
threads = 2
stats = 127.0.0.1:9191

И пускать так

uwsgi wsgi.conf

Не стоит запускать загрузчик из под рута, не безопасно это!

Можно указывать владельца так:

[uwsgi]
uid = user
gid = group

Зависшие процессы.

Иногда процессы подвисают, и чтобы их сбрасывать по таймауту в 30 сек делайте так:

[uwsgi]
...
harakiri = 30

Автозагрузка.

Для обеспечения автозагрузки и перезапуска uwsgi вокера будем использовать питонячую либу supervisor

ссылка на доку

Установка.

sudo apt install supervisor

Создаем конфиг /etc/supervisor/conf.d/dj.conf.

[program:prj]
user = zdimon
directory = /home/zdimon/Desktop/sgi/prj
command = /home/zdimon/Desktop/sgi/venv/bin/uwsgi /home/zdimon/Desktop/sgi/wsgi.ini
autostart = true
autorestart = true
stderr_logfile =/home/zdimon/Desktop/sgi/prj/uwsgi-err.log
stdout_logfile =/home/zdimon/Desktop/sgi/prj/uwsgi-out.log
stopsignal = QUIT

Перечитать конфигурацию.

sudo supervisorctl update

Посмотреть статус процессов.

sudo supervisorctl status

login angular form

Рестарт процесса.

sudo supervisorctl restart prj

Протокол asgi.

В отличие от JavaScript или Go, в момент появления Python не предоставлял возможность асинхронного исполнения кода. Долгое время параллельное выполнение кода в Python могло быть реализовано только с помощью многопоточной или многопроцессорной обработки.

Все изменилось в Python 3.4+. В Python 3.4 в стандартную библиотеку включили asyncio, в результате появилась поддержка кооперативной многозадачности на основе генераторов и синтаксиса yield from.

Позже в Python 3.5 добавлен синтаксис async/await.

C помощью них функции превращают в корутины (сопрограммы).

С момента выпуска версии 3.5 сообщество буквально асинхронизовывает все вокруг.

Сопрограмма (англ. coroutine) — программный модуль, особым образом организованный для обеспечения взаимодействия с другими модулями по принципу кооперативной многозадачности: модуль приостанавливается в определённой точке, сохраняя полное состояние (включая стек вызовов и счётчик команд), и передаёт управление другому, тот, в свою очередь, выполняет задачу и передаёт управление обратно, сохраняя свои стек и счётчик.

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

Подпрограмма может возвращаться только однажды, сопрограмма может возвращать управление несколько раз.

Верхнеуровнево ASGI можно рассматривать как связующее звено, которое позволяет асинхронным Python серверам и приложениям взаимодействовать друг с другом. Он повторяет множество архитектурных идей из WSGI, и зачастую представляется как его преемник со встроенной асинхронностью.

login angular form

ASGI состоит из двух различных компонентов:

Сервера протокола (protocol server) — слушает сокеты и преобразует их в соединения и сообщения о событиях внутри каждого соединения.

Приложения (application), которое живет внутри сервера протокола, его экземпляр создается один раз для каждого соединения и обрабатывает сообщения о событиях по мере их возникновения.

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

На самом деле, все, что представляет собой ASGI-приложение — это callable (вызываемый объект).

Параметры этого вызываемого объекта:

async def app(scope, receive, send):
    ...

Параметры функции:

scope — это словарь, содержащий информацию о входящем запросе. Его содержимое отличается для HTTP и WebSocket соединений.

receive — асинхронная функция для получения сообщений о событиях ASGI.

send — асинхронная функция для отправки сообщений о событиях ASGI.

По сути, эти параметры позволяют получать (receive()) и передавать (send()) данные по каналу связи, который поддерживает сервер протокола, а также понимать, в каком контексте (или scope) этот канал был создан.

Деплой ASGI приложения для Django

Установка загрузчика.

pip install daphne

Запуск сервера.

daphne prj.asgi:application
Задать вопрос, прокомментировать.