Vamos a comparar el rendimiento de distintas configuraciones de servidores web sirviendo páginas dinámicas programadas con Python, en concreto vamos a servir un CMS Mezzanine (Instala algunas páginas de demostración durente la instalación: Would you like to install some initial demo pages?).
Las configuraciones que vamos a realizar son las siguientes:
- apache2 + Módulo wsgi
- apache2 + gunicorn
- apache2 + uwsgi
- nginx + gunicorn
- nginx + uwsgi
Tarea 1 (2 puntos)(Obligatorio): Documenta la instalación del módulo wsgi de apache2. Muestra los ficheros de configuración y muestra la ejecución del CMS.
Los paquetes necesarios son:
root@bob:/home/debian# apt install apache2 libapache2-mod-wsgi python-virtualenv python python-setuptools python-dev build-essential
Creamos un entorno virtual
debian@bob:~$ virtualenv mezzanine Running virtualenv with interpreter /usr/bin/python2 New python executable in /home/debian/mezzanine/bin/python2 Also creating executable in /home/debian/mezzanine/bin/python Installing setuptools, pkg_resources, pip, wheel...done. debian@bob:~$ cd mezzanine/ debian@bob:~/mezzanine$ source bin/activate (mezzanine) debian@bob:~/mezzanine$
En el entorno virtual instalamos mezzanine y creamos un proyecto
(mezzanine) debian@bob:~/mezzanine$ pip install mezzanine (mezzanine) debian@bob:~/mezzanine$ mezzanine-project mezza
Una vez creado, ejecutamos:
(mezzanine) debian@bob:~/mezzanine$ cd mezza/ (mezzanine) debian@bob:~/mezzanine/mezza$ python manage.py collectstatic (mezzanine) debian@bob:~/mezzanine/mezza$ python manage.py collecttemplates (mezzanine) debian@bob:~/mezzanine/mezza$ python manage.py createdb ... A site record is required. Please enter the domain and optional port in the format 'domain:port'. For example 'localhost:8000' or 'www.example.com'. Hit enter to use the default (127.0.0.1:8000): Creating default site record: 127.0.0.1:8000 ... Creating default account ... Username (leave blank to use 'debian'): Email address: m.romeroangulo@gmail.com Password: Password (again): Superuser created successfully. Installed 2 object(s) from 1 fixture(s) Would you like to install some initial demo pages? Eg: About us, Contact form, Gallery. (yes/no): yes Creating demo pages: About us, Contact form, Gallery ... Installed 16 object(s) from 3 fixture(s)
Lo siguiente es indicar los ALLOWED_HOSTS en mezza/local_settings.py:
# Domains for public site ALLOWED_HOSTS = ["172.22.200.103","127.0.0.1"]
Para configurar apache, copiamos el default a mezzanine.conf y cambiamos lo parámetros necesarios para que quede:
<VirtualHost *:80> DocumentRoot /home/debian/mezzanine/mezza/ Alias /static /home/debian/mezzanine/mezza/static <Directory /home/debian/mezzanine/mezza/static> Require all granted </Directory> <Directory /home/debian/mezzanine/mezza/mezza> <Files wsgi.py> Require all granted </Files> </Directory> WSGIDaemonProcess mezzanine \ python-home=/home/debian/mezzanine \ python-path=/home/debian/mezzanine/mezza/:/home/vagrant WSGIProcessGroup mezzanine WSGIScriptAlias / /home/debian/mezzanine/mezza/mezza/wsgi.py ErrorLog ${APACHE_LOG_DIR}/mezzanine.log CustomLog ${APACHE_LOG_DIR}/mezzanine.log combined </VirtualHost>
Los siguientes pasos son:
root@bob:/etc/apache2/sites-available# a2dissite 000-default.conf Site 000-default disabled. To activate the new configuration, you need to run: systemctl reload apache2 root@bob:/etc/apache2/sites-available# a2ensite mezzanine.conf Enabling site mezzanine. To activate the new configuration, you need to run: systemctl reload apache2 root@bob:/etc/apache2/sites-available# systemctl reload apache2
Nos aseguramos que los permisos son los correctos:
root@bob:/etc/apache2/sites-available# chown -R www-data. /home/debian/mezzanine/
Tarea 2 (2 puntos)(Obligatorio): Documenta la instalación y configuración de gunicorn y apache2. Muestra mezzanine funcionando y una comprobación de que, efectivamente, se está usando gunicorn.
La instalación de mezzanine es igual que el punto anterior.
Ahopra instalamos gunicorn en el entorno virtual:
debian@stuart:~/mezzanine$ source bin/activate (mezzanine) debian@bob:~/mezzanine$ pip install gunicorn
Salimos del entorno virtual y creamos el fichero de configuración del nuevo sitio:
debian@stuart:~/mezzanine/mezza$ cd /etc/apache2/sites-available/ debian@stuart:/etc/apache2/sites-available$ sudo nano gunicorn.conf <VirtualHost *:80> DocumentRoot /home/debian/mezzanine/mezza ProxyPass /static/ ! ProxyPass / http://127.0.0.1:8080/ <Directory /home/debian/mezzanine/> Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/mezzanineerror.log CustomLog ${APACHE_LOG_DIR}/mezzanineaccess.log combined </VirtualHost>
Habilitamos los siguientes módulos:
debian@stuart:/etc/apache2/sites-available$ sudo a2enmod proxy proxy_http cache
Añadimos a ALLOWED _HOSTS la 127.0.0.1
root@stuart:/home/debian/mezzanine/mezza# nano mezza/local_settings.py ALLOWED_HOSTS = ["172.22.200.101","127.0.0.1"]
Deshabilitamos el sitio de mezzanine y habilitamos el nuevo
debian@stuart:~$ sudo a2dissite 000-default Site 000-default already disabled debian@stuart:~$ sudo a2dissite mezzanine Site mezzanine disabled. To activate the new configuration, you need to run: systemctl reload apache2 debian@stuart:~$ sudo a2ensite gunicorn Enabling site gunicorn. To activate the new configuration, you need to run: systemctl reload apache2 debian@stuart:~$ sudo systemctl reload apache2
Para que se inicie gunicorn:
root@stuart:/home/debian/mezzanine/mezza# /home/debian/mezzanine/bin/gunicorn -w 2 -b :8080 mezza.wsgi:application [2018-02-06 17:46:01 +0000] [2674] [INFO] Starting gunicorn 19.7.1 [2018-02-06 17:46:01 +0000] [2674] [INFO] Listening at: http://0.0.0.0:8080 (2674) [2018-02-06 17:46:01 +0000] [2674] [INFO] Using worker: sync [2018-02-06 17:46:01 +0000] [2678] [INFO] Booting worker with pid: 2678 [2018-02-06 17:46:01 +0000] [2679] [INFO] Booting worker with pid: 2679
Tarea 3 (2 puntos)(Obligatorio): Documenta la instalación y configuración de uwsgi y apache2. Muestra mezzanine funcionando y una comprobación de que, efectivamente, se está usando wusgi.
Con la misma instalción de antes, paramos el comando ejecutado para lanzar gunicorn e instalamos uwsgi con pip en el entorno virtual
debian@stuart:/home/debian/mezzanine/mezza# source ../bin/activate (mezzanine) debian@stuart:/home/debian/mezzanine/mezza# pip install uwsgi
Creamos el fichero de configuración de uwsgi:
(mezzanine) debian@stuart:~/mezzanine/$ nano uwsgi.ini [uwsgi] http = :8080 chdir = /home/debian/mezzanine/mezza wsgi-file = mezza/wsgi.py processes = 4 threads = 2 logger = file:/home/debian/mezzanine/mezza/uwsgi.log
Recagramos los ficheros estaticos:
python manage.py collectstatic python manage.py collecttemplates
Habilitamos los siguientes módulos:
debian@stuart:~/mezzanine$ sudo a2enmod proxy proxy_http
El virtualhost lo modificamos para que quede:
<VirtualHost *:80> DocumentRoot /home/debian/mezzanine/mezza Alias /static /home/debian/mezzanine/mezza/static ProxyPass /static/ ! ProxyPass / http://127.0.0.1:8080/ <Directory /home/debian/mezzanine/mezza/static> Require all granted Options FollowSymLinks </Directory> ErrorLog ${APACHE_LOG_DIR}/mezzanineerror.log CustomLog ${APACHE_LOG_DIR}/mezzanineaccess.log combined </VirtualHost>
Reiniciamos apache para aplicar los cambios:
debian@stuart:~/mezzanine$ sudo service apache2 reload
Y comprobamos la configuración:
(mezzanine) debian@stuart:~/mezzanine$ uwsgi --ini uwsgi.ini [uWSGI] getting INI configuration from uwsgi.ini
Tarea 4 (2 puntos): Documenta la instalación y configuración de gunicorn y nginx. Muestra mezzanine funcionando y una comprobación de que, efectivamente, se está usando gunicorn.
Se van a necesitar los siguientes paquetas:
root@stuart:/home/debian# apt install nginx virtualenv
Nos vamos al directorio /var/www y creamos un entorno virtual
root@stuart:/home/debian# cd /var/www/ root@stuart:/var/www# virtualenv mezzanine root@stuart:/var/www# source mezzanine/bin/activate
Instalamos mezzanine y gunicorn y creamos el proyecto
(mezzanine) root@stuart:/var/www# pip install mezzanine gunicorn (mezzanine) root@stuart:/var/www# mezzanine-project maria
En el fichero settings.py permitimos las conexiones:
(mezzanine) root@stuart:/var/www/mezzanine# nano maria/maria/settings.py ALLOWED_HOSTS = ["*"]
Ejecutamos los siguientes comandos:
(mezzanine) root@stuart:/var/www/mezzanine/maria# python manage.py collectstatic (mezzanine) root@stuart:/var/www/mezzanine/maria# python manage.py createdb
Nos aseguramos de que los permisos sean los correctos:
root@stuart:/var/www# chown -R www-data. mezzanine/
Modificamos el sitio por defecto para que quede así:
server { location /static { root /var/www/mezzanine/maria; } location / { proxy_pass http://127.0.0.1:8080; } }
Creamos una unidad en /etc/systemd/system/mezzanine.service:
[Unit] Description=gunicorn daemon After=network.target [Service] User=www-data Group=www-data WorkingDirectory=/var/www/mezzanine/maria ExecStart=/var/www/mezzanine/bin/gunicorn -w 2 -b :8080 maria.wsgi:application [Install] WantedBy=multi-user.target
Ejecutamos lo siguiente:
systemctl daemon-reload systemctl enable mezzanine.service systemctl start mezzanine.service
Comprobamos que está activo:
root@stuart:/var/www/mezzanine# systemctl status mezzanine.service ● mezzanine.service - gunicorn daemon Loaded: loaded (/etc/systemd/system/mezzanine.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2018-02-11 18:56:24 UTC; 7s ago Main PID: 1789 (gunicorn) Tasks: 3 (limit: 4915) CGroup: /system.slice/mezzanine.service ├─1789 /var/www/mezzanine/bin/python2 /var/www/mezzanine/bin/gunicorn -w 2 -b :8080 maria.wsgi:application ├─1793 /var/www/mezzanine/bin/python2 /var/www/mezzanine/bin/gunicorn -w 2 -b :8080 maria.wsgi:application └─1795 /var/www/mezzanine/bin/python2 /var/www/mezzanine/bin/gunicorn -w 2 -b :8080 maria.wsgi:application Feb 11 18:56:24 stuart systemd[1]: Started gunicorn daemon. Feb 11 18:56:24 stuart gunicorn[1789]: [2018-02-11 18:56:24 +0000] [1789] [INFO] Starting gunicorn 19.7.1 Feb 11 18:56:24 stuart gunicorn[1789]: [2018-02-11 18:56:24 +0000] [1789] [INFO] Listening at: http://0.0.0.0:8080 (178 Feb 11 18:56:24 stuart gunicorn[1789]: [2018-02-11 18:56:24 +0000] [1789] [INFO] Using worker: sync Feb 11 18:56:24 stuart gunicorn[1789]: [2018-02-11 18:56:24 +0000] [1793] [INFO] Booting worker with pid: 1793 Feb 11 18:56:24 stuart gunicorn[1789]: [2018-02-11 18:56:24 +0000] [1795] [INFO] Booting worker with pid: 1795
Tarea 5 (2 puntos): Documenta la instalación y configuración de uwsgi y nginx. Muestra mezzanine funcionando y una comprobación de que, efectivamente, se está usando wusgi.
Paramos el servicio con gunicorn
root@stuart:~# systemctl stop mezzanine.service
Instalamos uwsgi y las dependencias:
root@stuart:~# apt install build-essential python-dev root@stuart:~# cd /var/www/mezzanine/ root@stuart:/var/www/mezzanine# source bin/activate (mezzanine) root@stuart:/var/www/mezzanine# pip install uwsgi
Creamos el uwsgi.ini en la carpeta del proyecto:
[uwsgi] http = :8080 chdir = /var/www/mezzanine/maria wsgi-file = maria/wsgi.py processes = 4 threads = 2 logger = file:/var/www/mezzanine/maria/uwsgi.log
Creamos una unidad de systemd en /etc/systemd/system/uwsgi.service
[uwsgi] http = :8080 chdir = /var/www/mezzanine/maria wsgi-file = maria/wsgi.py processes = 4 threads = 2 logger = file:/var/www/mezzanine/maria/uwsgi.log root@stuart:~# cat /etc/systemd/system/uwsgi.service [Unit] Description=uWSGI Python After=syslog.target [Service] ExecStart=/var/www/mezzanine/bin/uwsgi --ini /var/www/mezzanine/maria/uwsgi.ini User=www-data Group=www-data [Install] WantedBy=multi-user.target
Ejecutamos: systemctl daemon-reload systemctl enable uwsgi.service systemctl start uwsgi.service
Comprobamos el estado:
root@stuart:~# systemctl status uwsgi.service ● uwsgi.service - uWSGI Python Loaded: loaded (/etc/systemd/system/uwsgi.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2018-02-11 19:29:26 UTC; 21min ago Main PID: 4293 (uwsgi) Tasks: 10 (limit: 4915) CGroup: /system.slice/uwsgi.service ├─4293 /var/www/mezzanine/bin/uwsgi --ini /var/www/mezzanine/maria/uwsgi.ini ├─4297 /var/www/mezzanine/bin/uwsgi --ini /var/www/mezzanine/maria/uwsgi.ini ├─4298 /var/www/mezzanine/bin/uwsgi --ini /var/www/mezzanine/maria/uwsgi.ini ├─4299 /var/www/mezzanine/bin/uwsgi --ini /var/www/mezzanine/maria/uwsgi.ini ├─4300 /var/www/mezzanine/bin/uwsgi --ini /var/www/mezzanine/maria/uwsgi.ini └─4301 /var/www/mezzanine/bin/uwsgi --ini /var/www/mezzanine/maria/uwsgi.ini Feb 11 19:29:26 stuart systemd[1]: uwsgi.service: Main process exited, code=killed, status=9/KILL Feb 11 19:29:26 stuart systemd[1]: Stopped uWSGI Python. Feb 11 19:29:26 stuart systemd[1]: uwsgi.service: Unit entered failed state. Feb 11 19:29:26 stuart systemd[1]: uwsgi.service: Failed with result 'timeout'. Feb 11 19:29:26 stuart systemd[1]: Started uWSGI Python. Feb 11 19:29:26 stuart uwsgi[4293]: [uWSGI] getting INI configuration from /var/www/mezzanine/maria/uwsgi.ini
Estudio de rendimiento
Ahora utilizando el script benchmark.py, realiza las pruebas de rendiemento para cada una de las configuraciones anteriores.
Tarea 6 (5 puntos): Entrega la configuración del script de pruebas para cada una de las configuraciones. Entrega los datos obtenidos y la gráfica que has generado.
IMPORTANTE: Hay que tener el paquete apache2-utils instalado, ya sea para para apache o nginx.
apache2 + Módulo wsgi
CONN =[1,10,25,50,75,100] TITULO="apache2 + wsgi" DURATION="10" IP="127.0.0.1" URLS=["contact/legals","blog","about/team"] SERVERS=[]
984,22 933,196666667 1024,346667 987,696666667 982,09 994,3166673
apache2 + gunicorn
CONN =[1,10,25,50,75,100] TITULO="apache2 + gunicorn" DURATION="10" IP="127.0.0.1" URLS=["contact/legals","blog","about/team"] SERVERS=[]
1049,96666667 1922,19666667 1998,57666667 2181,106667 2121,27 2140,85
apache2 + uwsgi
CONN =[1,10,25,50,75,100] TITULO="apache2 + uwsgi" DURATION="10" IP="127.0.0.1" URLS=["contact/legals","blog","about/team"] SERVERS=[]
956,856666667 1993,55666667 1940,57666667 1964,89 2193,02 1955,27666667
nginx + gunicorn
CONN =[1,10,25,50,75,100] TITULO="nginx + gunicorn" DURATION="10" IP="127.0.0.1:8080" URLS=["contact/legals","blog","about/team"] SERVERS=[]
1131,68666667 2425,35666667 2243,516667 2314,37 2143,24 2143,29
nginx + uwsgi
CONN =[1,10,25,50,75,100] TITULO="nginx + uwsgi" DURATION="10" IP="127.0.0.1" URLS=["contact/legals","blog","about/team"] SERVERS=[]
995,09 2449,33666667 2438,35666667 2740,51 2423,016667 2459,80666667
Gráfica: