My ZF2 application seems to be extremely slow when more than 3 users are using it at the same time.
I profile my code with xdebug and webgrind and non of my function
All of the above and using some kind of opcode caching like APC / Opcache it will speed things up. But yes ZF 2 seems to be very slow unfortunately even more slow then ZF 1 :(
Also the module config cache speeds things up, you cannot have any closures though to make this working ;)
http://hounddog.github.io/blog/performance-in-zend-framework-2/
the ZF2 classmap generator will give you a big boost if you have a large project:
http://framework.zend.com/manual/2.0/en/modules/zend.loader.classmap-generator.html
Alternatively if you are using composer (you should do) then you can use composer to generate the classmap for all your modules and dependdencies too which is even better:
php composer.phar install --optimize-autoloader
php composer.phar update --optimize-autoloader
First of all to speedup your zf2 application you should use ZendOptimizerPlus. The vast part of execution time used to read and precompile php code. Typical ZF2 app has a lot of files, so it takes a lot of time to handle them.
ZendOp+ saves bytecode of your php application in shared memory, so server doesn't read a lot of files and doesn't parse it every request. ZendOp+ will be at php5.5 by default, so it is useful to know it and to use it.
Benchmarks gives 9x increase in performance for simple framework applications (symfony2 tests - http://www.ricardclau.com/2013/03/apc-vs-zend-optimizer-benchmarks-with-symfony2/ ).
I use it for my zf2 + doctrine2 + zfcUser application. Memcached is used for doctrine2 purposes, it gives only about 5% performance increase. So with ZendOp+ I got 6x increase (0.2 -> 0.03s) for simple pages and 3x increase (0.2 - 0.06) for complex pages with a lot of forms, entities, views. If I use classmap generator, I will update the answer.
Another issue is to use nginx + php-fpm rather than apache2+module. It saves server resources.
There's few very simple steps to achieve a faster application. There's three things that can always be considered.
ZF2 Performance QuickTipp #1 - ViewModels Always manually assign the fully qualified script to render. This will increase the performance a little. It's done like this:
public function someAction()
{
$viewModel = new ViewModel();
$viewModel->setTemplate('MODULE / CONTROLLER / ACTION.phtml');
// In this given example: $viewModel->setTemplate('foo/bar/some.phtml');
// Do some other Controller-logic as used to
return $viewModel->setVariables(array(
//key-value-paired view-variables
));
}
ZF2 Performance QuickTipp #2 - Classmap Autoloading This probably is one of the most important parts of speeding up your application. Personally i've seen an increase in LoadingTimes by up to 40%. Implementing this is pretty simple:
class Module
{
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
);
}
}
The autoload_classmap.php
then is a simple array of 'FQ-CLASSNAME' => 'FQ-FILEPATH'
. This can be automatted pretty easily using the classmap_generator-utility of ZF2
ZF2 Performance QuickTipp #3 - Keep Module.php light!
Sadly this is a post i haven't come around to write yet. The Module.php
is a file that is loaded on every single request. Lots of people forget about this and write lots and lots of factories inside them. At one point, ZfcUser-Module.php was an example of what not to do. Closures or anonymous functions are executed on every request, too. This is quite a bit of work to be done if there's too many of them over the whole project. A better approach would be to simply write Factory-Classes. ZfcUser later updated Module.php to use this strategy.
And that's pretty much all the easy stuff one can do (that i know of - i dont know much! :D). However what sounds interesting is that starting to use 3 users your application runs slow. To my experience this has nothing to do with the scripts itself but is rather an server issue. Is this from a Staging Machine or locally?
If you are using Doctrine, don't forget to add a cache for annotations. This drastically improve performance (when I activate this cache I divide nearly by two the loading time). If you are using DoctrineORMModule:
'doctrine' => array(
'driver' => array(
'cache' => array(
'class' => 'Doctrine\Common\Cache\ApcCache'
),
'configuration' => array(
'orm_default' => array(
'metadata_cache' => 'apc',
'query_cache' => 'apc',
'result_cache' => 'apc'
)
),
)
)
However, it's quite inconvenient while developing because you must clear the cache whenever your mapping change.