por qué symfony2 es tan rápido

38

Upload: carlos-granados

Post on 05-Dec-2014

3.098 views

Category:

Technology


1 download

DESCRIPTION

Mi charla en deSymfony 2013 explicando la cache de aplicaciones de Symfony que es uno de los elementos que más contribuyen a su velocidad.

TRANSCRIPT

Page 1: Por qué Symfony2 es tan rápido
Page 2: Por qué Symfony2 es tan rápido
Page 3: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Carlos Granados

Page 4: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Page 5: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Page 6: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Page 7: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

• Crear el Kernel y leer la petición• Leer configuración• Compilar y cargar el contenedor

de dependencias• Aplicar la configuración de

seguridad• Leer todas las rutas definidas• Decidir qué ruta aplicar• Ejecutar al controlador apropiado• Leer la configuración de las

entidades • Conectarse con la base de datos• Consultar la base de datos

• Convertir los resultados de la base de datos en entidades

• Construir las rutas que podamos necesitar

• Encontrar qué plantilla twig usar• Compilar la plantilla twig• Ejecutar la plantilla twig• Convertir el resultado de la

plantilla twig en una respuesta• Devolver esa respuesta al cliente• Autocargar todas las clases

implicadas

¿Qué hace Symfony cuando recibe una petición?

Page 8: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

¿Para cuándo dice que lo quiere?

Page 9: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

• Crear el Kernel y leer la petición• Leer configuración• Compilar y cargar el contenedor

de dependencias• Aplicar la configuración de

seguridad• Leer todas las rutas definidas• Decidir qué ruta aplicar• Ejecutar el controlador apropiado• Leer la configuración de las

entidades • Conectarse con la base de datos• Consultar la base de datos

• Convertir los resultados de la base de datos en entidades

• Construir las rutas que podamos necesitar

• Encontrar qué plantilla twig usar• Compilar la plantilla twig• Ejecutar la plantilla twig• Convertir el resultado de la

plantilla twig en una respuesta• Devolver esa respuesta al cliente• Autocargar todas las clases

implicadas

Muchos de estos procesos están cacheados

Page 10: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

No hablamos del caché HTTP

“La mejor petición es aquella que nunca llega a nuestro servidor”

Page 11: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Hablamos del caché de aplicación

app/cache

Page 12: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

app.php

Entornos y depuración

$kernel = new AppKernel('prod', false);

app_dev.php

$kernel = new AppKernel(‘dev', true);

Entorno debug

Page 13: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

config_dev.ph

web_profiler: toolbar: true

El entorno se usa para saber qué fichero de configuración usar

config_prod.ph

web_profiler: toolbar: false

Y también qué subdirectorio de app/cache utilizar

app/cache/prodapp/cache/dev

Page 14: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

El valor de debug es el que realmente distingue un entorno de depuración de uno de producción

%kernel.debug%

- Si se muestran los errores o no (en Symfony 2.3 está separado)

- Si se actualiza la caché en cada ejecución

Page 15: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Normalmente ‘prod’ = no debug y ‘dev’=debug

Pero NO tiene por qué ser así

Podemos, por ejemplo, crear un ‘app_staging.php’ con la configuración del entorno de producción pero con debug=true

$kernel = new AppKernel('prod', true);

Page 16: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

APC

“Sin APC Symfony no sería posible”

Page 17: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

APC: evitar que compruebe si tiene que recompilar ficheros

apc.stat=0 en php.ini

Al subir nuevo código hay que vaciar el caché APC:

• Reiniciar el servidor• Crear un script que borre esta caché y

ejecutarlo (con una llamada http)

Page 18: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Autoload: como encuentra las clases el autoloader

if (isset($this->prefixes[$first])) { foreach ($this->prefixes[$first] as $prefix => $dirs) {   if (0 === strpos($class, $prefix)) {     foreach ($dirs as $dir) {       if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {         return $dir . DIRECTORY_SEPARATOR . $classPath;        }      }    }  }}

vendor/composer/ClassLoader.php

Page 19: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Autoload: crear un classmap con Composer

php composer.phar dump-autoload --optimize

vendor/composer/autoload_classmap.php

…'Acme\\DemoBundle\\AcmeDemoBundle' => $baseDir . '/src/Acme/DemoBundle/AcmeDemoBundle.php','Acme\\DemoBundle\\Controller\\DemoController' => $baseDir . '/src/Acme/DemoBundle/Controller/DemoController.php','Acme\\DemoBundle\\Controller\\SecuredController' => $baseDir . '/src/Acme/DemoBundle/Controller/SecuredController.php','Acme\\DemoBundle\\Controller\\WelcomeController' => $baseDir . '/src/Acme/DemoBundle/Controller/WelcomeController.php',…

Page 20: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Autoload: utilizar ApcClassLoader

web/app.php

// Use APC for autoloading to improve performance// Change 'sf2' by the prefix you want in order to prevent key conflict with another application $loader = new ApcClassLoader('sf2', $loader);$loader->register(true);

Page 21: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Bootstrap

app/bootstrap.php.cache

• Construido por Composer durante la instalación

• Se incluye en los front controllers• Contiene las clases básicas necesarias para

inicializar el entorno Symfony: ContainerAwareInterface, Container, Kernel, ClassCollectionLoader, ApcClassLoader, Bundle, ConfigCache, HttpKernel

Page 22: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Classes.php

app/cache/prod/classes.php

• Se construye a partir de un mapa de clases: classes.map

• En modo debug se comprueba cada clase del mapa para ver si ha cambiado y si es así se reconstruye el fichero classes.php

• En modo no debug sólo se construye classes.php si no existe

Page 23: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Classes.map

app/cache/prod/classes.map

Contiene las clases que cada bundle decida incluir para optimizar

$this->addClassesToCompile(array(            'Twig_Environment',            'Twig_Extension',            'Twig_Extension_Core',            'Twig_Extension_Escaper',            'Twig_Extension_Optimizer',            'Twig_LoaderInterface',            'Twig_Markup',            'Twig_Template',        ));

Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php

Page 24: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Classes.map

app/cache/prod/classes.map

Podemos añadir clases de nuestros bundles

public function load(array $configs, ContainerBuilder $container){

…$this->addClassesToCompile(array(

     'Acme\DemoBundle\Twig\Extension\DemoExtension',    'Acme\DemoBundle\Twig\EventListener\

ControllerListener', ));

}

Acme/DemoBundle/DependencyInjection/AcmeDemoExtension.php

Page 25: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Contenedor de dependencias

app/cache/prod/appProdProjectContainer.php

• Lo construye el compilador del contenedor de dependencias

• En modo debug se comprueba un fichero appDevDebugProjectContainer.php.meta generado al compilar. Si alguna de las clases incluidas ha cambiado, regeneramos el contenedor

• En modo no debug sólo se construye el contenedor si no existe

Page 26: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Contenedor de dependencias

…/** * Gets the 'doctrine' service. * * This service is shared. * This method always returns the same instance of the service. * * @return Doctrine\Bundle\DoctrineBundle\Registry A Doctrine\Bundle\DoctrineBundle\Registry instance. */protected function getDoctrineService(){    return $this->services['doctrine'] = new \Doctrine\Bundle\DoctrineBundle\Registry($this, array(

'default' => 'doctrine.dbal.default_connection'), array('default' => 'doctrine.orm.default_entity_manager'),'default', 'default');

}…

app/cache/prod/appProdProjectContainer.php

Page 27: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Enrutador

app/cache/prod/appProdUrlMatcher.php

• Lo construye el componente de enrutación• En modo debug se comprueba un fichero

appDevUrlMatcher.php.meta generado por el router. Si alguno de los recursos (ficheros yml, controladores, etc…) incluidos ha cambiado, regeneramos el enrutador

• En modo no debug sólo se construye el enrutador si no existe

Page 28: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

if (0 === strpos($pathinfo, '/_')) {    // _wdt    if (0 === strpos($pathinfo, '/_wdt') && preg_match('#^/_wdt/(?P<token>[^/]++)$#s', $pathinfo, $matches)) {     return $this->mergeDefaults(array_replace($matches, array('_route' => '_wdt')), array ('_controller'

=>'web_profiler.controller.profiler:toolbarAction',));    }

app/cache/prod/appProdUrlMatcher.php

Enrutador

Es importante que las rutas más usadas estén al principio:

• Definirlas antes en los ficheros yml• Definirlas antes en los controladores si usamos anotaciones

Page 29: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

# app/config/config_prod.ymlparameters:  router.options.matcher.cache_class: ~ # disable router cache  router.options.matcher_class: Symfony\Component\Routing\Matcher\ApacheUrlMatcher

Usar el Enrutador de Apache

$ php app/console router:dump-apache -e=prod --no-debug

# skip "real" requestsRewriteCond %{REQUEST_FILENAME} -fRewriteRule .* - [QSA,L] # helloRewriteCond %{REQUEST_URI} ^/hello/([^/]+?)$RewriteRule .* app.php [QSA,L,E=_ROUTING__route:hello,E=_ROUTING_name:%1,E=_ROUTING__controller:AcmeDemoBundle\:Demo\:hello]

// web/app.php…use Symfony\Component\HttpFoundation\ApacheRequest;…$kernel->handle(ApacheRequest::createFromGlobals())->send();

Page 30: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

static private $declaredRoutes = array(    

'_demo' => array (  0 =>   array (  ),  1 =>   array (    '_controller' => 'Acme\\DemoBundle\\Controller\\DemoController::indexAction',  ),  2 =>   array (  ),  3 =>   array (    0 =>     array (      0 => 'text',      1 => '/demo/',    ),  ),  4 =>   array (  ),),    

'_demo_hello' => array (  0 =>   array (    0 => 'name',  ),  1 =>   array (    '_controller' => 'Acme\\DemoBundle\\Controller\\DemoController::helloAction',  ),  2 =>   array (  ),  3 =>   array (    0 =>     array (      0 => 'variable',      1 => '/',      2 => '[^/]++',      3 => 'name',    ),    1 =>     array (      0 => 'text',      1 => '/demo/hello',    ),  ),  4 =>   array (  ),),…

app/cache/prod/appProdUrlGenerator.php

Enrutador: generador de rutas

Page 31: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Plantillas

app/cache/prod/templates.php

• Lo construye un caché warmer del componente de plantillas

• En modo debug no se construye• Hay un directorio app/cache/prod/twig donde

están las plantillas compiladas. En modo no debug sólo se genera cada plantilla si no existe.

• La estructura del directorio Twig es un poco rara. Puede ser dificil encontrar la plantilla compilada. Usar una búsqueda global por ficheros con el nombre de la plantilla.

Page 32: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

return array (…    'AcmeDemoBundle:Demo:index.html.twig' => '/Z:/stack/src/Acme/DemoBundle/Resources/views/Demo/index.html.twig',  'AcmeDemoBundle:Demo:hello.html.twig' => '/Z:/stack/src/Acme/DemoBundle/Resources/views/Demo/hello.html.twig',  '::base.html.twig' =>

'/Z:/stack/app/Resources/views/base.html.twig',);

app/cache/prod/templates.phpPlantillas

// line 5public function block_content($context, array $blocks = array()){    // line 6    echo "    <h1>Hello ";    echo twig_escape_filter($this->env, (isset($context["name"]) ?

$context["name"] : null), "html", null, true);    echo "!</h1>";}

Page 33: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Otros elementos en el cache

• Anotaciones• Traducciones• Assetic• Doctrine• Etc…

Muchos de estos elementos se crean con un cache warmer.

Page 34: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface

Crear un cache warmer para tu bundle

public function warmUp($cacheDir){    // Creamos el contenido a guardar el el cache    $content = ...;     // Lo guardamos en el cache    $this->writeCacheFile($cacheDir.'/filename.php', $content);}

public function warmUp($cacheDir); public function isOptional();

Symfony\Component\HttpKernel\CacheWarmer\CacheWarmer

Page 35: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

• Query cache• Metadata cache• Result cache

Cache de Doctrine

doctrine:    orm:        metadata_cache_driver: apc        query_cache_driver:            type: service            id: my_doctrine_common_cache_service        result_cache_driver:            type: memcache            host: localhost            port: 11211            instance_class: Memcache… 

Page 36: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

• Hacer un cache:clear (con warmup) cada vez que instalemos en producción

• apc.stat=0 en php.ini

• Crear un classmap con Composer

• Activar ApcClassLoader

• Listar las clases que queremos añadir a classes.map en nuestro bundle

• Ordenar las rutas para que las más usadas aparezcan antes

• Usar el enrutador de Apache

• Crear cache warmers con ficheros inicializados por nuestro bundle

Conclusiones

Page 37: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

Page 38: Por qué Symfony2 es tan rápido

Por qué Symfony2 es tan rápido Carlos Granados

¡¡Gracias!!

[email protected]• @carlos_granados• http://es.linkedin.com/in/carlosgranados

¿Preguntas?

• https://joind.in/8852