Symfony2 performance issues and improvements
Symfony2 performance issues and improvements
Vitaliy [email protected]
https://github.com/vitaliyberdylo
Symfony2 performance issues and improvements
WHAT is Performance
- Server response time
- Render response time
Symfony2 performance issues and improvements
Premature optimization
Symfony2 performance issues and improvements
Measure performance
Symfony2 performance issues and improvements
Measure serverside performance
Backend benchmarks:
- ab ApacheBanch- siege
Profiler:
- XHProf + XHGui- Blackfire
Enable the slow query log
Symfony2 performance issues and improvements
Measure client performance
Client benchmark:
- YSlow- PageSpeed
online:
https://gtmetrix.com/
http://www.webpagetest.org/
Symfony2 performance issues and improvements
Symfony book Performance
- Use a Byte Code Cache (e.g. APC)- Use Composer's Class Map Functionality- Caching the Autoloader with APC- Use Bootstrap Files
Symfony2 performance issues and improvements
Expensive service construction
- Be careful with listeners for kernel.request, kernel.controller, kernel.view and kernel.response events.
- Don't perform any work in the service constructor
- Minimize deep layers of dependencies
- Minimize injecting services into listeners
- Use lazy services
Symfony2 performance issues and improvements
kernel.request event issues
- Avoid calling a database or external services in listeners- Don’t forget check request type and skip listener run for sub-requests
- Avoid excessive usage of Internal Subrequests. Every sub-request will go through the HttpKernel event lifecycle.
use Symfony\Component\HttpKernel\Event\GetResponseEvent;// ...
public function onKernelRequest(GetResponseEvent $event){ if (!$event->isMasterRequest()) { // don't do anything if it's not the master request return; }
// ...}
Symfony2 performance issues and improvements
User don’t need wait
Symfony2 performance issues and improvements
Do blocking work in the background
Symfony2 performance issues and improvements
Doctrine best practice- Constrain relationships as much as possible. Avoid bidirectional associations if possible
- Avoid composite keys
- Use lifecycle events judiciously
-Make $em->clear() in batches$batchSize = 20;for ($i = 1; $i <= 10000; ++$i) { $user = new User; $user->setStatus('user'); $user->setUsername('user' . $i); $user->setName('Mr.Smith-' . $i); $em->persist($user); if (($i % $batchSize) === 0) { $em->flush(); $em->clear(); // Detaches all objects from Doctrine! }}$em->flush(); //Persist objects that did not make up an entire batch$em->clear();
Symfony2 performance issues and improvements
Enable doctrine cache
doctrine: orm: metadata_cache_driver: apc result_cache_driver: apc query_cache_driver: apc
Symfony2 performance issues and improvements
Enable doctrine cache
You can use your own service:
doctrine: orm: metadata_cache_driver: apc result_cache_driver: apc query_cache_driver: apc
doctrine: orm: metadata_cache_driver: type: service id: acme.demo.doctrine.cache.mycache // ...
Symfony2 performance issues and improvements
Custom caching service
<?php
namespace Acme\DemoBundle\Doctrine\Cache;
use Doctrine\Common\Cache\CacheProvider
class MyCache extends CacheProvider{ protected function doFetch($id) {}
protected function doContains($id) {} protected function doSave($id, $data, $lifeTime = 0) {} protected function doDelete($id) {} protected function doFlush() {} protected function doGetStats() {}}
Symfony2 performance issues and improvements
Caching in action/*** Get all articles with best rank* @return array*/public function findBestArticles(){ $query = $this->createQueryBuilder('article') ->select('article.title, article.description, article.published') ->where('article:rank = :rank') ->orderBy('article.published') ->setParameter('rank', 5) ->getQuery(); $query->useResultCache( true, 3600, __METHOD__ . serialize($query->getParameters()) ); $query->useQueryCache(true); return $query->getArrayResult();}
Symfony2 performance issues and improvements
Beware of lazy loading
Symfony2 performance issues and improvements
Beware of lazy loading Beware of lazy loading when querying entities with associations
{% for article in articles %} <article> <h2>{{ article.title }}</h2> <p>Author: {{ article.author.firstName }} {{ article.author.lastName }}</p> <p>{{ article.text }}</p> </article>{% endfor %}
Symfony2 performance issues and improvements
Beware of lazy loading Beware of lazy loading when querying entities with associations
Apparent solution:
{% for article in articles %} <article> <h2>{{ article.title }}</h2> <p>Author: {{ article.author.firstName }} {{ article.author.lastName }}</p> <p>{{ article.text }}</p> </article>{% endfor %}
$articles = $this->getDoctrine()->getRepository('AcmeDemoBundle:Article')->findAll();
Symfony2 performance issues and improvements
Beware of lazy loading Right solution:
// src/Acme/DemoBundle/Entity/Repository/ArticleRepository
public function findAllWithAuthors(){ $qb = $this->createQueryBuilder('article'); $qb->addSelect('author') ->innerJoin('article.author', 'author');
return $qb->getQuery()->getResult();}
Symfony2 performance issues and improvements
Don't use hydration without needs
Doctrine ORM, like most ORMs, is performing a process called Hydration when converting database results into objects.
With hydration:
Without hydration
$articles = $this->createQueryBuilder('article')->getQuery()->getResult();
$articles = $this->createQueryBuilder('article')->getQuery()->getResult(Query::HYDRATE_ARRAY);
$articles = $this->createQueryBuilder('article')->getQuery()->getArrayResult();
Symfony2 performance issues and improvements
Use Reference ProxiesWith get author query into DB:
Without query for getting author:
$author = $this->getDoctrine()->getManagerForClass('AcmeDemoBundle:Article')->getRepository('AcmeDemoBundle:Article')->find($authorId);
$article = new Article();$article->setAuthor($author);
$em = $this->getDoctrine()->getManagerForClass('AcmeDemoBundle:Article');
$article = new Article();$article->setAuthor($em->getReference('AcmeDemoBundle:Author', $authorId));
Symfony2 performance issues and improvements
Assets
- Merging and minifying assets with Assetic (YUI compressor)- CSS at top javascript at bottom- use sprites for images- encode small images into base64- run image optimizations on your images
Symfony2 performance issues and improvements
Use reverse proxy
Symfony2 performance issues and improvements
Bibliography● http://blog.hma-info.
de/content/stuff/Full_Stack_Web_Application_Performance_Tuning.pdf
● http://symfony.com/blog/push-it-to-the-limits-symfony2-for-high-performance-needs
● https://tideways.io/profiler/blog/5-ways-to-optimize-symfony-baseline-performance
● http://ocramius.github.io/blog/doctrine-orm-optimization-hydration
● http://labs.octivi.com/mastering-symfony2-performance-internals
● http://www.emanueleminotto.it/im-afraid-symfony-2-performances
● http://alexandre-salome.fr/media/sfpot-english.pdf
Symfony2 performance issues and improvements
Questions & Answers