Using Zend Framework for Highload Projects

Using Zend Framework for highload projects

For what I have seen, the definitive defense of Zend Framework performance and recommendations for performance optimization comes from Padraic Brady at:

PHP Framework Benchmarks: Entertaining But Ultimately Useless

In particular, note his four recommendations for performance optimization:

  1. Don't use Zend_Application. While Zend_App is great for creating consistent complex bootstraps within a standardised structure, it doesn't come without a significant performance hit to baseline performance. A more direct bootstrap (typical of ZF until Zend_App arrived) is far faster and can also be done without configuration files.

  2. Skip using the ViewRenderer plugin. Without the ViewRenderer, you need to manually configure Zend_View and add render() calls to Controllers. This is actually very simple to do and is fairly fast - fast was never really part of the ViewRenderer's genetics.

  3. Use autoloading. Strip require_once calls from the framework library so unneeded files are ignored. Replace uses of Zend_Loader_Autoloader with a not-so-crazy autoloader function. In fact, pray Zend_Loader is never used - it does a lot of file ops that, to date, have never been explained to me as having any value.

  4. Preload everything (Symfony 2 Preview does!). It buys you some performance cookies and equalises the speed baseline. Using a simple preload script is not that hard.


Zend Framework optimization - preload everything?

Preloading means taking the classes used in almost every request (like Bootstrap, Zend_Config, Zend_Registry, Zend_Db, ... depending on your project) and putting them all in one file you load at first instead of doing lazy loading (loading only when needed).

As Zend does not do it by itself, it can be rough when you want to update it. I would try the following before editing Zend's code:

There is the performance guide from Zend:
http://framework.zend.com/manual/en/performance.html

To help speedup your application, you should consider using APC :
http://php.net/manual/en/book.apc.php

Finally, you could cache computed results with Memcached:
http://php.net/manual/en/book.memcached.php

Speeding up your application must be done on multiple levels to be the most efficient.

Optimising the Zend Framework

My tips for faster ZF (try from top to bottom):

Optimize include path

  • zend path first
  • models next
  • rest at the end

Use PHP 5.5 with OPCache enabled [NEW]

  • I can't stress this enough
  • gains around 50%

Cache table metadata

  • should be cached even if no other caching is needed
  • one of our application performance improved by ~30% on Oracle server ;)

Favour viewHelpers over using action() view helper

  • create view helper that access your model
  • or pass only the data from model and format them with view helpers

Use classmap autoloader

  • since ZF1.11
  • preferably with stripped require_once calls

Minimize path stacks

  • there are a lot of path stacks in ZF

    • form elements
    • view helpers
    • action helpers
  • each path stack lookup means stat call = performance loss
  • default classes are more and more expensive with every path on stack

Strip require_once

  • strip require_once from Zend's classes in favour of autoloading using find & sed

Favour render() over partial() view helper

  • no new view instance is created
  • you need to set variables outside the rendered view scope, inside the main view!
  • you can also replace partialLoop() with foreach + render()

Cache anything possible

  • small chunks that require lot of work and change seldomly (like dynamic menus)
  • use profiler to find low-hanging fruit

    • what you think is slow may not really be so slow
  • cache everything that can have cache set statically

    • see manual - Zend_Locale::setCache(), Zend_Currency::setCache(), Zend_Db_Table::setDefaultMetadataCache(), configs...

Never use view helper action() or action helper actionStack()

  • Never use them unless 100% needed - for example for complicated data output, but mind the performance loss they pose
  • They create whole new dispatch loop and are performance killers!

Disable viewRenderer

  • take care of view rendering yourself

Try my superlimunal plugin

  • it merges included classes to one long file to minimize stat calls
  • get if from GitHub

    • it's port from ZF2 version from EDP
    • but beware - it's not tested in production yet, use with care
  • measure performance gain

    • there was a loss for me on slow HDD and all ZF classes in it
    • try minimizing it with strip whitespace function

Server-side file minification

  • It makes sense for really big files - HDD is always the bottleneck
  • Even micro-optimization works fine sometimes

    • classmap with all ZF classes' paths is HUGE, striping whitespace and replacing long variables with $a and $b brought performance gain when having "dry" opcode cache and HDD under pressure.

Any opcode cache is of course a must have ;) (APC, ZendOptimizer, etc.)

Zend Framework project without using Zend_Application

I just threw this together:

https://gist.github.com/2822456

Reproduced below for completion. Not tested, just some ideas for how I think it generally (!) might work. Now that i have walked through it a bit, I have a greater appreciation for Zend_Application, its bootstrap classes, and its configurable/reusable application resources. ;-)

// Do your PHP settings like timezone, error reporting
// ..

// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/_zf/application'));

// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));

// Get autoloading in place
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
// Any additional configs to autoloader, like custom autoloaders

// Read config
$config = new Zend_Config_Ini(APPLICATION_PATH . '/configs/application.ini', APPLICATION_ENV);

// bootstrap resources manually:
// * create db adapter
// * create resource autoloaders with the mappings you need
// * etc

// Get the singleton front controller
$front = Zend_Controller_Front::getInstance();

// Set controller directory
$front->setControllerDirectory(APPLICATION_PATH . '/controllers');

// Or set module directory
$front->setModuleDirectory(APPLICATION_PATH . '/modules');

// Other front config, like throw exceptions, etc.
// ...
//
// Create a router
$router = new Zend_Controller_Router_Rewrite();

// Add routes to the router
$router->addRoute('myRoute', new Zend_Controller_Router_Route(array(
// your routing params
)));
// More routes...
// Alternatively, the routes can all be in an xml or ini file and you can add
// them all at once.

// Tell front to use our configured router
$front->setRouter($router);

// Add an plugins to your $front
$front->registerPlugin(new My_Plugin());
// other plugins...

// Dispatch the request
$front->dispatch();

There might be some View/ViewRenderer stuff to do, as well. But as noted in other places, the ViewRenderer incurs a non-trivial performance hit. If performance is the issue, then you'll want to disable the ViewRenderer and make your action controllers call their own rendering using $this->view->render('my/view-script.phtml')

When you call $front->dispatch(), the $request and $response objects will be created automatically. If you want to do something specific to them at bootstrap - like setting the charset in Content-Type header of the response - then you can create your request/response object yourself, do what you want to it, and then attach it to the front with $front->setResponse($response); Same for the request object.

Although I see that my example uses Zend_Loader_Autoloader and Zend_config_Ini which Padraic notes incur performance hits. The next step would be to address those by using arrays for config, stripping require_once calls from the framework, registering a different autoloader, etc, an exercise left for the reader... ;-)

Zend Framework performance (autoload)

I was surprised to find that this is the only question on the site tagged performance, autoload, php. What a better place than this to dispel the #1 autoload myth:

Modern, well-designed autoloaders won't break APC (or PHP 5.5's OPcache), and are not any worse for performance than require_once (except for the function call overhead, of course).

Why? Well, now we have spl_autoload_register, which lets you add multiple autoload handlers. This allows each third party library to ship it's own autoloader that knows how to load that library's files, and skip the rest.

For example, Zend Framework 1's Zend_Loader_Autoloader restricts itself to trying to load classes that start with a specific pseudo-namespace -- Zend_ (and anything else the user asks it to load). If it doesn't start with the desired pseudo-namespace, it simply returns and lets the next loader on the stack run. It also knows that it can find Zend_Foo_Bar_Baz in Zend/Foo/Bar/Baz.php, so it doesn't need to search the include path by hand. Like other modern framework autoloaders, it follows the the PSR-0 autoloading standard.

Any dependencies installed via composer also get automatically built namespaced autoloaders in the same way.

It's that include path scouring that makes poorly-designed autoloaders suck. You generally don't see these in modern PHP code. The intense filesystem stat calls that result from trying to find files are a frequent performance drag. Check out this presentation by PHP creator Rasmus Lerdorf, in which he increases the performance of Wordpress through benchmarking, profiling, and careful removal of slow operations like stat calls.

The require_once-everything-up-front from the olden days is is unnecessary when you're using modern libraries and don't have a sucky autoloader. It's only a major win when you disable apc.stat if you're using APC, or fiddling with OPcache's validate_, revalidate_, and enable_file_override INI options if you're using OPcache.

tl;dr: Unless you know that statting include files is your largest bottleneck, the Zend autoloader is just fine, and you don't need to resort to a require_once fest.

How to get week number from date with Zend Framework 2

You don't need the framework's featureset for this. Just the raw language.

date('W', $timestamp);

W: ISO-8601 week number of year

Note that W is uppercase. Lowecase w returns the day number of the week.

Zend Framework vs Drupal, or is the argument silly?

They are two different products altogether. Drupal is not a framework, it is a Content Management System. This allows for distributed publishing, workflow and much more. It can be extended through plugins to provide additional functionality.

Zend Framework is a web application framework. It gives a common set of tools, services and code that can be used to build a site. It does not give you a site unless you put these items to some use first.

Think of it this way:
If you wanted to build a Content Management System like Drupal from scratch, you would use a Web Application Framework like Zend Framework to shortcut a lot of the standard elements you would need such as session management, email, database abstraction layer etc.



Related Topics



Leave a reply



Submit