Don’t rush on a more powerful server. A faster machine can surely help, but sometimes the slowness resides in a poorly written code, a request toward an external API or a database that does not scale well with the number of items it contains.
Caching is the key
I’ll tell you a secret: most of today’s backends are slow by nature. We ask them too much. This is why a vast majority of websites cheat with caching. Some companies even build 2, 3, 4 levels of cache to support their slow code.
But caching has one drawback: it eliminates real time changes. Let’s say you configured your cache with a TTL (Time To Live) of 2 hours, then any change in a page can take up to 2 hours to go live. Find the good balance between your need for reactivity and the number of users visiting your pages.
The subject of server-side caching would deserve a full article, but for now I’ll list here a few solutions:
- Install a reverse proxy cache such as Nginx or Varnish (both free) on your server when most of your users are anonymous. The proxy will simply save the outputted HTML and send a copy of it in a fraction of time to the next user.
- Use a CDN (Content Delivery Network). It acts like a reverse proxy but you don’t install anything on your server, plus it is built with geographical proximity on top. Cloudflare is probably one of the cheapest (starting at $20 per month).
- For WordPress, the W3 Total Cache plugin is free but needs advanced skills. WP Rocket is much easier (but $49 per year). Both plugins can be combined with a CDN so you get 2 levels of cache. And they are good enough to clear the cache when an article is updated.
Let’s dive into the real problems
Sometimes, adding a cache is not a possibility. For example:
- if the information needs to stay minute-fresh,
- if page contents are personalized,
- if most of your users are logged in,
- if the shopping basket is handled server-side,
Then you have no other choice. You need to change things inside your application. Warning: it’s not for beginners. If you’re not familiar with your server technology, you’d better ask to an expert.
Profilers know everything
Roll up your sleeves, put your helmet on, we will now enter the machine!
A profiler is a tool that instrumentalizes your server language to track and measure almost everything. It will point you the slowest functions, components, database queries, external queries and point you some server settings done wrong.
The NewRelic profiler interface
If you have a test server and it’s as slow as the production server, go for this one to avoid disturbing your website. If you do it on the production server, don’t forget to disable the profiler when you’re done optimizing, because it adds itself a little bit of slowness.
The biggest player in this industry is probably NewRelic. It handles dozens of languages and can almost do anything. With its 30 days free trial, you can have the time to diagnose problems, fix them and check again.
The goal of this article is not to list and resolve the different problems you will discover, it could require a full encyclopedia. But at least you’ll have clues what to search for in Google!
Caching inside the application
Caching is not only useful on the final HTML file, it can also help accelerating the language. Examples:
- If every simple page load asks the database the total number of items in the shop or the total number of articles on the blog. Cache it to reduce the number of database requests.
- If your navigation menu is complex and generated with database requests, cache the outputed HTML.
- If your application often requests an external API for minute-fresh currency exchange rates, why not caching them, even for a minute?
Once you start caching, you can’t stop because it’s damn easy. If you don’t want to experiment the hell of debugging an application with too much caching, remember to create a “cache free” mode for development purpose, or at least a “clear all caches” button.
Last but not least, make sure your language-side cache is fast. Caching in a database is slow. In a file on the disk is 10 times faster. In the memory is 10 times faster than the disk. I personally like Memcached, simple and efficient, with connectors with almost every languages and frameworks.
Slowness related to user peaks
This subject will be treated in a different article. Here are some quick ideas in the meanwhile:
- Cache things, of course.
- Reduce the number of static requests that hit your origin server with the help of a properly configured proxy or CDN.
- Increase your number of servers with the help of some load balancing technology.
- Transform dynamic parts of your website into static ones. Many website use Ajax-based user sessions and e-commerce baskets for this reason.
- Use Load Testing to simulate peaks on your development server. Or during the night on your production server.