Historia de una migración

El de cómo planteamos la migración de la infraestructura de Uvinum a un entorno virtualizado

Albert Garcia
Building the Wine&Spirits Marketplace
7 min readSep 20, 2016

--

Históricamente Uvinum ha funcionado en su mayor parte sobre una infraestructura de 2 servidores físicos dedicados que se repartían los principales servicios y responsabilidades: un servidor de aplicación -AKA Pekesaurio- y un servidor de base de datos -AKA Bobby- (¿no le ponéis nombres a vuestros servidores? ;D).

Dos servidores (dedicados) principales con algunos servicios puntuales en cloud

Más allá de algunos servicios como el alojamiento de ficheros (Amazon S3), el CDN (MaxCDN) o las instancias de nuestro crawler (pequeñas instancias cloud en DigitalOcean), la mayoría de los servicios se concentran en los dos servidores dedicados: Apache, PHP, MySQL, Memcached, Redis, Sphinx, Beanstalkd…

Escalando verticalmente

Con el paso del tiempo y el incremento de las necesidades del proyecto en términos de recursos y rendimiento, hemos recurrido al escalado en vertical, es decir, incrementamos los recursos y la potencia de estos servidores. Aunque esto nos ha permitido crecer sin muchos problemas, presenta algunos inconvenientes. Principalmente:

  • No aprovechar de forma óptima los recursos disponibles. Al convivir tantos servicios en una misma máquina, varios de ellos consumen recursos de diverso tipo, compitiendo en algunos casos por los mismos (p.e. alto consumo de CPU de los agentes de Sphinx compitiendo con los procesos periódicos de consolidación de datos de PHP).
  • Puntos únicos de fallo. Aunque ambos servidores tienen instalados todos los servicios disponibles para poder afrontar el fallo de alguno de ellos en el servidor que lo ofrece de forma habitual, ni los estamos balanceando de forma automática, con lo que el posible cambio debería llevarse a cabo de forma manual, y el punto de entrada a la aplicación se lleva a cabo desde un frontal. Ante un eventual fallo grave de este servidor, sería necesario un cambio de DNS o de IP pública en el servidor restante para encaminar el tráfico del servidor caído. Por suerte nunca ha sido necesario. Por suerte. ¬¬

La nueva infraestructura

Ante este escenario nos planteamos el rediseño de la infraestructura para tratar de mitigar estos dos problemas y sentar unas bases de futuro:

Una infraestructura con todos los servicios balanceados y redundados en diferentes máquinas virtuales, en cloud privado

Separamos los servicios principales en máquinas diferentes, y nos aseguramos de que todos ellos estuvieran redundados, de forma que pudieran ser reemplazados de forma automática en caso de fallo gracias al balanceo. Por una parte el balanceo de MySQL y Sphinx se lleva a cabo mediante nuestra propia aplicación, que gestiona un pool de servidores disponibles cacheado en Memcached. Por otra, el balanceo de los frontales web del marketplace y de nuestro backend lo gestionamos con HaProxy. ¿Y quién balancea al balanceador? Para eso aprovechamos el DNS failover que ofrece la gente de DNS Made Easy. En nuestras zonas DNS tenemos definida una IP principal y una IP de backup, que entra en funcionamiento en caso que la principal falle. De esta forma, en caso de fallo el tráfico se redirigiría al segundo balanceador.

Virtualización VS servidores físicos

Aunque inicialmente evaluamos también la posibilidad de seguir con servidores físicos para reproducir la estructura de la imagen anterior, nos acabamos decidiendo por una opción basada en virtualización: mejor control de costes, mayor flexibilidad a la hora de ajustar la configuración y los recursos de cada máquina o crear templates, agilidad a la hora de poner en marcha nuevas máquinas, portabilidad de las máquinas virtuales entre diferentes nodos / entornos, recuperación rápida de backups basados en snapshots…

Si bien es cierto que existen algunos contras, como el impacto en performance de algunos procesos por la propia virtualización, existen algunos puntos a tener en cuenta que pueden ayudarnos a exprimir los recursos de forma que podamos obtener un rendimiento óptimo de nuestro nodo y las máquinas virtuales que levantemos (p.e.: limitar las vCPU y levantar más VMs = performance boost).

De momento hemos descartado Docker básicamente por falta de experiencia con la tecnología. Sigue en el radar para próximas versiones. :-)

Provisionamiento y configuración del stack: Ansible al rescate

Hasta ahora sólo usábamos Ansible para provisionar nuestro entorno de desarrollo en Vagrant (y para el deploy del código en producción con Ansistrano).

Aprovechando como base lo que ya habíamos ido preparando para reproducir nuestro entorno de producción en Vagrant, hemos preparado un conjunto de roles y playbooks que nos sirven para que todos los entornos puedan compartir una misma configuración, con ciertas particularidades (reglas de firewall, archivos hosts, crons y poca cosa más. El resto es compartido 100%).

Sin entrar mucho en detalle en el cómo y el qué hacemos con Ansible, valga decir que nos permite aprovechar al 100% las ventajas de la virtualización que antes mencionamos: Podemos levantar un nuevo nodo y sus máquinas virtuales, provisionarlas y configurarlas desde cero y desplegar el código de la aplicación, incluyéndolas en los pools de balanceo en cuestión de minutos. Si te interesa, hace unos meses publicamos una pequeña presentación sobre cómo empezamos a usar Ansible en Uvinum.

Pruebas de carga

Una vez hemos tenido todas las máquinas virtuales en marcha, provisionadas, configuradas y con el código desplegado, hemos preparado algunas baterías de pruebas para poder comparar el rendimiento de la plataforma anterior VS la actual. Las pruebas han consistido básicamente en

  1. Prueba de carga web. Hemos preparado una prueba basada en el tráfico real acumulado de un día normal, extrayendo todas las URL visitadas del log de Apache en un día cualquiera. Tomando como base ese listado de URLs, y mediante Parallel y Apache Benchmark, hemos podido simular un volumen de carga similar al de producción. De esta forma podemos comparar con bastante fiabilidad el comportamiento que tendrá la aplicación una vez en producción y el funcionamiento de todos los servicios, la comunicación entre las máquinas, posibles incrementos de tiempo debido a la latencia de red que se añade con esta estructura, etc. Usamos New Relic para monitorizar el rendimiento de la aplicación y los servidores, y en base a estas mediciones hemos podido ver mejoras de rendimiento del 25%. ✔ Check.
  2. Tiempos de ejecución de procesos diarios con uso intensivo de BD. Cada día lanzamos algunos procesos de importación y validación de catálogos de nuestros afiliados que hacen un uso intensivo de base de datos, tanto en escritura como en escritura. Aunque mantuviéramos tiempos de querys o ejecución de PHP, un problema de latencia de red podría suponer un retraso importante en la ejecución de estos procesos (hablamos de varios millones de queries por ejecución). La mejora en este caso ha sido de un ~45%. ✔ Check
  3. Tiempos de ejecución de procesos diarios con uso intensivo de disco y CPU. Además de los procesos relacionados con los catálogos de los afiliados, tenemos varios procesos que se encargan de la generación de feeds para terceros (merchant, adwords, etc.). Hay pocas consultas, que devuelven gran cantidad de datos, con un peso importante en tratamiento de datos desde PHP y en acceso a disco, para la generación de unos pocos miles de ficheros. La mejora en este caso ha sido de un ~30%. ✔ Check.

Migración

Vistos los resultados, sólo queda arremangarse y empezar a mover los servicios a la nueva infraestructura virtualizada. Estos son los pasos que seguiremos, con el objetivo de evitar (o minimizar al menos) cualquier downtime:

  • Movimiento de la BD: Copia de seguridad en caliente de la actual BD de producción usando Xtrabackup de Percona. Movimiento de los datos a la BD principal en el nuevo entorno. Configuración de ésta como réplica de la BD de producción para asegurarnos de que dispone de todos los datos que se hayan originado durante la copia y el movimiento de datos. Una vez completada la replicación, reemplazo del master de producción actual al nuevo entorno, promoviendo la nueva BD como master. Finalmente, repetiremos el proceso con la BD secundaria en el nuevo entorno, quedando la configuración master / slave completada. En la aplicación de producción empezaremos a apuntar a las nuevas BD.
  • Movimiento de Sphinx: En este caso será más sencillo. Simplemente regeneraremos los índices desde cero, lo que no debería llevar más de 5–10 minutos. Podríamos copiar los índices desde los servidores actuales de producción, pero durante el proceso de optimización que llevamos a cabo además modificamos la configuración de los agentes, para poder aprovechar al máximo la CPU disponible, reduciendo los tiempos de las consultas a Sphinx en un 70%. Dado que la cantidad de índices no coincidirá con la disponible actualmente en producción, no podemos llevar a cabo este movimiento de archivos y será mejor una regeneración completa de los mismos.
  • Movimiento de frontales: Movidas las principales fuentes de datos, sólo nos quedará empezar a encaminar las peticiones que lleguen a nuestros dominios a las nuevas máquinas. Para esto, simplemente actualizaremos las zonas DNS de los dominios principales, aprovechando para configurar el DNS failover apuntando al segundo balanceador. Probablemente configuremos los Apache de los servidores de producción para que actúen como proxy, para agilizar el paso de todo el tráfico al nuevo entorno.

Hecho esto, y a falta de ir afinando algunos detalles (nuevas políticas de backup, tratamiento de logs distribuidos, etc.), podremos dar por finalizado el proceso. Esperamos que os resulte útil en caso que os encontréis en una situación similar.

Agradecer al equipo de Dinahosting el trato y el buen servicio durante estos años y a nuestro nuevo proveedor StackScale por acompañarnos en el montaje y la optimización de la nueva infraestructura.

--

--

Albert Garcia
Building the Wine&Spirits Marketplace

Former CTO & founder @ Uvinum.com, also OboLog & Splitweet. Father of @soclajulia & @soclabril