3 simple steps to boost performance of a PHP web application

Developers care about performance of their software. The problem is that they don’t usually have enough time for a proper optimisation. I would like to propose 3 relatively simple steps which won’t take much time and will improve a response time by at least 60%.

If you can not measure it, you can not improve it.

There are many great tools you can use for benchmarking and finding bottle necks but the tools are not everything. If you want your results to be representative you need to follow the best practice. Doing a good science is a big subject far behind scope of this post. I can recommend four simple points which used to work for me.

  • make sure there is no external traffic on a tested host
  • always run benchmarks from a different host
  • test form local network if possible
  • monitor load (top, htop or dmesg will do) during a test

Apache Benchmark

This is my favourite tool. It’s very easy to use and you can find it everywhere. I usually go for a concurrency set between 20 and 100 and a minimum 500 requests. For example:

$ ab -n500 -c20 "http://example.com/"

Look at average requests per second. Higher is better.

Apache jMeter

Very rubost testing tool. If you want to know more about it read my previous post.

XDebug

Well known PHP extension for debugging and profiling. Profiling takes lots of resources so it’s better to use it on demand (trigger with XDEBUG_PROFILE=1 attached to a URL).

xdebug.profiler_enable=0
xdebug.profiler_enable_trigger=1

Profiler will save cache grinds to /tmp/ directory. You can use webbgrid to analyse it. It’s a very useful tool and it doesn’t require any configuration.

1. PHP accelerator

It has been iterated many times and I’m not very innovative here. This is the starting point. You can use APC or Zend Optimizer Plus. Bare in mind that the default configuration is not the fastest one. Both extensions will be looking into file timestamp to make sure the cache is up to date. Code doesn’t change spontaneously in a production environment so you can disable that feature. It will eliminate the slow fstat() calls but you will have to restart all web servers after every release.

2. Autoload with the Composer

Composer is designed to manage dependencies but it can also help with the performance. Even if a code is cached by an accelerator your framework can still try to call functions like “is_readable” and loop through the include_path. I had this particular problem with Zend Framework 1.12.1. You can quickly fix it by editing the composer.json file.

"autoload": {
        "classmap": ["application/", "library/"]

}

Classmap is an array so you can keep adding new paths. Run the composer to re-generate the autoloader.

$ php composer.phar update

The classmap is going to be cached by the APC so autoloading should get much faster.

3. Serialiaze heavy objects

Instantiating an object with a complex relationship might take a significant amount of time. A good example is Zend Framework’s router. The router is a collection of routes. Every route is an instance of “Zend_Controller_Router_Route”. Instantiating a route means executing route’s constructor (for every instance). Certain routes might be storing (chaining) other routes which adds to the execution time. Not to mention a configuration is usually stored in an XML or INI file which needs to be opened and parsed in the first place.

If the component is hermetic and doesn’t affect the environment you can skip the execution process and cache serialized object. Our goal is performance so cache it in RAM. When the instance is needed acquire it from a cache and unserialize it. Obviously the unserialize function doesn’t come without a cost. There are some opinions it can be sometimes slower than the normal approach. It might also vary accross different PHP versions. You can easly measure it with the mirotime function:

microtime(true);

In the router example I got a 10% improvement just with that one change.

It’s not difficult to achieve a major performance improvement on a not optimised code. The key to success is to measure everything and apply the 80-20 rule (80% of problems are in the 20% of code). XDebug profiler will instantly highlight where are the problems. Remember to profile against your production config.

6 thoughts on “3 simple steps to boost performance of a PHP web application

  1. A easy way to improve your Zend 1 Routing is to (if possible) split your app in main index.php and load different, module-specific Application class with different set of routes. It also means that adding new routes will not slow down other parts of your app!

    APC is your friend – but be careful, and always benchmark your changes. Fetching objects from APC can take more then 5ms in some cases, it might be more then initialising PHP object with config array retrieved from APC.

    Also, it’s good to make sure that there are no `require_once` in your code, there is a lot of it in Zend 1. Even with `apc.stat = 0` require once will hit disk and stat the file!

    And finally, use XDebug regularly on your production environment! πŸ™‚

    Like

    1. Hello Wojtek, thank you for your comment. Breaking routes is a good idea but for this particular application hard to do. We need routes from various modules to build links with the URL helper.

      Could you please tell more about the issue with APC? 5ms is indeed very slow for pulling data form memory. Is it because of concurrency and locking or there are some other reasons?

      Like

      1. I guess that depends on settings. If you have profiling ON by default than you can expect trouble. If you have the remote debugging on there is a security issue. Appart fron that I wouldn’t think so but I have no data to support it so it’s only an assumption πŸ™‚

        Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s