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

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

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

Протокол CGI

CGI (от англ. Common Gateway Interface — «общий интерфейс шлюза») — стандарт интерфейса, используемого для связи внешней программы с веб-сервером.

Программу, которая работает по такому интерфейсу совместно с веб-сервером, принято называть шлюзом, хотя многие предпочитают названия «скрипт» (сценарий) или «CGI-программа».

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

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

Как работает CGI?

cgi

Обобщенный алгоритм работы через CGI можно представить в следующем виде:

Клиент запрашивает CGI-приложение по его URI.

Веб-сервер принимает запрос и устанавливает переменные окружения, через них приложению передаются данные и служебная информация.

Веб-сервер перенаправляет запросы через стандартный поток ввода (stdin) на вход вызываемой программы.

CGI-приложение выполняет все необходимые операции и формирует результаты в виде HTML.

Сформированный гипертекст возвращается веб-серверу через стандартный поток вывода (stdout). Сообщения об ошибках передаются через stderr.

Веб-сервер передает результаты запроса клиенту.

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

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

Все CGI-приложения имеют доступ к переменным окружения, устанавливаемым веб-сервером. Эти переменные играют важную роль при написании CGI-программ.

login angular form

Протокол wsgi

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

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

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

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

WSGI (произносится как «whiz-gee») был разработан Филиппом Дж. Эби в начале 2000-х годов. Модуль Apache, известный как mod_python, разработанный Григорием Трубецким в конце 90-х годов, на тот момент обрабатывал большую часть Python-приложений. Однако mod_python не был официальной спецификацией. Он был просто создан, чтобы разработчики могли запускать код Python на сервере.

WSGI(Web-Server Gateway Interface) является потомком CGI(Common Gateway Interface). Когда веб начал развиваться, CGI разрастался из-за поддержки огромного количества языков и из-за отсутствия других решений. Однако, такое решение было медленным и ограниченным. WSGI был разработан как интерфейс для маршрутизации запросов от веб-серверов(Apache, Nginx и т.д.) на веб-приложения.

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

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

При этом необходимо запускать uwsgi c флагом –stats-http

Например

./venv/bin/uwsgi --http :9090 --wsgi-file  imagin/imagin/wsgi.py --master --processes 4 --threads 2 --stats 127.0.0.1:9191 --stats-http

./venv/bin/uwsgitop http://127.0.0.1:9191

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

Для того, чтобы исключить 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

Возможный вид архитектуры сервера.

login angular form

Установка PHP

В начале устанавливаем менеджер просессов PHP.

sudo apt-get install php-fpm

Настройка.

sudo nano /etc/php/7.2/fpm/pool.d/www.conf

# listen = /var/run/php5-fpm.sock
listen = 127.0.0.1:9000
listen.owner = www-data
listen.group = www-data

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

sudo netstat -nlp | grep :9000

Настройка nginx

index index.html index.htm index.nginx-debian.html index.php;
root /home/zdimon/html;

...

location / {
    # First attempt to serve request as file, then
    # as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;

    location ~ [^/]\.php(/|$) {
        fastcgi_pass    127.0.0.1:9000;
        include snippets/fastcgi-php.conf;
    }
}

Перезапуск служб.

sudo service nginx restart
sudo service php7.2-fpm restart

Установка PHP 7.3

sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
sudo apt update


sudo apt install php7.3-fpm

Установка дополнительных пакетов.

sudo apt install php-gd
sudo apt install php-curl
sudo apt install php-zip


sudo apt install php7.3-gd
sudo apt install php7.3-curl
sudo apt install php7.3-zip

Установка mysql

sudo apt install mysql-server
sudo apt install mysql-workbench