Протоколи для веб-додатків 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 з прапором –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.

За допомогою них функції перетворюють на корутини (супрограми).

З моменту випуску версії 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