Hace unos meses, comencé a notar problemas de rendimiento en un web server debido a un exceso de conexiones entrantes. Es decir, en determinados horarios, este equipo recibía tantas peticiones que no lograba responderlas a todas y comenzaba a responder lento. Por supuesto, una configuración con load balancing o autoscaling lo habría solucionado, pero este caso merecía, al menos, una investigación técnica previa. El poder combinado de Cloudflare y CloudFront fue la solución a ¡costo cero!
El resumen |
|
---|---|
Viabilidad | Muy Buena |
Implementación | Media |
Dificultad | Baja |
Precio | Bajo |
La viabilidad es muy buena, ya que el bajo expertise necesario para implementarlo, el costo económico y el resultado final, hacen que sea un objetivo redituable.
A pesar de ser configuraciones relativamente rápidas, dependiendo del framework y la minuciosidad en la configuración, puede que la implementación pueda demorar tiempo.
Si bien puede ser que la implementación demore (no es lo mismo en un sitio a medida que usando un CMS de base como Wordpress), el bajo nivel de conocimiento necesario hace que la dificultad sea baja.
Finalmente, dependiendo del camino que elijamos y del tráfico al que el sitio esté sometido, el precio puede ser nulo (gratis) o de muy baja monta.
¿Qué es Cloudflare y para qué sirve?
Por lo general, los dominios que suelo manejar lo hago a través de Cloudflare ya que tiene múltiples beneficios incluso en su capa gratuita. El mayor (a mi criterio) es proveer al dominio de un CDN nativo. Esto lo logra mediante una configuración de proxy inverso:
Cliente => Cloudflare => Web server
El beneficio inmediato es que nos libramos de tener que configurar el origen de datos del CDN y reemplazar dominios a nivel código, ya que Cloudflare controla el 100% del tráfico y decide qué elemento cachear y desde dónde servirlo, ahorrándole mucho tráfico y peticiones al web server que, como ideal, sólo debería servir el HTML.
Cloudflare no es mágico, al menos en el plan gratuito
Ahora bien, si Cloudflare maneja todo y lo hace bien… ¿Por qué el web server está recibiendo tantas peticiones? Entonces me puse a investigar y me topé con algo interesante. Resulta que Cloudflare no guarda el caché de archivos para siempre.
Comienzo por explicar que a cada petición (request) se le puede configurar ciertas variables (headers) para mejorar el entendimiento entre el servidor y el cliente. En dichas variables, es posible indicar un valor de expiración del archivo en caché. En otras palabras, el servidor le dice al browser «este archivo lo podés guardar hasta esta fecha pero después pedímelo de nuevo». Cloudflare se vale, inicialmente, de esta variable (y otras) para guardar el archivo en la caché de su CDN y servirlo. Entonces, si le digo a Cloudflare «este archivo expira en 1 año»… ¿Lo servirá durante todo 1 año sin volver a pedírlo? La respuesta es NO. Lógicamente, si hiciese algo así, los discos de almacenamiento de Cloudflare estarían inundados de archivos que tal vez no vuelvan a usarse. Y por otro lado, la lógica implícita del plan gratuito nos dice algo como: «te ayudo a alivianar el tráfico» y no «te ayudo a servir tu sitio web». Y tiene mucho sentido además, ya que si un sitio no tiene un tráfico demandante, ¿Para qué necesitaría un CDN de todas formas?
Volviendo al tema del caché, Cloudflare obedece el tiempo establecido como expiración únicamente si el objeto es frecuentemente requerido. Por ejemplo, si pasa determinado tiempo sin que nadie pregunte por ese archivo, Cloudflare lo eliminará sin importar su fecha de vencimiento. Pero si el archivo es muy solicitado (como un .css o .js en la home de un sitio con varias visitas diarias), entonces lo retendrá y servirá hasta cumplir con la fecha de eliminación impuesta por el servidor. A este tiempo de vida se le conoce como TTL (time to live) y en Cloudflare «es» configurable. Esto es algo engañoso porque existen opciones de configuración para el TTL del CDN (nada intuitivo, sino que generando una regla específica y controlando el «Edge Cache TTL»). Sin embargo, este TTL puede expirar antes de lo previsto, siguiendo la línea de lo que indica la documentación para el sistema de caché de Cloudflare:
«Some CDNs will also purge files from the cache early if the content is not requested for a while».
Algunos CDNs (también) eliminarán archivos del caché si el contenido no se solicita por un tiempo.
¿Qué es CloudFront y para qué sirve?
Ahora, un vistazo rápido a CloudFront, de Amazon Web Services (AWS).
Comenzamos diciendo que es un CDN (no inverso, a diferencia de Cloudflare):
Cliente => Web server => Cloudfront
En este caso, debemos crear y configurar la distribución de datos en CloudFront, indicando ciertos parámetros, y luego reemplazar en el código el dominio actual por el del CDN. Entonces, si queremos servir una imagen como dominio.com/a.jpg
, habrá que reemplazarla con 123.cloudfront.com/a.jpg
, siendo «123.cloudfront.com» una URL aleatoria que nos generará CloudFront. De esta forma, la petición del objeto queda finalmente así:
Cliente => CloudFront => Web Server
a.jpg => existe en caché? devuelvo, sino => WS => caché y devuelvo
CloudFront es pago, pero también gratuito. ¿Eh?
Cuando creamos una cuenta en AWS, ingresamos a un free tier, que es una especie de plan gratuito por 1 año. Digo «especie» porque lo es siempre y cuando no utilicemos servicios por fuera de los límites establecidos. De hacerlo, comenzará a cobrarnos por el uso. Otra cosa: No todos los servicios tienen un free tier.
Afortunadamente, CloudFront está dentro del free tier y nos ofrece 50 GB mensuales de transferencia, lo suficiente para manejar tráfico moderado en un sitio web promedio, digamos que de 1.5 MB por página y unas 1000 impresiones (únicas) diarias. Un e-commerce en WordPress con un modesto nivel de ventas puede encuadrarse en este esquema. Sin embargo, en cuanto el sitio despegue, podremos sobrepasar fácilmente este límite e incurrir en gastos.
Y lo más importante: El tiempo en caché (TTL) de CloudFront puede configurarse para durar mucho más. La documentación del sistema de caché de CloudFront dice:
«If a file in an edge location isn’t frequently requested, CloudFront might evict the file—remove the file before its expiration date—to make room for files that have been requested more recently.»
Si un archivo no es solicitado frecuentemente, CloudFront podría removerlo antes de su fecha de vencimiento para dar lugar a archivos de uso más reciente.
Entonces, ¿Estamos en la misma que con Cloudflare? ¡No! Si bien la documentación dice eso, luego aclara que es posible modificar este comportamiento:
«…you can change the CloudFront settings for Minimum TTL, Maximum TTL, and Default TTL…»
Puede cambiar la configuración de CloudFront para un TTL Mínimo, Máximo y por Default.
Y este «Minimum TTL» es justamente el valor que necesitamos modificar para extender la vida del cache tanto como queramos. Este valor se respetará sin importar la frecuencia con la que el objeto es requerido.
Cloudflare + CloudFront: ¡Siempre es mejor ayudarse!
En vez de tanto luchar por uno y otro, ¿Por qué no elegir uno y listo? Porque combinándolos, se puede obtener lo mejor de ambos mundos.
Por un lado, tenemos a Cloudflare que es un servicio gratuito (plan) y nos proporciona una capa de caché fiable para mediana y alta demanda (corto plazo). Por el otro, tenemos a CloudFront, que es un servicio pago pero tiene una capa de uso gratuito, y nos porporciona una capa de caché fiable a largo plazo. ¿Y si conectamos uno detrás de otro? Eso mitigaría la falencia de corto plazo de Cloudflare, pero también haría que el tráfico servido por CloudFront (como fallback) no se pase nunca del límite grauito. Obtendríamos un caché de objetos lo suficientemente perdurable para alivianar casi por completo la carga del servidor y permitir servir una mayor cantidad de sitios u otros objetos sin costo.
Cloudflare y los dominios externos
El esquema que buscamos es el siguiente:
Cliente => Cloudflare => CloudFront => Web server
[IP] => d.com/a.jpg => 123.cloudfront.com/a.jpg => [IP]
Acá nos encontramos con el primer obstáculo, que para muchos resultará evidente: si Cloudflare sólo es capaz de proporcionar caché mediante dominios dentro de su nube y CloudFront es un dominio externo, entonces… ¿Cómo hace Cloudflare para cachear y servir un recurso cacheado en el dominio externo de CloudFront? El browser, al ver 123.cloudfront.com/a.jpg
irá a recuperarlo desde CloudFront, CloudFront irá a Cloudflare (ya que Cloudflare es transparente), y nuestro esquema quedará al revés:
Cliente => CloudFront => Cloudflare => Web server
Y esto no es lo que buscamos, porque toda la carga la estará recibiendo directamente CloudFront, y además los objetos de corta duración en Cloudflare directamente no existirán (se crearán y desaparecerán en cuestión de horas) y siempre irá a recuperarlos al Web server. En definitiva, este esquema no sirve.
Sin embargo, Cloudflare nos permite una ventaja inesperada. ¡El sistema es capaz de cachear el contenido de dominios externos que estén asociados a un «alias»! Bueno, no es exactamente un alias, pero conceptualmente es muy parecido: un registro CNAME. Este registro nos permite asociar un nombre de dominio con otro. Entonces, podríamos apuntar cdn.dominio.com/a.jpg
a 123.cloudfront.com/a.jpg
y Cloudflare cachearía el contenido.
Cliente => Cloudflare => CloudFront => Web server
[IP] => cdn.d.com/a.jpg => 123.cloudfront.com/a.jpg => [IP]
¿Así de simple? ¡Sí! Si queremos ser detallistas, si bien el esquema mostrado está reducido, en realidad hay un pasamanos más luego del eslabón de CloudFront, que es un poco redundante:
Cliente => Cloudflare => CloudFront => Cloudflare => Web server
[IP] => cdn.d.com/a.jpg => 123.cft.com/a.jpg => d.com/a.jpg => [IP]
¿Nos afecta? ¡Para nada! No sé internamente lo que ocurre o implica para Cloudflare, es decir, si ese objeto se duplica o hay una tabla de referencias a archivos para no tener objetos duplicados, pero para lo que nosotros lo necesitamos no nos molesta.
Configuracion de CloudFront y Cloudflare
1 Creación del certificado SSL (HTTPS) para CloudFront
Asumiremos que nuestro sitio web está cableado con SSL (HTTPS), por lo que primero necesitaremos generar y configurar el certificado con Amazon Certificate Manager:
Cómo Crear un Certificado SSL Público con Amazon Certificate Manager para AWS
2 Creación de la distribución en CloudFront y configuración en Cloudflare
El segundo paso será crear la distribución en Amazon CloudFront:
Cómo Configurar Amazon CloudFront como CDN Creando una Distribución
Acá debemos prestar atención a algunos puntos:
- TTL: Debemos asignar un valor propio. aclarado en el tutorial
- SSL: Debemos configurar el certificado creado. aclarado en el tutorial
- Cloudflare: Debemos agregar el CNAME del dominio de la distribución al subdominio elegido. aclarado en el tutorial
3 Cambiar el dominio a los objetos estáticos en nuestro sitio
Por último, debemos reemplazar el dominio de las URLs a los objetos estáticos (CSS, JS, imágenes, fuentes, etc.) en nuestro sitio web. Por ejemplo reemplazando https://dominio.com/*
con https://cdn.dominio.com/*
, de modo que las URls queden así: https://cdn.dominio.com/css/styles.css
. La implementación dependerá exclusivamente de cómo hayamos construido el sitio web. No es lo mismo haber utilizado un CMS (Wordpress, por ejemplo) que haberlo desarrollado utilizando un framework (Laravel, por ejemplo). Para el caso de WordPress, existen varios plugins que se emplear para para conectar con un CDN. Mi favorito (y el más sencillo de los que he probado) es WP Fastest Cache. Este plugin nos permite tanto agregar una capa de caché estática como reemplazar las URLs por el CDN que elijamos, y todo de una forma muy sencilla.
Estadísticas de la implementación
De nada serviría toda esta teoría si no se pudiese avalar con datos. Acá muestro el caso de un sitio web con tráfico moderado bajo (unos 3 mil usuarios por día): Ornela Recetas.
Este sitio web fue construído utilizando WordPress y está cubierto por Cloudflare + CloudFront. Se utiliza el plugin WP Fastest Cache para brindar caché y CDN. Si se observa el código fuente, se podrá ver que el dominio de todos los elementos estáticos ha sido reemplazado por cdn.ornelarecetas.com.ar
. También puede observarse en los gráficos la cantidad de usuarios únicos en los últimos 3 meses, y estadísticas de peticiones atajadas por el CDN de Cloudflare y CloudFront.
Por ejemplo, la transferencia mensual es servida en su mayoría por Cloudflare (casi 90 GB), contra los 2.3 GB servidos por CloudFront como backup. Este número es especialmente dispar debido a que es un sitio activo, con elementos de consulta recurrentes por su buen posicionamiento orgánico, lo cual hace que haya puntos de entrada bien definidos. Muy distinto sería un e-commerce, donde los elementos se dan por búsquedas internas, haciendo variar demasiado algunos objetos (como imágenes), que serán cacheadas pero no recuperadas desde el caché dada su poca exposición (ocurrirá primero la fecha de expiración que un nuevo hit).
Otro dato a considerar es que esos 90 GB posiblemente sean engañosos, ya que como la cadena, luego de CloudFront es nuevamente Cloudflare debido a su condición «transparente» (Cloudflare => CloudFront => Cloudflare), tal vez se considere como doble (o más) la recuperación de un objeto. Por ejemplo, tomemos el caso de que no exista a.jpg
ni en Cloudflare ni Cloudfront: cdn.dominio.com/a.jpg (Cloudflare)
irá por 123.cloudfront.com/a.jpg (CloudFront)
, que irá por dominio.com/a.jpg (Cloudflare)
, que irá por 200.186.5.15/a.jpg (Servidor)
quien lo devolverá (transf. OUT Server #1); luego lo recibirá Cloudflare (transf. IN Cloudflare #1) en dominio.com/a.jpg
y devolverá (transf. OUT Cloudflare #1) a CloudFront (transf. IN CloudFront #1) en 123.cloudfront.com/a.jpg
, que se lo devolverá (transf. OUT CloudFront #1) a Cloudflare (transf. IN Cloudflare #2) en dominio.com/a.jpg
, que se lo devolverá (transf. OUT Cloudflare #2) al cliente. Si consideramos las transferencias de entrada IN y salida OUT, veremos que cada petición no cacheada se desglosa en varias transferencias adicionales entre (al menos) 3 servidores, generando una doble transferencia (de entrada y salida) en Cloudflare, que seguramente afectará las estadísticas.
Conclusión final
En definitiva, este es un método de hilado fino. No es imprescindible su implementación para todos los sitios, aunque ayuda a balancear la carga en sitios de mediana y alta demanda, y los resultados son notorios a nivel servidor. La ventaja es el costo cero para la mayoría de los sitios que lo implementen, ahorrando transferencia, memoria y cpu en el servidor, permitiendo almacenar más sitios en un mismo equipo, o mejorar el rendimiento en equipos de baja potencia.
Hola.
Muy buen post, justo lo que había estado buscando y pensé que no tenía lógica.
Si fueras tan amable podrías indicar el proceso para hacerlo en WordPress, y si hay que tocar algo en Cloudflare.
De antemano gracias.
Hola! Perdón la tardía respuesta! Para WP es bastante sencillo. Podés seguir los pasos acá para configurar Cloudflare y Cloudfront (la interfaz de ambos cambió un poco, pero igual sirve): https://lucianofantuzzi.com/blog/tutoriales/como-configurar-amazon-cloudfront-como-cdn-creando-una-distribucion/
Luego en WP instalás el plugin «WPAdmin AWS CDN» y lo configurás con el dominio que hayas creado (ej: cdn.midominio.com), NO con el de la distro de CloudFront, obviamente.
IMPORTANTE: Si tenés un plugin de cache en el medio como «WP Fastest Cache», no instales el plugin anterior, simplemente configurá el CDN en las opciones del plugin para evitar problemas.