En estos últimos artículos expliqué cómo montar una caché local de paquetes implementada a través de un proxy con Nginx, tanto para Debian como para CentOS. Para mejorar el esquema se me ocurrió balancear la carga de red entre varios mirrors. De esta forma, nuestro proxy repartirá los accesos entre varios mirrors, en lugar de utilizar un único mirror.

El balanceo de carga es un problema común en la actualidad, especialmente cuando se manejan cientos o miles de solicitudes/accesos desde varios clientes al mismo tiempo. Este artículo apunta a demostrar cómo es posible implementar un balanceador de carga de manera extremadamente simple utilizando los módulos de Nginx ngx_http_upstream_module y ngx_http_proxy_module.

El balanceo de carga mejora la distribución de carga de trabajo entre múltiples recursos computacionales como servidores, nodos de un cluster, enlaces de red, servicios, procesadores o discos. Apunta a optimizar el uso de recursos, maximizar el ancho de banda, minimizar tiempos de respuesta, y evitar la sobrecarga de un recurso simple. Por otro lado, el uso de múltiples componentes con balance de carga (en lugar de un componente simple), además de incrementar la capacidad (máximo posible de usuarios o clientes concurrentes) incrementa la confiabilidad y disponibilidad a través de la redundancia.

Un balanceador de carga es un dispositivo que actúa como proxy reverso y distribuye el tráfico de red y aplicaciones entre un número de servidores. Los balanceadores de carga generalmente se agrupan en dos categorías: capa 4 y capa 7. Los de capa 4 actúan sobre datos encontrados en los protocolos de las capas de red y transporte (IP, TCP, FTP, UDP). Los balanceadores de carga de capa 7 distribuyen solicitudes basandose en datos encontrados en los protocolos de capa de aplicación, como por ejemplo HTTP (tal como es el caso de este artículo).

Las solicitudes recibidas en ambos tipos de balanceadores de carga se distribuyen a un servidor en particular basándose en diferentes algoritmos, como pueden ser round-robin, round-robin con peso, menos conexiones y menor tiempo de respuesta.

Además, los balanceadores de carga de capa 7 pueden distribuir aún más basándose en datos específicos de la aplicación, tales como las cabeceras HTTP, cookies, o datos dentro del mensaje en sí mismo (tal como el valor de un cierto parámetro).

Balance de carga utilizando Nginx

Nginx permite implementar balanceadores de carga de manera simple utilizando una combinación de los módulos "http_upstream" y "http_proxy". El punto de este artículo es lograr que nuestro proxy Nginx reparta las solicitudes entre un subconjunto de mirrors, en lugar de descargar los paquetes siempre desde el mismo mirror. Utilizando el módulo "http_upstream" es posible definir un conjunto de servidores disponibles, junto con el algoritmo de distribución de carga, para luego reenviar las solicitudes a cada mirror a través de directivas proxy_pass.

El primer paso consiste en definir nuestro conjunto de servidores. En este caso defino cuatro servidores, escuchando en diferentes puertos (sólo para localhost), donde cada uno hace de proxy a un mirror de Debian diferente (examinar la directiva proxy_pass en cada uno):


    # DEBIAN MIRROR 1 - ftp.br.debian.org
    server {
        listen 127.0.0.1:8081;
        server_tokens off;

        access_log /var/log/nginx/deb_apt_m1--access.log;
        error_log /var/log/nginx/deb_apt_m1--error.log;

        location / {
             proxy_pass http://ftp.br.debian.org:80;
             proxy_set_header Host ftp.br.debian.org;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_http_version 1.1;
        }
    }

    # DEBIAN MIRROR 2 - mirrors.ucr.ac.cr
    server {
        listen 127.0.0.1:8082;
        server_tokens off;

        access_log /var/log/nginx/deb_apt_m2--access.log;
        error_log /var/log/nginx/deb_apt_m2--error.log;

        location / {
             proxy_pass http://mirrors.ucr.ac.cr:80;
             proxy_set_header Host mirrors.ucr.ac.cr;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_http_version 1.1;
        }
    }

    # DEBIAN MIRROR 3 - mirrors.tecnoera.com
    server {
        listen 127.0.0.1:8083;
        server_tokens off;

        access_log /var/log/nginx/deb_apt_m3--access.log;
        error_log /var/log/nginx/deb_apt_m3--error.log;

        location / {
             proxy_pass http://mirrors.tecnoera.com:80;
             proxy_set_header Host mirrors.tecnoera.com;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_http_version 1.1;
        }
    }

    # DEBIAN MIRROR 4 - linorg.usp.br
    server {
        listen 127.0.0.1:8084;
        server_tokens off;

        access_log /var/log/nginx/deb_apt_m4--access.log;
        error_log /var/log/nginx/deb_apt_m4--error.log;

        location / {
             proxy_pass http://linorg.usp.br:80;
             proxy_set_header Host linorg.usp.br;
             proxy_set_header X-Real-IP $remote_addr;
             proxy_http_version 1.1;
        }
    }

Luego se define el grupo de servidores sobre los cuales se balanceará la carga:


    upstream debiancache {
        server 127.0.0.1:8081;
        server 127.0.0.1:8082;
        server 127.0.0.1:8083;
        server 127.0.0.1:8084;
    }

En este caso, todos los servidores tienen el mismo peso, con lo cual se trata de un round-robin puro. Es posible alterar el peso de cada servidor a través del parámetro weight. Por ejemplo, si quisiera que de cada 10 pedidos 4 vayan al primer servidor, 3 al segundo, 2 al tercero y 1 al último, podría configurar los pesos del round-robin de la siguiente manera:


    upstream debiancache {
        server 127.0.0.1:8081 weight=4;
        server 127.0.0.1:8082 weight=3;
        server 127.0.0.1:8083 weight=2;
        server 127.0.0.1:8084 weight=1;
    }

Por último se configura el balanceador de carga. Se trata precisamente del proxy que actuará como caché de paquetes (por ello incluye las directivas proxy_cache*):


    # DEBIAN PAQUETES
    server {
        listen 8080;
        server_name debian-cache.linuxito.com;
        server_tokens off;

        access_log /var/log/nginx/deb_apt--access.log;
        error_log /var/log/nginx/deb_apt--error.log;

        location / {
             proxy_pass http://debiancache;

             proxy_cache cache01;
             proxy_cache_revalidate on;
             proxy_cache_min_uses 1;
             proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
             proxy_cache_lock on;
        }
    }

En esta configuración, la única directiva interesante a los fines de balanceo de carga es:

proxy_pass http://debiancache;

Aquí se dice que todas las solicitudes se reenvíen al grupo llamado "debiancache". No hace falta que este nombre resuelva a localhost o 127.0.0.1, ya que Nginx se da cuenta de que se trata de un alias interno. Luego el grupo implementa el round-robin según haya sido configurado, conformando efectivamente el balanceo de carga entre los diferentes servidores.

En este caso, sólo el puerto 8080 aceptará peticiones desde los clientes (deberá permitirse el acceso a través del firewall subyacente), y los servidores en el grupo aceparán peticiones sólo de manera interna.

Finalmente resta configurar a los clientes para que accedan a los repositorios a través del proxy en el puerto 8080.

Con esta serie de tres artículos logramos implementar nuestra caché local de paquetes de Debian y CentOS utilizando balanceo de carga entre mirrors. Espero que les sea de gran utilidad y haya resultado interesante. Por supuesto es posible implementar exactamente el mismo balanceo de carga para los mirrors de CentOS replicando esta configuración y utilizando diferentes puertos.

Referencias


Tal vez pueda interesarte


Compartí este artículo