rendimiento en aplicaciones web con symfony2

64

Upload: asier-marques

Post on 14-Dec-2014

5.809 views

Category:

Technology


3 download

DESCRIPTION

Ponencia sobre rendimiento web orientado a aplicaciones web Symfony2, para el evento #desymfony 2011

TRANSCRIPT

Page 1: Rendimiento en aplicaciones web con Symfony2
Page 2: Rendimiento en aplicaciones web con Symfony2
Page 3: Rendimiento en aplicaciones web con Symfony2

Asier Marqués @asiermarques

Socio fundador de Blackslot.com

Socio fundador de Artesanio.com

Organizador de #webdevbilbao

Arquitecto web, ex-administrador de sistemas Microsoft, apasionado de la creación de servicios en internet y adicto al café.

Escribo en asiermarques.com

Page 4: Rendimiento en aplicaciones web con Symfony2

Rendimiento Web

Page 5: Rendimiento en aplicaciones web con Symfony2

El rendimiento importaSegún kissmetrics.com:

El 73% de los usuarios de móvil ha encontrado algún sitio web demasiado lento en cargar.

El 47% de los usuarios esperan un máximo de 2 segundos a que cargue una página web en la que van a comprar algo. 

Si un sitio de comercio electrónico está ganando $ 100.000 por día, un retraso de 1 segundo en la página podría costar $ 2.5 millones de perdidas al año.

http://blog.kissmetrics.com/loading-time

Page 6: Rendimiento en aplicaciones web con Symfony2

Rendimiento no es escalabilidadPero es clave que la aplicación esté bien diseñada y sea escalable.

Page 7: Rendimiento en aplicaciones web con Symfony2

Cómo diseñar bien

• No te repitas. DRY

• Divide. MVC

• Calidad. TDD

• Symfony2 te ayuda a conseguirlo.

Page 8: Rendimiento en aplicaciones web con Symfony2

“la optimización prematura es la raíz de todo mal”

Donald Knuth

Page 9: Rendimiento en aplicaciones web con Symfony2

Antes de optimizar

• No resuelvas problemas que no tienes

• No tomes decisiones tecnológicas en base a lo que hacen “los grandes”

• Monitoriza, estudia la información y después optimiza

• Evita operaciones síncronas que supongan demora

Page 10: Rendimiento en aplicaciones web con Symfony2
Page 11: Rendimiento en aplicaciones web con Symfony2

Usa InnoDB!

Page 12: Rendimiento en aplicaciones web con Symfony2

MyISAM

Bloqueos a nivel de tabla, no de filaLos selects pesados bloquean la tabla frente a escrituraLas escrituras bloquean la tablaLOW_PRIORITY, HIGH_PRIORITYhttp://dev.mysql.com/doc/refman/5.0/en/table-locking.html

No soporta transacciones

No es relacional

Page 13: Rendimiento en aplicaciones web con Symfony2

InnoDB

Relacional

Bloqueos de fila, no de tabla

Soporta transacciones• Doctrine2 hace uso interno de

transacciones

Page 14: Rendimiento en aplicaciones web con Symfony2

Configuración

Innodb_buffer_pool_size

Innodb_log_file_size

Innodb_flush_log_at_trx_commit=2

innodb_flush_method=O_DIRECT

innodb_file_per_table

Page 15: Rendimiento en aplicaciones web con Symfony2

Query Cachehttp://dev.mysql.com/doc/refman/5.1/en/query-cache-status-and-maintenance.html

query_cache_type = 1 # 0 desactivada, 1 activada, 2 bajo demandaquery_cache_size = <tamaño de cache>

SHOW STATUS LIKE 'Qcache%';

! -> Qcache_hits: Número de aciertos de la query caché.

! -> Qcache_lowmem_prunes: El número de consultas eliminadas de la cache por falta de memoria disponible.

! -> Qcache_inserts: El número de consultas insertadas a la cache.

Page 16: Rendimiento en aplicaciones web con Symfony2
Page 17: Rendimiento en aplicaciones web con Symfony2

El espacio importa

Page 18: Rendimiento en aplicaciones web con Symfony2

DivideParticionado

Vertical (por columna)Horizontal (por fila)http://mysql.isu.edu.tw/tech-resources/articles/testing-partitions-large-db.html

Mantener los datos de texto opcionales en otra tabla

Configura InnoDB con innodb_file_per_table Cada archivo maneja1) Los datos de la tabla2) Los datos de los índices3) Los MVCC (Multiversioning Concurrency Control) 4) La metainformación de la tabla

Optimize Table reduce la información de cada archivo y reorganiza los índices

Page 19: Rendimiento en aplicaciones web con Symfony2

Índices

Usa EXPLAIN para saber cuando utilizarlos

NOT NULL cuando sea posibleUna columna indexada que pueda ser NULL ocupa más espacio

Usa el tipo de datos correcto

Page 20: Rendimiento en aplicaciones web con Symfony2

EXPLAIN <QUERY>

Valores en los que fijarte

typeALL indica que debe recorrerse toda la tabla y debe evitarseINDEX se debe recorrer todo el índice

key y key_lenCuanto menor sea el valor de KeyLen mejorKey te indica el Índice elegido para la consulta

EXTRAEvitar Filesort y tablas temporalesLas tablas temporales aparecen al ordenar resultados o al hacer agrupaciones

Page 21: Rendimiento en aplicaciones web con Symfony2

Índices y espacio: Tipos de datos

Usa INT en claves primarias como unsigned en lugar de BIGINT.

Usa TINYINT en lugar de INT(1).TINYINT es 1 Byte, INT(1) son 4

Usa BIT para booleanos en lugar de INT(1) o TINYINT

Usa TIMESTAMP en lugar de DATETIMETIMESTAMP son 4 Bytes, DATETIME son 8

Page 22: Rendimiento en aplicaciones web con Symfony2

Índices y espacio: Tipos de datos

Usa CHAR(num) en lugar de VARCHAR(num) para valores fijos

No uses palabras en ENUM(), usa un solo carácter si es posible

Usa unsigned INT para guardar ips, no varchar

Usa utf8 cuando sea realmente necesarioVarchar(255) en utf8 son más de 700 bytes

Page 23: Rendimiento en aplicaciones web con Symfony2

Conoce tus consultas

Es peor tener 83 consultas simples que una consulta “compleja”

No hagas operaciones matemáticas en tus consultas

Aligera en la medida de lo posible tus consultas

No hagas JOINs en campos que no tengan índice

Cuidado con los count y los order

Page 24: Rendimiento en aplicaciones web con Symfony2

Conoce tus consultas

Count(*)Usa mejor SQL_CALC_FOUND_ROWS

OrderByfilesort en la mayoría de los casosrecupera los PK en una consulta simple antes de hacer una consulta compleja

Page 25: Rendimiento en aplicaciones web con Symfony2

Ejemplo típico en doctrine

Es típico hacer consultas innecesarias dentro de un bucle.

Tomemos por ejemplo la aplicación de #desymfony

Page 26: Rendimiento en aplicaciones web con Symfony2

Vista de PonentesSe ejecuta el siguiente dql en el controlador

SELECT p FROM Desymfony\DesymfonyBundle\Entity\Ponente pORDER BY p.nombre ASC

Y en la vista se hace

{% for ponente in ponentes %} … {% for ponencia in ponente.ponencias %}

Page 27: Rendimiento en aplicaciones web con Symfony2

Resultado

Cada iteración de Ponente hace una query de Ponencias

Tenemos 13 ponentes, se ejecutan 13 querys

Con 200 ponentes, se ejecutarían 200 querys

Page 28: Rendimiento en aplicaciones web con Symfony2

La solución es sencilla

En el DQL

SELECT p, po FROM Desymfony\DesymfonyBundle\Entity\Ponente p INNER JOIN p.ponencias po ORDER BY p.nombre ASC

Solamente con añadir el INNER JOIN reducimos el número de querys a tan sólo una en lugar de 13 o (n).

Page 29: Rendimiento en aplicaciones web con Symfony2

Symfony y Doctrine

Usar arrays en las vistas en lugar de objetos

Usar la cache de doctrineCache de DQL$config->setMetadataCacheImpl(new Doctrine\Common\Cache\ApcCache());

Cache de resultados$config->setQueryCacheImpl(new Doctrine\Common\Cache\ApcCache());

Page 30: Rendimiento en aplicaciones web con Symfony2

Búsqueda

InnoDB no soporta FULLTEXT

Sphinx, Lucene, SolrBuenas opciones incluso para reducir complejidad en consultas, pe. Ordenar, filtros complejos..

Page 31: Rendimiento en aplicaciones web con Symfony2

Analiza

Debes llevar un control de lo que sucede a diario en tu servidor y comparar los valores que obtengas cuando este tenga problemas con tus valores normales.

Herramientas: Munin, Nagios, Cacti..

Page 32: Rendimiento en aplicaciones web con Symfony2

Analiza mysqladmin extended

Threads_runningNúmero de consultas que se están ejecutando.

Handler_read_rnd_next y Handler_read_firstSi es muy superior a lo normal puede que sea debido a un problema con los índices.

Handler_rollback El número de rollbacks que se han hecho.

Select_full_joinJoins sin índices, debe ser cero.

Slow_queriesSi este valor crece indica problemas en el rendimiento de la aplicación.

Page 33: Rendimiento en aplicaciones web con Symfony2

AnalizaSHOW FULL PROCESS LIST\G

Para saber cuánto tardan las consultas pesadas en ejecutarse y las que se encuentran en estado “Locked”

SHOW TABLE STATUS FROM <base datos> LIKE ‘<nombre>’\GComprobar el espacio de la tabla (el Max_data_length nunca puede ser consumido por completo)

EXPLAIN [EXTENDED] <query>

SHOW INNODB STATUS\GEstadísticas de acceso a disco, transacciones, consultas con problemas de integridad..

SHOW PROFILE Comprobar los recursos de hardware consumidos por una queryhttp://dev.mysql.com/doc/refman/5.0/en/show-profiles.html

Page 34: Rendimiento en aplicaciones web con Symfony2

NO SQL

No lo uses por moda, conoce la tecnología y los problemas que solventaConoce sus posibilidades de escaladoConoce su rendimientoConoce sus posibilidades de backup/restore!

Funciona bien como frontend de una base relacional si su motor es rápido

Buena alternativa a desnormalizar

Page 35: Rendimiento en aplicaciones web con Symfony2

Cache

Page 36: Rendimiento en aplicaciones web con Symfony2

Http Cache – RFC 2616

Symfony2 implementa la cache definida en el RFC

Sigue los conceptos Expiración-Validación

Symfony2 tiene su propio proxy cache pero permite ser integrado con sistemas proxy cache como Varnish.

Page 37: Rendimiento en aplicaciones web con Symfony2

Cache-Control

PublicTodos los usuarios comparten la cache

PrivateLa cache es distinta para cada usuario

No-CacheNo se cachea en ningún casoEn Symfony2 por defecto es no-cache o private

Page 38: Rendimiento en aplicaciones web con Symfony2

Expires y Cache-Control: max-age

expires (fecha GMT)Frescura = expires – fecha actual

max-age (segundos)s-maxage se usa por servidores proxy, es público por lo que es común a todos los usuarios

max-age tiene prioridad sobre Expires ..y s-maxage sobre el max-age si es pública

Page 39: Rendimiento en aplicaciones web con Symfony2

expires y max-age en Symfony2

$response = $this ->render('DesymfonyBundle:Ponente:index.html.twig', array('ponentes' => $ponentes));        $response->setPublic();       $response->setMaxAge(10); <- Private $response->setSharedMaxAge(10); <- Public

  $date = new DateTime(); $date->modify('+60 seconds');

$response->setExpires($date); <- Private (si no hay un setPublic())

       return $response;    

Page 40: Rendimiento en aplicaciones web con Symfony2

expires y max-age en Symfony2

Primera carga de la página, 234ms

Carga desde la caché, 3ms

Page 41: Rendimiento en aplicaciones web con Symfony2

Validación: Last Modified y ETAG

Last ModifiedFecha de última modificación del archivo, si el servidor retorna una fecha menor a la de la caché del cliente, descargará el archivo.

EtagEl navegador cachea el archivo identificándolo con el valor del Etag.

El navegador comprobará si debe servir el archivo comparando el Etag del servidor con el valor que él tiene almacenado en su cache, para ello usará el campo If-None-Match

Page 42: Rendimiento en aplicaciones web con Symfony2

Last Modified y ETAG en Symfony2

//debemos crear los métodos en la entidad$etag = $entity->getCurrentETag();$mod_date = $entity->getLastModification();

$response->setETag($etag);$response->setLastModified($mod_date);

if($response->isNotModified($this->get('request'))){ …

Page 43: Rendimiento en aplicaciones web con Symfony2

Varnish

Page 44: Rendimiento en aplicaciones web con Symfony2

Varnish

• Proxy cache

• Balanceador de carga

• Lenguaje de configuración VCL

• Soporte para ESI y HTTP Cache

Page 45: Rendimiento en aplicaciones web con Symfony2

Varnish

Podemos especificar

qué es lo que queremos cachear

Declaramos el servidor o

servidores web frontales

Retornando pass evitamos que se cachee y con lookup

forzamos a que se busque en el cache

Page 46: Rendimiento en aplicaciones web con Symfony2

VarnishPodemos

indicar un ttl para el objeto en la cache

También podemos evaluar si queremos

cachear desde aquí

Page 47: Rendimiento en aplicaciones web con Symfony2

Varnish: invalidar cacheIndicamos los Host que pueden lanzar

peticiones de invalidación

Si el request es de tipo PURGE se elimina la

url del host especificado

curl -X PURGE http://dominio.com/url-a-invalidar

Page 48: Rendimiento en aplicaciones web con Symfony2

Varnish: ESI

Page 49: Rendimiento en aplicaciones web con Symfony2

Varnish: ESISI una url contiene tags ESI basta con

indicar esi; para que Varnish lo procese

Podemos establecer que si la ruta es /esi/*

le ponga otro ttl o retorne pass, evitando

que se cachee

Page 50: Rendimiento en aplicaciones web con Symfony2

Varnish con Symfony2

En la plantilla{% render '...:vista' with {}, {'standalone': true} %}Devuelve..<esi:include src=“http://dominio/url_al_contenido”/>

Symfony2 añade automáticamente sólo cuando use ESI un header Surrogate-Control = "abc=ESI/1.0“.

En Varnish le debemos indicar que es capáz de procesar ESI con set req.http.Surrogate-Capability = "abc=ESI/1.0“.http://symfony.com/doc/2.0/cookbook/cache/varnish.html

Page 51: Rendimiento en aplicaciones web con Symfony2

Más cosas

Page 52: Rendimiento en aplicaciones web con Symfony2

APC

ByteCode cache para PHP

APC.STAT = 0En producción si no hay cambios frecuentes

Page 53: Rendimiento en aplicaciones web con Symfony2

Assetic

Agrupa los estáticos indicados de tu sitio web en un único archivo.

Se puede escribir en disco, en un cdn (pe.Amazon s3) o manejar como string.

Comprime y optimiza los css, js e imágenes.

Reduce las peticiones HTTP

Se integra con HTTP Cache de Symfony2 y con la sintaxis de Twig

Page 54: Rendimiento en aplicaciones web con Symfony2

Assetic

$assets = new AssetCollection( array( new FileAsset(“web/Bundle/style.css”), new GlobAsset(“web/*.css”), )

);$assets->load();

$writer = new AssetWriter(“s3://bucket”);$writer->writeManagerAssets($assets);

Page 55: Rendimiento en aplicaciones web con Symfony2

Assetic en Symfony2

{% javascripts '@Bundle/Resources/public/js/*' filter=‘nombre_js' %} <script src="{{ asset_url }}"></script> {% endjavascripts %}

$ php app/console assetic:dump s3://bucket

Page 56: Rendimiento en aplicaciones web con Symfony2

Usa un CDN público

Ahorro de ancho de banda

El navegador probablemente tenga ya cacheadas las librerías comunes (pe. jquery)

Page 57: Rendimiento en aplicaciones web con Symfony2

Operaciones en tiempo real

El tiempo real no es necesario en la mayoría de los casos.

Envío de emailsProcesamiento de imágenesInvalidaciones de cache

Herramientas: RabbitMQ, Gearman.

Otras soluciones:Queue de SwitfmailerImplementar nuestra solución en memcached, redis..

Page 58: Rendimiento en aplicaciones web con Symfony2

Usa Html5 y CSS3

Page 59: Rendimiento en aplicaciones web con Symfony2

Async

Page 60: Rendimiento en aplicaciones web con Symfony2

Cache Manifest

<html lang="en" manifest=“ejemplo.manifest">

CACHE MANIFEST

CACHEclock.js clock.css

NETWORKno_se_cachea.php

Page 61: Rendimiento en aplicaciones web con Symfony2

Cache Manifest

El manifiesto se descarga en base a nuestras indicaciones en el HTTP Cache

..o forzándolo con JavaScript mediante el método window.applicationCache

La caché se invalida mediante una comparación byte-for-byte entre el archivo más reciente y el anterior.

Page 62: Rendimiento en aplicaciones web con Symfony2

No uses imágenes, usa CSS3Border-radius

Gradient

Text-shadow y Box-shadow

Canvas

Font-face

Page 63: Rendimiento en aplicaciones web con Symfony2

¿Preguntas?