Etiqueta: Performance

  • Qué es un CDN y por qué deberías usarlo

    Qué es un CDN y por qué deberías usarlo

    CDN significa Content Delivery Network o Red de Distribución de Contenidos.

    Se trata de conjuntos (por lo general bastante grandes) de servidores sincronizados entre sí y preparados para servir contenido estático desde diversos puntos del planeta.

    Su objetivo principal es el de disminuir el tiempo de carga de una página web (Algo que siempre viene bien).

    Este objetivo se logra combinando varios factores. Entre ellos:

    1. Aprovechando el paralelismo de los pedidos HTTP: Al tener el contenido distribuido en diversos servidores (en lugar de tener el código php y los archivos estáticos en el mismo) el cliente puede lanzar varias peticiones en paralelo por un lado y, por el otro, el pobre servidor al que llegan todos los visitantes de tu sitio puede delegar parte de la carga, lo cual a su vez hace todo el proceso más ligero.
    2. Sirviendo el contenido estático desde la locación física más cercana a cada cliente. Parte de la magia del CDN es tener la capacidad de identificar velozmente cuál es el nodo que responderá con menos latencia (Generalmente el que se encuentre más próximo al cliente).

    Qué se puede almacenar en un CDN

    Cualquier recurso estático (html, javascript, imágenes, etc…) es susceptible de ser almacenado en un CDN. De hecho, la mayoría de las librerías populares de javascript (Como jQuery por ejemplo) tienen sus propios CDNs que podés usar para cualquier proyecto, basta con hacer un include como este:

    <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    </head>

    De esta forma, en lugar de usar un archivo de jQuery alojado en tu propio servidor, usás la capacidad instalada de Google.

    Otra ventaja de usar un CDN (En realidad esto no es particular del CDN si no de cualquier fuente conocida) es que muy probablemente el cliente ya haya descargado el archivo que tu sitio necesita para funcionar, aún cuando se trata de la primera visita (Otra optimización de performance que realizan los navegadores).

    Alternativas

    CloudFlareExiste una gran cantidad de empresas que ofrecen servicios de CDN, te dejo acá algunas que yo he usado en proyectos propios:

    En cuanto a su funcionalidad están todas bastante cerca, el factor que suele inclinar la balanza es el precio… ahí CloudFlare es un claro ganador ya que ofrece un muy buen paquete gratuito.

    ¿Qué opinás? ¿Vas a implementar un CDN en tu próximo proyecto?

  • Un sistema de caché distribuido en PHP

    Un sistema de caché distribuido en PHP

    Hace un tiempo, cuando trabajaba para una gran .com del rubro turismo, surgió un escenario muy interesante que teníamos que resolver junto con mi equipo:

    Teníamos un servidor de bases de datos que daba soporte a siete servidores que hacían de FrontEnd. Nuestra aplicación era php puro (con un «framework» desarrollado in-house… muy mala idea) y todos los frontends corrían el mismo código (Todo detrás de un balanceador de carga, obvio):

    El problema que teníamos era que el sitio tenía bastante tráfico y la base de datos se nos convertía en un cuello de botella bastante a menudo.

    La solución que implementamos consistía en tener ciertas partes de las respuestas pre-calculadas.

    Ahora, como te imaginarás, mantener una experiencia de navegación consistente teniendo varios servidores diferentes tiene sus complicaciones, en nuestro caso, el desafío más importante era cómo mantener copias sincronizadas de la información pre-calculada (Para evitar, por ejemplo, que un simple F5 mostrara algo diferente de una página supuestamente estática).

    Por otro lado, los servidores de FrontEnd que usábamos eran simples instancias de máquinas virtuales que (no estoy muy seguro de por qué), tenían una tendencia a romperse intempestivamente (Bueno… un poco por eso teníamos tanta redundancia :)), con lo cual, no era viable tener un único responsable de la generación del caché…

    Lo que necesitábamos básicamente era una arquitectura que permitiera:

    1. Que cualquier FrontEnd fuera capaz de generar la versión estática de la información
    2. Que no hubiese dos FrontEnds generando la versión estática a la vez
    3. Que todos los FrontEnds sirvieran el mismo contenido (Si estaba disponible)

    Sin entrar en detalles sobre cómo logramos el objetivo 2 (Lo dejo para otro post en todo caso, pero involucra un sistema de semáforos), lo que hicimos fue crear una función (Método de una clase en realidad) que recibiera dos funciones:

    • Una para verificar si la copia local de la información estaba vigente aún
    • Otra para generar la información en caso de ser necesario

    Lo interesante de este mecanismo es que, gracias al uso de los callbacks fue bastante sencillo separar (¡y reutilizar!) el mecanismo de exclusión mutua y todo lo que hacía al andamiaje de lo que tenía que ver con la generación de la información propiamente dicha.

    Una versión simplificada del código a modo de ilustración es esta:

    public function get( $sKey, $iTtl, Closure $fGeneration, array $aGenerationParams = [], Closure $fValidation = null ) {   
       $oRemoteStorage = $this->getRemoteStorageFactory()->build($sKey);
       if ( ( $oCache = $this->getFromStorage( $oRemoteStorage ) ) && !$oCache->isExpired() && $fValidation( $mContents = $oCache->getContents() ) ) {
           $this->putInStorage( $oCache, $oLocalStorage );
           return $mContents;
       }
       $mContents = call_user_func_array( $fGeneration, $aGenerationParams );   
       $oCache = new CacheObject( $mContents, time() + $iTtl );
       $this->putInStorage( $oCache, $oLocalStorage );
       $this->putInStorage( $oCache, $oRemoteStorage );
       return $mContents;
    }
    

    Lo interesante de esta función son los parámetros $fGeneration y  $fValidation, ambos Closures, esta es la clave para que el mecanismo de caché se mantenga agnóstico respecto de qué es exactamente lo que se está cacheando… cómo se genera ese caché y cómo se verifica su vigencia son problemas del usuario del mecanismo de caché.

    De esta forma queda un sistema altamente reutilizable :).

    Si te interesa ver el código completo (Está un poco viejo, pero la idea sirve), acá está el repo en GitHub.