Протоколи для веб-додатків wsgi та asgi.
Основи роботи з Linux. -> Протоколи для веб-додатків wsgi та asgi.
Протоколи для веб-додатків wsgi та asgi.
Протокол CGI
CGI (від англ. Common Gateway Interface - “загальний інтерфейс шлюзу”) - стандарт інтерфейсу, що використовується для зв’язку зовнішньої програми з веб-сервером.
Програму, яка працює за таким інтерфейсом спільно з веб-сервером, прийнято називати шлюзом, хоча багато хто віддає перевагу назвам «скрипт» (сценарій) або «CGI-програма».
Сам інтерфейс розроблений таким чином, щоб можна було використовувати будь-яку мову програмування, яка може працювати зі стандартними пристроями вводу-виводу.
Оскільки гіпертекст статичний за своєю природою, веб-сторінка не може безпосередньо взаємодіяти з користувачем. До появи JavaScript, не було іншої можливості відреагувати на дії користувача, крім передати введені ним дані на веб-сервер для подальшої обробки. У разі CGI ця обробка здійснюється за допомогою зовнішніх програм та скриптів, звернення до яких виконується через стандартизований інтерфейс – загальний шлюз.
Як працює CGI?
Узагальнений алгоритм роботи через CGI можна подати у такому вигляді:
Клієнт запитує CGI-додаток з його URI.
Веб-сервер приймає запит та встановлює змінні оточення, через них додатку передаються дані та службова інформація.
Веб-сервер перенаправляє запити через стандартний потік введення (stdin) на вхід програми, що викликається.
CGI-додаток виконує всі необхідні операції та формує результати у вигляді HTML.
Сформований гіпертекст повертається до веб-сервера через стандартний потік виведення (stdout). Повідомлення про помилки надсилаються через stderr.
Веб-сервер передає результати запиту клієнта.
Подальший розвиток технології CGI породило швидшу версію FastCGI, яка підтримується багатьма веб-серверами, наприклад Nginx.
FastCGI, замість створення нових процесів для кожного нового запиту, використовує постійно запущені процеси для обробки безлічі запитів.
Всі CGI-програми мають доступ до змінних оточення, які встановлюються веб-сервером. Ці змінні відіграють важливу роль під час написання CGI-програм.
Протокол 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 і т.д.) до веб-додатків.
Принцип роботи.
Для того, щоб запустити програму в режимі wsgi, необхідна програма-завантажувач.
uWSGI
Це завантажувач, написаний С. Тому вимагає наступного для складання.
apt-get install build-essential python-dev
pip install wheel
Він залежить від мови програмування.
Встановлення.
pip install uwsgi
Простий запуск говорить про те, чого не вистачає.
Найпростіший 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
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
При цьому необхідно запускати 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.
Приріст продуктивності для 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
Рестарт процесу.
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, і часто представляється як його наступник із вбудованою асинхронністю.
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
Можливий вигляд архітектури сервера.
Встановлення 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