ctors.net
Blog tvlooy

Symfony2 suddenly slow in Vagrant

Symfony2, Vagrant, Xdebug | April 21, 2014

Yesterday, I noticed that a Symfony2 project I work on became very slow in Vagrant. Requests took more than 15 seconds, which is unacceptable to get any work done on the project.

Timeline

The first thing I looked at was the Symfony2 timeline. It showed me that most of the time was spent by Symfony\Component\Security\Http\Firewall.

Symfony2 timeline

To validate if this was really the problem, I disabled the security component by putting these lines in comment:

In app/AppKernel.php:

public function registerBundles() { $bundles = array( new Symfony\Bundle\FrameworkBundle\FrameworkBundle(), // new Symfony\Bundle\SecurityBundle\SecurityBundle(), new Symfony\Bundle\TwigBundle\TwigBundle(), new Symfony\Bundle\MonologBundle\MonologBundle(), new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(), new Symfony\Bundle\AsseticBundle\AsseticBundle(), new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new JMS\AopBundle\JMSAopBundle(), new JMS\DiExtraBundle\JMSDiExtraBundle($this), // new JMS\SecurityExtraBundle\JMSSecurityExtraBundle(), ... );

In app/config/config.yml:

imports: - { resource: parameters.yml } # - { resource: security.yml }

At this point the application was fast again. This means I am on the right track.

The only thing that I could find on Google about performance problems related to the security component is that the security component makes a database connection and PDO does a name lookup when you connect on localhost instead of 127.0.0.1. This can cause a serious slowdown. But I was already connecting on the IP so this is not the same as my problem.

Profiling

The Symfony2 timeline didn't give me any details about what was going on in the firewall so I enabled Xdebug profiling to get a cachegrind output file. I added these two lines to my /etc/php5/mods-available/xdebug.ini file:

xdebug.profiler_enable=1 xdebug.profiler_output_dir=/vagrant/xdebug_dump

When I refreshed my application and openend the cachegrind file with KCachegrind it became clear that the problem was with SessionHandler->read:

KCachegrind file

Sessions

The default session storage handler in Symfony2 uses the filesystem. The sessions are located in /vagrant/app/cache/<environment>/sessions. The /vagrant path is on a shared folder (NFS in my case). I tried to move this path to the local filesystem but performance didn't get any better.

As the problem must be related to the filesystem, I enabled memcached as session storage. I got the setup instructions from Kévin Gomez:

# apt get install memcached php5-memcached

And restart your webserver.

In app/config/config.yml:

framework: session: handler_id: session.handler.memcached services: session.memcached: class: Memcached arguments: persistent_id: %session_memcached_prefix% calls: - [ addServer, [ %session_memcached_host%, %session_memcached_port% ]] session.handler.memcached: class: Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler arguments: [@session.memcached, { prefix: %session_memcached_prefix%, expiretime: %session_memcached_expire% }]

And in app/config/parameters.yml:

parameters: ... session_memcached_host: localhost session_memcached_port: 11211 session_memcached_prefix: sess session_memcached_expire: 3600

At this point my application was fast again (~200 ms). I'm still not sure what exactly causes the problem with the filesystem because I stopped investigating this after I had a workaround. Symfony2 uses the PHP SessionHandler behind the scenes so it's probably not related to just Symfony2.

Edit: John Kary pointed out on Twitter that Benjamin Eberlei also blogged about speeding up Symfony2 on Vagrant boxes.

I hope this article gives you an example to help you solve similar problems with your own PHP projects.