| Sunday, 16 October 2011
I recently stumbled on a post about optimizing a site for a sudden spike of traffic. Try as I might, I can't find it to link to it here. However, it got me thinking about optimizing this site a bit. It's often just little things that can be adding the milliseconds to your page load time, and low hanging fruit is something I find very tasty. While my results aren't necessarily much to boast about, here is what I found:
To test where the waiting time was coming from, I started with Firebug. YSlow showed me a few issues, such as a large number of CSS and JS includes on my pages, no CSS sprites, and no Content Delivery Network (CDN). However, I wasn't about to sprite all my images, and I also wasn't about to pull all my CSS and JS into a single file each. These kinda need to be separate as they are mainly different libraries like jQuery and jQueryUI. Pulling them all into one is too much effort for now, so I stayed away from that.
One thing I did discover, was that my assets were being returned much more quickly than the requested page. This is no great achievement, all it means is that I didn't have ridiculously large images. Good to know, but next I needed to figure out why the page was rendering so slowly. I figured it was probably something to do with DB queries, so I headed over to the PHP to check it out. I started by running a bunch of microtime() calls in index.php, to segment the setup and actual execution of the controller being called. I found that the setup of all the classes and config was the smaller portion of the time cost. The call to the controller itself was slow. Still no surprises.
I had a look at the controller being called. I was testing on my home page, so it was the common/home controller. This is a fairly simple file. It doesn't do much other than set the page title and meta description, call in its children (modules, etc), and render its template. I only have the slideshow module, latest products, and SeoTags modules running on my homepage, and I could already pretty much see the extent of the damage done by the slideshow module, so I looked closer at the code of the other two. I added caching to the SeoTags module, which didn't change much. It shaved a few millis off the time. It was the latest products module that gave me the best gain. I added caching to the getProduct function in the catalog/product model, and immediately - with only 6 products being pulled in to my home page - improved page speed by 50%. That's impressive.
I am not sure if OpenCart has neglected caching somewhat in recent versions, or if there's a method to the way it's happening, but there are many DB queries that simply do not cache at all. Adding caching to DB queries was the first low hanging fruit I discovered, and it gave me great results. On product pages, the getProduct function caching saved me about 66% of my page load time, cutting it down from around 600ms to 200ms. It is important to make sure the cache files are deleted at the right time - ie: when a review is added, a product updated, etc - but I think it is worth caching anywhere possible. Particularly with shared hosts, where DBs are a common bottleneck, caching may just give you some great performance improvements.
Caching may not be ideal if you have a large inventory. The OpenCart caching mechanism stores DB queries as files, meaning each unique query is a new file on your webserver. HostJars has less than 30 products, and won't be hitting 50 any time soon. We also don't have any distinct customer groups and only support a single language and store. This means we will have at most 30 cached product query files, which won't get out of hand. If we had thousands of products, multi store or language and many customer groups, I'd think twice about caching. After thinking twice, I'd probably still do it!.
The next thing I think would be helpful, would be caching at the module level. Caching a whole module, rather than executing its controller and rendering it each time would be a reasonable saving, particularly on pages with many modules enabled. OpenCart doesn't support caching of whole controller outputs as easily as DB queries, so this change may require a little more effort in the meantime. I think it may yield significant improvements.
If you've made any performance gains on your OpenCart store, with these or other methods, I'd be keen to hear about them. Just leave a comment below.
Phone Us: (408) 675-5884