eCommerce is losing the performance battle, folks.
The average load time of an eCommerce website (based on Alexa Top 100) has risen from 6.79 seconds to 7.72 seconds in just under 18 months.
Websites are becoming increasingly rich in content and imagery, and responsive design is becoming increasingly popular, although it comes with a larger resource overhead than a regular eCommerce website.
Bad news is that according to statistics, 57% of people will abandoned a page if it takes more than 3 seconds to load, and every 0.1 second decrease in load time results in an increase of conversions by 2%.
Magento is a ‘heavy’ eCommerce CMS system, with thousands of files making up its standard codebase. Originally, the Magento engineers were tasked with making the most customisable, flexible eCommerce system available and left addressing performance for later. In other words: Magento’s core was never built to be fast.
However, performance can be improved by configuration in both Magento admin and server settings. Often the best way to look at it is 'every little helps', as saving 10s of milliseconds here and there will add up in the long run.
Here are some of the main ways to help speed up Magento just within the admin:
- Turn on caching
- Enable JS/CSS Merging
- Turn on flat category/product data
- Disable logging
- Clean up unused URL rewrites
- Use a separate subdomain for JS, Media & Skin Base URL’s (store scope only).
Here are some server side additions:
- Install a backend cache (Redis, Memcache) to store all caches
- Install a backend cache (Redis, Memcache) to store all sessions
- Optimize MySql settings
- Install Pagespeed to help reduce request load to the server
- Install Varnish to sit in front of the webserver to shield it from requests
The last one on that list, Varnish, is technically an HTTP Accelerator, designed to serve static content.
The idea is that it sits in front of the web server and shields it from repetitive requests that are using up CPU and memory resources, unnecessarily. This means that not only are we returning cacheable pages fast, we also free up server resources for non-cacheable pages. Simple but effective.
The homepage of a site is requested by nearly every user that visits and it always returns almost identical content, so why not cache the entire page and return it to the user?
- Normal Page load 6 secs
- Full Page Cache load 3-5 secs
- Varnish Page load 1-2 secs
Obviously when Varnish returns an entire page, it is not aware of any dynamic areas of the page, such as basket items or recommended products. These need to be handled by Ajax requests or ESI’s which requires additional development and configuration.
All browsers limit the number of concurrent connections per domain they allow - Internet Explorer 7 allows 2 and Firefox allows up to 8.
We can get around this problem by using 'domain sharding' where we use a number of subdomains to serve assets - multiplying the number of concurrent connections by the number of subdomains used.
Some of the world's top websites such as YouTube and Yahoo! use domain sharding, e.g. i1.ytimg.com, i2.ytimg.com, i3.ytimg.com. Although due to the time taken to perform a DNS lookup, the general recommendation is that sharding should happen over at least 2 subdomains but no more than 4, since performance begins to degrade after this point.
In Magento you can provide a separate base url for JS files, media files and skin files. So we can set these URL’s to have separate domains such as http://skin.magentosite.com/skin/ or http://media.magentosite.com/media/. This can reduce the browser loading time significantly.
You can also address your code quality for efficiency.
If anything within code prevents the full DOM from being loaded and stylesheets being downloaded and applied, it will give the perceived impression that the website is slow.
Even if you have a super-fast server and configured perfectly with caching etc. it could still take time for the browser to display the page.
We can combat this by improving the code quality and source order, so here are a few things to consider.
- Where possible stop JS being run until the page has finished loading
- Write efficient CSS
- Reference elements via ID where possible
- #some_id = good
- img#some_id = terrible
- .image#some_id = redundant
- .div #some_id = also redundant
- Avoid heavy graphical processes such as 3d translations
- Selectors are read from right to left, so being more specific further down the selector is generally more efficient
- Avoid loops within loops
- Use local variables rather than array keys or object values.
- Manage scopes and store out of scope values as local variables
- Efficient looping by reversing the iterations
Finally, you can leverage browser caching, where your browser stores content and assets previously requested from a website.
By marking these files to be cached by the browser, we are saving HTTP requests and load time. If we could even cache 25% of asset files, we not only gain 25% of the load time, but we also save time performing the DNS lookup for the domain these files are served from.
The downsides to this would be if the content within cached files changed, the browser wouldn't identify it and load the old cached version of the website. The only way around this is to rename the file, ideally with some kind of timestamp.
Browser caching is configured by the server which can set which types of files can be cached and for how long - it is up to the browser exactly how it implements these requests.