por qué symfony2 es tan rápido

Post on 05-Dec-2014

3.101 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

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

Por qué Symfony2 es tan rápido Carlos Granados

Carlos Granados

Por qué Symfony2 es tan rápido Carlos Granados

Por qué Symfony2 es tan rápido Carlos Granados

Por qué Symfony2 es tan rápido Carlos Granados

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?

Por qué Symfony2 es tan rápido Carlos Granados

¿Para cuándo dice que lo quiere?

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

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”

Por qué Symfony2 es tan rápido Carlos Granados

Hablamos del caché de aplicación

app/cache

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

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

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

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);

Por qué Symfony2 es tan rápido Carlos Granados

APC

“Sin APC Symfony no sería posible”

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)

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

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',…

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);

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

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

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

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

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

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

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

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

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();

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

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.

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>";}

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.

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

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… 

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

Por qué Symfony2 es tan rápido Carlos Granados

Por qué Symfony2 es tan rápido Carlos Granados

¡¡Gracias!!

• carlos@planetapluton.com• @carlos_granados• http://es.linkedin.com/in/carlosgranados

¿Preguntas?

• https://joind.in/8852

top related