Blog Archives

Carga rápida y masiva de Memcache para Nginx

Hace años escribí sobre como uso Nginx como proxy de Apache en algunas instalaciones. En esa arquitectura contemplo Memcache. La configuración es muy sencilla, basta agregar a la sección location que queramos cachear lo siguiente:

set $memcached_key $uri;
memcached_pass 127.0.0.1:11211;
error_page 404 @fallback;

Y agregar el location @fallback correspondiente:

location @fallback {
proxy_pass http://localhost:8000;
}

El único problema, como algunas personas que han usado Nginx con Memcache, es que alguien tiene que llenar Memcache con objetos para que Nginx pueda leerlos.

Usualmente, los desarrolladores de la aplicación usarán las librerías del lenguaje de programación para acceder a Memcache y cargar allí algunos objetos. Esto funciona, y es como la mayoría de la gente implementa este escenario. Sin embargo, si uno quiere cargar varios archivos de forma rápida a Memcache, no hay muchas herramientas sencillas y fácilmente disponibles.

Por ejemplo, hace dos meses en la wiki de Nginx alguien publicó un método para precargar memcache con Python. Es un enfoque interesante, pero complicado de mantener y decididamente experimental.

Sin embargo, memcache ya incluye un cliente llamado memccp que permite cargar archivos en Memcache. El problema es que este cliente no permite definir la llave con la que el objeto se almacena en Memcache. Esa llave es $uri, por ejemplo algo como /wp-content/plugins/akismet/akismet.gif.

Cuando Nginx encuentra un cliente que hace GET a este archivo, lo sirve desde Memcache, lo que en este escenario nos ahorra abrir una conexión TCP a localhost, que Apache atienda y responda una petición, y potencialmente I/O de disco.

Este parche a libmemcached permite que se defina una clave con –key, lo que facilita precargar archivos como imágenes o CSS en Memcache. Su uso es sencillo y se puede invocar desde un shell script (probado en dash)

#!/bin/sh
BASE=”/var/www/mysite”
for file in `\
find $BASE -type f \
-name ‘*.jpg’ -or \
-name ‘*.gif’ -or \
-name ‘*.png’ \
| sed “s#$BASE##”`
do
echo “Adding $file to memcached…”
sudo memccp –key=$file –servers=localhost $BASE$file
done

Entre otros escenarios que puedes activar en este caso, está el poder almacenar archivos para distintos hosts virtuales. En este caso sugiero que configures $memcached_key para usar $http_host y $uri, y añadas una variable de prefijo a tu script. También puedes correr otro memcache, si en realidad lo necesitas. memccp tiene otros problemas, por ejemplo no maneja la codificación de caracteres muy bien. Pero para archivos binarios, usualmente estáticos, ahorra bastante trabajo.

El repositorio en GitHub es un paquete fuente de Debian. Si tienes las dependencias (sudo apt-get build-dep libmemcached-tools) puedes construir el paquete (dpkg-buildpackage -b) e instalar libmemcached-tools que contiene memccp.

Este escenario es uno de los que describo en mi próximo libro rápido sobre Debian para aplicaciones Web, que está actualmente en fase de edición.

Reviviendo el Neo Freerunner en Campus Party Quito 2011

Hace más de 3 años puse mis manos en un Neo Freerunner, la segunda versión al público del teléfono celular del proyecto OpenMoko. Luego me pasé a Android (un HTC Magic) durante bastante tiempo y lo dejé por otros smartphones. Pero el Freerunner siguió ahí, desplazado por tecnología más nueva y por software más completo.

Hasta hace una semana.

Tuve la oportunidad de ser invitado a dar dos presentaciones en el escenario de Innovación de la Campus Party Quito 2011, y una de ellas era sobre clusters. Para lxs que me conocen, y lxs asiduxs al blog, la clusterización de servicios (y no la clusterización de cómputo científico) es un tema específico de expertise que me apasiona desde hace 5 años.

En mi paso por la Electrificación del Caroní, primero Corporación Venezolana de Guayana y ahora Corporación Eléctrica Nacional, una de las hidroeléctricas más importantes del mundo, le asignaron a mi equipo la responsabilidad de construir un cluster para correo electrónico con almacenamiento compartido.

El cluster, que se encuentra en producción, consta de servidores Itanium geográficamente distribuidos (EDELCA tiene una red que va desde Brasil hasta Colombia) así como balanceadores de carga en alta disponibilidad, un servicio de directorio propio, etc.

También he hecho clusters con máquinas virtuales anteriormente. Por ejemplo, hace algunos meses en el TechDay Quito, o en algunos screencasts de mi trabajo.

Pero para Campus Party Quito pensé que la gente necesitaba ver algo más cool, así que preparé un cluster sencillo, para un servicio sobre TCP (HTTP) usando HTML estático y los siguientes miembros del cluster:

1. Dos (2) máquinas virtuales Debian GNU/Linux 6.0 corriendo sobre Hyper-V en Windows Server 2008 R2, a su vez booteado desde un disco duro USB exteo (sí, se puede correr Windows en una memoria USB) con nginx como servidor Web

2. Una (1) máquina virtual Windows Server 2008 R2 con IIS corriendo PHP (específicamente Drupal) también sobre Hyper-V

3. Una (1) máquina física con Debian GNU/Linux Sid para las pruebas del cluster

4. Un (1) Openmoko Neo Freerunner corriendo Hackable:1 (distribución basada en Debian) y a su vez con lighttpd como servidor Web y conectado al router del cluster vía Wi-Fi

Con respecto a Hackable::1, la instalación fue straightforward. No usé microSD, sino la flash del teléfono. Tan solo necesité dfu-util (disponible en Debian) y las dos imagenes (keel y root filesystem) para flashear el dispositivo. Luego configuré USB networking para entrar por SSH al teléfono e instalar lighttpd y configurar la IP. Todos los detalles en el link de arriba.

El cluster está inspirado en la metodología Ultramonkey, específicamente en el escenario de HA+LB streamlined, donde se utiliza una sola capa de equipos Linux entregando HA, LB y potencialmente también el servicio. Esto reduce costos, pero requiere una configuración un poco cumbersome de ARP en las máquinas.

La verdad, la prueba salió bastante bien. El cluster respondió muy bien a los casos de prueba, que fueron:

1. Remoción en caliente de uno de los balanceadores de carga en alta disponibilidad

2. Remoción en caliente de uno de los equipos prestadores del servicio

3. Inclusión en caliente del balanceador de carga activo inicial (del caso 1) y restitución de la alta disponibilidad

Incluso, al final, el Freerunner se quedó sin batería (recuerden que era un miembro del cluster conectado por Wi-Fi) y el cluster lo manejó sin problemas.

También tuvimos la oportunidad de revisar diversas ventajas y retos de hacer un cluster, e identificar los SPOF (puntos únicos de falla) del cluster de demostración. Las láminas están publicadas aquí, y el video aquí. Gracias a todos/as los que participaron y se interesaron por el tema. Siempre estaré a la orden para cualquier inquietud.

Haciendo que nginx y Apache coexistan

nginx es un producto que me ha apasionado desde hace varios años. Su enfoque orientado a eventos lo hace inherentemente distinto a otros servidores Web, y en particular Apache y Cherokee que eran los dos que tenían mi atención allá en el 2006, cuando usaba Gentoo y pasaba la noche compilando cosas.

El rendimiento de nginx es increíble, y su funcionalidad como proxy reverso HTTP es incuestionable. Lo que la gente normalmente dice es que nginx tiene muy buen performance, pero pocas funcionalidades, especialmente cuando se compara con Apache, que tiene módulos para casi cualquier cosa.

A pesar de que mi primer proyecto grande con nginx fue justamente un caso de funcionalidades (hacer un proxy IMAP) estoy consciente de esa limitante, por lo que siempre he pensado que Apache es un buen servidor Web de backend, y nginx funciona muy bien en el frontend, como proxy reverso y caché. De hecho eso se aplica para otros servidores Web, incluso no solamente de código abierto sino propietarios como IIS o WAS.

Desde hace ya varios años utilizo una arquitectura sencilla pero con muchos beneficios, donde nginx se para delante de mis servidores Apache (que sirven aplicaciones con maravillosos módulos) y hace caché con el popular motor memcached.

Básicamente, en la instancia server de nginx correspondiente, y en el location que queramos servir, colocamos algo como:

location / {                set  $memcached_key  $uri;                memcached_pass 127.0.0.1:10101;                proxy_pass http://127.0.0.1:8080/;                ...        }

Lo que hacemos es pasar a un server memcached corriendo en 10101, y utilizar un proxy reverso en 8080, que en este caso sería nuestro Apache. La URI que el cliente desea es lo que se busca en memcache como una clave, y para eso sirve la primera línea. El resto de la configuración involucra instalar y correr memcached (en Debian y derivados, aptitude install memcached) e instalar, configurar y correr Apache en el puerto que definamos; y opcionalmente protegerlo con Netfilter (iptables).

Hay dos caveats de esta solución. El primero es que si delegamos los registros en Apache, solo veremos conexiones locales. Para eso hay soluciones, como pasar algunos headers con el host apropiado y usar un módulo de Apache (RPAF) en el backend. El segundo caveat es que no queremos que todas las aplicaciones pasen por el memcached, para ello podemos abrir el puerto del Apache, o bien definir otro server en nginx y solo usar proxy_pass.

En mi escenario, memcached ocupa alrededor de 2 MB. de memoria RAM cuando no hay carga y puede crecer hasta 64 MB. cuando hay carga (es el default) lo cual es razonable en un VPS.

¿Hay algo mejor que nginx? Sí. nginx y tu servidor Web preferido.

nginx como proxy balanceador de carga de otros servidores Web

Hace 4 años y medio que escribí por primera vez sobre nginx, un servidor Web orientado a eventos, muy robusto y elegante. En ese momento, Aníbal Rojas, uno de los programadores, profesionales y personas más creativas que conozco, me habló de nginx y de como se estaba haciendo popular en el underground de Ruby. Decidí dar un paso y empaquetarlo para Debian, era la versión 0.4.2

Mi primera experiencia con nginx en un proyecto grande fue utilizando sus capacidades de proxy IMAP para escribir un módulo de autenticación (en Perl) que consultaba en OpenLDAP el destino de una conexión entrante. Esto se convirtió en el IMAP de entrada de lo que es ahora la CORPOELEC.

Luego, me pregunté si podía usar nginx como proxy para Puppet, en vez del terrible servidor Web integrado (WEBrick) que traía en su momento.

Y desde hace algunos años, lo uso para hacer caché junto a memcached, escenario que publicaré en los próximos días. Pero nunca lo había puesto como un proxy balanceador de carga ante otros servidores Web, así que aquí explico como, y en realidad es bastante sencillo. Para hacerlo más interesante usé IIS en Windows Server 2003R2, tratando de emular lo que una organización con aplicaciones en .NET quisiera hacer para ahorrar costos de appliances de balanceo de carga usando software libre. Como nginx.

En mi escenario, nginx 0.7.67 corre en Debian, dirección IP 192.168.56.104, y IIS corre en dos máquinas Windows Server 2003, direcciones IP 192.168.56.101 y 192.168.56.102. En ambas he instalado Acquia Drupal, tal y como se instala con Web Platform Installer, y he nombrado a los sitios WS1 y WS2. He comprobado que puedo ver el sitio por las direcciones IP de los servidores.

En nginx, la configuración en el site (por ejemplo, en /etc/nginx/sites-available/default en Debian y derivados) se remite a:

upstream mycluster { # en el contexto http, que es el default de este archivo  server 192.168.56.101;  server 192.168.56.102;}...server {  ...  location / {    proxy_pass http://mycluster;  }}

Puedo hacer algunas variaciones, por ejemplo, dentro de upstream puedo definir un puerto para cada server, puedo usar IPv6, o puedo definir un peso (weight) para hacer un balanceo con preferencias, por ejemplo si uno de los servidores con Windows tiene más recursos de cómputo.

Un service nginx restart es suficiente para que la nueva configuración está funcionando y pueda llamar directamente a la IP (o host name) de nginx y utilizar los recursos del cluster. En Firefox, con http://192.168.56.104/acquia-drupal y recargando puedo ver como cambia el título WS1 y WS2 con cada request.

Si pongo un weight=2 en el primer server, cada 3 requests veré 2 con WS1 y 1 con WS2, y así sucesivamente.

¿Por qué es útil? Nuevamente, si tengo una granja de servidores de aplicación, potencialmente propietarios (como los de IBM o Microsoft) y administrados por una unidad dedicada que no necesariamente conoce de infraestructura, y quiero una solución rápida a un problema común (balanceo de carga) entonces puedo ahorrarme el overhead de tener appliances y hacer una solución en software con nginx sobre Linux. Y con nginx en el borde puedo hacer aplicaciones interesantes como el proxy IMAP del que les hablé o incluso colocar memcache antes de los servidores Web de backend.

Puntero Nulo – Episodio 5

Escúchalo:: PunteroNulo-Episodio5

La semana pasada me dijeron que el podcast era demasiado técnico. Gracias, aunque siempre intento digerir las noticias de tecnología algunos días después de que estén de moda (para no caer en la agenda) y de una forma que sea comprensible para la mayoría de la audiencia técnica.

Como siempre, sus comentarios y sugerencias son siempre bienvenidos en el correo j en bureado.com y en Twitter, @bureado.

De facto, el podcast ha estado saliendo quincenal así que mejor no engañaos. A continuación las fuentes de este episodio:

Follow

Get every new post delivered to your Inbox.

Join 1,800 other followers