Práctica: Aumento de rendimiento en servidores web
HAProxy: Balanceador de carga
Parte 1
Crear y configurar el escenario usando el repositorio vagrant_ansible_haproxy
Clono el repo:
Creo las máquinas:
Entro en cada una de ellas y apunto sus IPs:
- frontend: 192.168.121.61
- backend1: 192.168.121.196
- backend2: 192.168.121.20
Modifico ansible/hosts
con estas IPs:
[servidor_ha]
frontend ansible_ssh_host=192.168.121.61 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/frontend/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
[servidores_web]
backend1 ansible_ssh_host=192.168.121.196 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/backend1/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
backend2 ansible_ssh_host=192.168.121.20 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/backend2/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
Ejecuto el playbook para configurar el escenario:
Podemos llegar a encontrarnos con este fallo, y lo documento para que se sepa:
Para arreglarlo tendríamos que entrar en cada máquina y cambiar los repositorios en /etc/apt/sources.list
a https:
Una vez hecho esto, vuelvo a ejecutar el playbook y ya funcionaría:
atlas@olympus:~/vagrant/vagrant_ansible_haproxy/ansible$ ansible-playbook site.yaml
PLAY [all] ************************************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************
ok: [frontend]
ok: [backend1]
ok: [backend2]
TASK [commons : Ensure system is updated] *****************************************************************************************************************
ok: [backend2]
ok: [backend1]
ok: [frontend]
PLAY [servidor_ha] ****************************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************
ok: [frontend]
TASK [haproxy : install haproxy] **************************************************************************************************************************
changed: [frontend]
PLAY [servidores_web] *************************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************
ok: [backend2]
ok: [backend1]
TASK [nginx : install nginx, php-fpm] *********************************************************************************************************************
changed: [backend1]
changed: [backend2]
TASK [nginx : Copy info.php] ******************************************************************************************************************************
changed: [backend1]
changed: [backend2]
TASK [nginx : Copy virtualhost default] *******************************************************************************************************************
changed: [backend1]
changed: [backend2]
RUNNING HANDLER [nginx : restart nginx] *******************************************************************************************************************
changed: [backend2]
changed: [backend1]
PLAY [servidores_web] *************************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************
ok: [backend1]
ok: [backend2]
TASK [mariadb : ensure mariadb is installed] **************************************************************************************************************
changed: [backend1]
changed: [backend2]
TASK [mariadb : ensure mariadb binds to internal interface] ***********************************************************************************************
changed: [backend2]
changed: [backend1]
RUNNING HANDLER [mariadb : restart mariadb] ***************************************************************************************************************
changed: [backend2]
changed: [backend1]
PLAY [servidores_web] *************************************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************************************
ok: [backend1]
ok: [backend2]
TASK [wordpress : install unzip] **************************************************************************************************************************
changed: [backend2]
changed: [backend1]
TASK [wordpress : download wordpress] *********************************************************************************************************************
changed: [backend2]
changed: [backend1]
TASK [wordpress : unzip wordpress] ************************************************************************************************************************
changed: [backend2]
changed: [backend1]
TASK [wordpress : Copy wordpress.sql] *********************************************************************************************************************
changed: [backend1]
changed: [backend2]
TASK [wordpress : create database wordpress] **************************************************************************************************************
changed: [backend2]
changed: [backend1]
TASK [wordpress : create user mysql wordpress] ************************************************************************************************************
changed: [backend1] => (item=localhost)
changed: [backend2] => (item=localhost)
TASK [wordpress : copy wp-config.php] *********************************************************************************************************************
changed: [backend1]
changed: [backend2]
RUNNING HANDLER [wordpress : restart nginx] ***************************************************************************************************************
changed: [backend1]
changed: [backend2]
PLAY RECAP ************************************************************************************************************************************************
backend1 : ok=20 changed=15 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
backend2 : ok=20 changed=15 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
frontend : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Parte 2
Configurar HAProxy en frontend
Al final de /etc/haproxy/haproxy.cfg
añado:
frontend servidores_web
bind *:80
mode http
stats enable
stats uri /ha_stats
stats auth cda:cda
default_backend servidores_web_backend
backend servidores_web_backend
mode http
balance roundrobin
server backend1 10.0.0.10:80 check
server backend2 10.0.0.11:80 check
Reinicio HAProxy:
Compruebo que ha empezado a escuchar en el puerto 80:
vagrant@frontend:/etc/haproxy$ sudo lsof -i -P -n | grep LISTEN
sshd 524 root 3u IPv4 12470 0t0 TCP *:22 (LISTEN)
sshd 524 root 4u IPv6 12481 0t0 TCP *:22 (LISTEN)
haproxy 20027 haproxy 7u IPv4 41481 0t0 TCP *:80 (LISTEN)
Parte 3
Configurar la resolución estática y acceder a wordpress
/etc/hosts
:
En cada nodo tenemos un info.php
, así que podemos comprobar si el balanceo funciona mirando los hostnames:
Parte 4
Calcular el rendimiento haciendo 5 pruebas. Obtener la media de
Requests per second
Hago una primera prueba con:
Estos son los resultados:
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking www.example.org (be patient)
Finished 917 requests
Server Software: nginx/1.18.0
Server Hostname: www.example.org
Server Port: 80
Document Path: /wordpress/
Document Length: 26892 bytes
Concurrency Level: 100
Time taken for tests: 10.009 seconds
Complete requests: 917
Failed requests: 508
(Connect: 0, Receive: 0, Length: 508, Exceptions: 0)
Total transferred: 24881439 bytes
HTML transferred: 24672135 bytes
Requests per second: 91.62 [#/sec] (mean)
Time per request: 1091.467 [ms] (mean)
Time per request: 10.915 [ms] (mean, across all concurrent requests)
Transfer rate: 2427.70 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.5 0 2
Processing: 14 954 945.3 559 2454
Waiting: 10 933 937.0 539 2427
Total: 14 954 945.2 559 2454
Percentage of the requests served within a certain time (ms)
50% 556
66% 1356
75% 2086
80% 2279
90% 2389
95% 2399
98% 2418
99% 2436
100% 2454 (longest request)
La parte que nos importa:
Hago 4 pruebas más y saco una media:
Requests per second: 102.89 [#/sec] (mean)
Requests per second: 101.58 [#/sec] (mean)
Requests per second: 101.68 [#/sec] (mean)
Requests per second: 99.28 [#/sec] (mean)
Parte 5
5.1
Instalar
hatop
5.2
Acceder a las estadísticas/administración
5.3
Deshabilitar el nodo backend1
Pulso F10 encima del nodo para que entre en mantenimiento:
5.4
Volver a hacer las pruebas de rendimiento
Requests per second: 43.26 [#/sec] (mean)
Requests per second: 38.94 [#/sec] (mean)
Requests per second: 45.58 [#/sec] (mean)
Requests per second: 45.73 [#/sec] (mean)
Requests per second: 45.78 [#/sec] (mean)
5.5
¿Se nota la diferencia entre balancear y no balancear?
Sí, básicamente porque al tener un solo nodo el rendimiento baja a la mitad (lógicamente).
5.6
Habilitar de nuevo el nodo backend1
Hago lo mismo que para deshabilitarlo, pero esta vez pulso F9:
Parte 6
Añadir un nuevo nodo backend3 donde se instale Wordpress.
6.1
Modificar el Vagrantfile
config.vm.define :backend3 do |backend3|
backend3.vm.box = "debian/bullseye64"
backend3.vm.hostname = "backend3"
backend3.vm.synced_folder ".", "/vagrant", disabled: true
backend3.vm.network :private_network,
:libvirt__network_name => "red1",
:libvirt__dhcp_enabled => false,
:ip => "10.0.0.12",
:libvirt__forward_mode => "veryisolated"
end
Creo la máquina:
6.2
Modificar el Ansible
ansible/hosts
:
[servidor_ha]
frontend ansible_ssh_host=192.168.121.61 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/frontend/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
[servidores_web]
backend1 ansible_ssh_host=192.168.121.196 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/backend1/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
backend2 ansible_ssh_host=192.168.121.20 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/backend2/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
backend3 ansible_ssh_host=192.168.121.236 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/backend3/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
Ejecuto el playbook de nuevo para configurar la nueva máquina como las demás:
atlas@olympus:~/vagrant/vagrant_ansible_haproxy/ansible$ ansible-playbook site.yaml
PLAY [all] *************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [backend2]
ok: [frontend]
ok: [backend3]
ok: [backend1]
TASK [commons : Ensure system is updated] ******************************************************************************************************************************
ok: [backend2]
ok: [backend1]
ok: [frontend]
changed: [backend3]
PLAY [servidor_ha] *****************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [frontend]
TASK [haproxy : install haproxy] ***************************************************************************************************************************************
ok: [frontend]
PLAY [servidores_web] **************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [backend3]
ok: [backend1]
ok: [backend2]
TASK [nginx : install nginx, php-fpm] **********************************************************************************************************************************
ok: [backend1]
ok: [backend2]
changed: [backend3]
TASK [nginx : Copy info.php] *******************************************************************************************************************************************
ok: [backend1]
ok: [backend2]
changed: [backend3]
TASK [nginx : Copy virtualhost default] ********************************************************************************************************************************
ok: [backend1]
ok: [backend2]
changed: [backend3]
RUNNING HANDLER [nginx : restart nginx] ********************************************************************************************************************************
changed: [backend3]
PLAY [servidores_web] **************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [backend1]
ok: [backend2]
ok: [backend3]
TASK [mariadb : ensure mariadb is installed] ***************************************************************************************************************************
ok: [backend1]
ok: [backend2]
changed: [backend3]
TASK [mariadb : ensure mariadb binds to internal interface] ************************************************************************************************************
ok: [backend2]
ok: [backend1]
changed: [backend3]
RUNNING HANDLER [mariadb : restart mariadb] ****************************************************************************************************************************
changed: [backend3]
PLAY [servidores_web] **************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [backend1]
ok: [backend2]
ok: [backend3]
TASK [wordpress : install unzip] ***************************************************************************************************************************************
ok: [backend1]
ok: [backend2]
changed: [backend3]
TASK [wordpress : download wordpress] **********************************************************************************************************************************
ok: [backend1]
ok: [backend2]
changed: [backend3]
TASK [wordpress : unzip wordpress] *************************************************************************************************************************************
changed: [backend3]
ok: [backend1]
ok: [backend2]
TASK [wordpress : Copy wordpress.sql] **********************************************************************************************************************************
changed: [backend1]
changed: [backend2]
changed: [backend3]
TASK [wordpress : create database wordpress] ***************************************************************************************************************************
changed: [backend3]
changed: [backend2]
changed: [backend1]
TASK [wordpress : create user mysql wordpress] *************************************************************************************************************************
changed: [backend3] => (item=localhost)
ok: [backend2] => (item=localhost)
ok: [backend1] => (item=localhost)
TASK [wordpress : copy wp-config.php] **********************************************************************************************************************************
ok: [backend1]
ok: [backend2]
changed: [backend3]
RUNNING HANDLER [wordpress : restart nginx] ****************************************************************************************************************************
changed: [backend3]
PLAY RECAP *************************************************************************************************************************************************************
backend1 : ok=17 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
backend2 : ok=17 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
backend3 : ok=20 changed=16 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
frontend : ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
6.3
Añadir backend3 a
/etc/haproxy/haproxy.cfg
para que se tome en cuenta para el balanceo
backend servidores_web_backend
mode http
balance roundrobin
server backend1 10.0.0.10:80 check
server backend2 10.0.0.11:80 check
server backend3 10.0.0.12:80 check
Reinicio HAProxy:
6.4
Volver a hacer las pruebas de rendimiento
Requests per second: 130.12 [#/sec] (mean)
Requests per second: 129.43 [#/sec] (mean)
Requests per second: 129.21 [#/sec] (mean)
Requests per second: 129.64 [#/sec] (mean)
Requests per second: 130.01 [#/sec] (mean)
6.5
¿Se nota la diferencia al balancear añadiendo un nuevo nodo?
Lógicamente sí. El rendimiento aumenta proporcionalmente.
Memcached
2.1
Crear y configurar el escenario vagrant_ansible_wordpress
Clono el repo:
Creo la máquina:
Entro en ella y apunto su IP: 192.168.121.239
Modifico ansible/hosts
con esta IP:
[servidores_web]
servidor_web ansible_ssh_host=192.168.121.239 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/default/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
Ejecuto el playbook para configurar la máquina:
atlas@olympus:~/vagrant/vagrant_ansible_wordpress/ansible$ ansible-playbook site.yaml
[WARNING]: ansible.utils.display.initialize_locale has not been called, this may result in incorrectly calculated text widths that can cause Display to print incorrect
line lengths
PLAY [all] *************************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [servidor_web]
TASK [commons : Ensure system is updated] ******************************************************************************************************************************
changed: [servidor_web]
PLAY [servidores_web] **************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [servidor_web]
TASK [nginx : install nginx, php-fpm] **********************************************************************************************************************************
changed: [servidor_web]
TASK [nginx : Copy info.php] *******************************************************************************************************************************************
changed: [servidor_web]
TASK [nginx : Copy virtualhost default] ********************************************************************************************************************************
changed: [servidor_web]
RUNNING HANDLER [nginx : restart nginx] ********************************************************************************************************************************
changed: [servidor_web]
PLAY [servidores_web] **************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [servidor_web]
TASK [mariadb : ensure mariadb is installed] ***************************************************************************************************************************
changed: [servidor_web]
TASK [mariadb : ensure mariadb binds to internal interface] ************************************************************************************************************
changed: [servidor_web]
RUNNING HANDLER [mariadb : restart mariadb] ****************************************************************************************************************************
changed: [servidor_web]
PLAY [servidores_web] **************************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [servidor_web]
TASK [wordpress : install unzip] ***************************************************************************************************************************************
changed: [servidor_web]
TASK [wordpress : download wordpress] **********************************************************************************************************************************
changed: [servidor_web]
TASK [wordpress : unzip wordpress] *************************************************************************************************************************************
changed: [servidor_web]
TASK [wordpress : Copy wordpress.sql] **********************************************************************************************************************************
changed: [servidor_web]
TASK [wordpress : create database wordpress] ***************************************************************************************************************************
changed: [servidor_web]
TASK [wordpress : create user mysql wordpress] *************************************************************************************************************************
changed: [servidor_web] => (item=localhost)
TASK [wordpress : copy wp-config.php] **********************************************************************************************************************************
changed: [servidor_web]
RUNNING HANDLER [wordpress : restart nginx] ****************************************************************************************************************************
changed: [servidor_web]
PLAY RECAP *************************************************************************************************************************************************************
servidor_web : ok=20 changed=16 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.2
Configurar la resolución estática
/etc/hosts
:
2.3
Instalar memcached. Comprobar en
info.php
que funciona.
Si se instaló correctamente, nos aparece esta sección:
2.4
Instalar y configurar W3 Total Cache en Wordpress para que se pueda comunicar con memcached
Comienzo la configuración de forma manual:
En General Settings
hay distintas cachés y opciones que podemos activar y configurar con este plugin. Lo hago:
Guardo las configuraciones:
Reinicio Nginx:
2.5
Realizar el cálculo de rendimiento y obtener la media
Requests per second: 1083.49 [#/sec] (mean)
Requests per second: 991.49 [#/sec] (mean)
Requests per second: 1075.94 [#/sec] (mean)
Requests per second: 1089.48 [#/sec] (mean)
Requests per second: 1088.40 [#/sec] (mean)
2.6
¿Se ha aumentado el rendimiento de forma significativa?
Bastante. Como he mostrado, hemos llegado a las mil peticiones por segundo.
Varnish
3.1
Reutilizar el escenario anterior
Borro la máquina y la creo de nuevo:
Entro en ella y apunto su IP: 192.168.121.53
Modifico ansible/hosts
con esta IP:
[servidores_web]
servidor_web ansible_ssh_host=192.168.121.53 ansible_ssh_user=vagrant ansible_ssh_private_key_file=../.vagrant/machines/default/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
Ejecuto el playbook para configurar la máquina:
3.2
Configurar la resolución estática
/etc/hosts
:
3.3
Instalar Varnish
3.4
Cambiar Nginx al puerto 8080
/etc/nginx/sites-available/default
:
Reinicio:
Compruebo que ha cambiado:
3.5
Cambiar Varnish al puerto 80
Según la documentación oficial de varnish no hace falta modificar el fichero /etc/default/varnish
en versiones recientes de Debian (ya que es legacy).
En su lugar, modifico /lib/systemd/system/varnish.service
:
Reinicio la configuración de los daemon:
Reinicio Varnish:
Compruebo que ha cambiado el puerto:
3.6
Comprobar que la sección backend en
/etc/varnish/default.vcl
que tenemos por defecto sea correcta
Lo es:
3.7
Comprobar que se puede acceder a Wordpress normalmente tras los cambios
3.8
Realizar las pruebas de rendimiento
Requests per second: 5806.68 [#/sec] (mean)
Requests per second: 5952.47 [#/sec] (mean)
Requests per second: 5941.95 [#/sec] (mean)
Requests per second: 5877.94 [#/sec] (mean)
Requests per second: 5960.23 [#/sec] (mean)
Casi llegamos a una media de 6.000 peticiones por segundo, así que hemos aumentado el rendimiento considerablemente.
3.9
¿Cuántas peticiones llegan realmente a Nginx?
/var/log/nginx/access.log
:
Como vemos, fijándonos en la hora, Nginx sólo ha servido 2 peticiones de las miles que se han hecho.