Over the weekend, I was fortunate enough to be at this year's PHP UK Conference, in London. One of the highlights for me, as a Zend Framework developer and evangelist, was Gary Hockin's talk on maximising Zend Framework 2 performance.
Whether you're new to Zend Framework 2, or an old hand (can someone really say they're an old hand after such a short period of time?) the talk covered a range of tools, tips, and techniques for increasing application performance.
Like all efforts to increase application performance, the talk was based on not making changes without having clear benchmarks and metrics to work from.
Looking at the benchmark, Gary pointed out the key metrics to be aware of - these being:
- Failed Transactions
- Response Time
- Transaction Rate
A key takeaway here, was that Xdebug should never be enabled, let alone installed, on a production server; whereas XHProf can be, and is designed to be so.
From here, Gary covered six key areas for improving Zend Framework 2 application performance.
- Use Caching
- Use of the EdpSuperluminal Module, by Evan Courey
- Go Easy on the Event Manager
- Proper Routing Table Composition
- View Template Map Construction
- Other Best Practices
Key Takeaway: Another point Gary stressed, was that if you can cache, you likely always should. If you're not aware of an opcode cache yet, such as APC (< PHP 5.5) or OPCache in PHP 5.5 or higher, then you should learn about them, quickly.
Given the way that Zend Framework 2's designed, where magic is replaced with explicit configuration, you should put a lot of thought into caching; specifically config files, view template maps, and expensive storage calls, such as MySQL or PostgreSQL SQL queries. Do you need to read the configuration files on every request? Do they really change that often? Would your application be better off by caching them?
The EdpSuperluminal Module
Following on, you should consider using EdpSuperluminal. I'd not heard of it before, but now that I have, it sounds amazing. In short, it combines all of the classes, required for a request, into one file.
I know, for maintainability, we follow PSR-0 and have one class per/file. But for performance, that can be quite a drag.
So Evan wrote the module to determine all the classes required for a request and combines them into one. One file, one include, one filesystem stat, faster performance. I strongly encourage you to check it out.
Go Easy on the Event Manager
Do you use the Event Manager? I do. Consequently I was quite surprised to find out what a performance hog it can be. Gary didn't suggest not using it, rather use it with care, and don't just throw anything in to it.
Look at what you need, be judicious in your choice, and as always - measure.
Proper Routing Table Composition
Here's another interesting point I'd not thought of - the ordering of the routing table. Did you know that the ordering is especially important?
Did you know that the most important route(s) should go at the bottom of the route stack, as it's a LIFO queue?
In the talk, just by adding an essential, often used route at the bottom, the route matching time dropped from 267,004μs to 135μs. That's damn incredible! So pay careful attention to how you order yours.
View Template Map Construction
As with the routing table, a view template map can be a very handy tool to have, especially if you have a view intensive application like I've been building of late.
If you're not familiar with a view template map, it tells the view renderer where to find the templates and view files it needs. This then saves lookup times, and when cached, saves even more time.
It can be a bit annoying to maintain, but then you should be able to script it away as well. Quoting Gary's slides, he reduce template resolution time from 153,445μs down to 60μs.
Other Best Practices
The talk then finished up with some performance savings which require no code whatsoever, but can be vital.
Do you have a favicon, Apple touch icons, robots.txt or a crossdomain.xml? and various other files? No, then be aware that clients (bots, mobile browsers etc) will still make requests for them.
When they're not found, a dispatch request will be made, resulting in a 404. So, for little to no effort, you can eliminate these requests, just by having the files there.
Another point to mention - closures in module.config.php. Don't do it. But that's a rather loaded statement. The reason why is that these can't be cached. So by enabling caching, you can potentially decrease performance.
But the flip side of this is maintainability. Do you need to cache everything? Is it essential? Do you need that last ounce of performance improvement?
Or is long-term maintainability more important. Have a think about it and make your own decision. But it's worth noting that closures, whilst handy, aren't performance friendly, at least in this case.
Gary's talk clearly showed that he has a lot of experience using Zend Framework 2. That, along with discussions we had between sessions, gave me loads of insights into using it better; I'll write about these in future posts.
By going through the talk slides, whether you're a beginner or more experienced developer, you'll learn loads about improving your Zend Framework 2 application's performance.
Remember, like all performance analysis, gut feelings don't belong. Before you make any changes, analyse. Then, based on the results of the analysis, make changes and analyse again.
Where you at the talk too? What did you think? Have you read the slides? What did you learn? Share your thoughts in the comments.