How quick do pages on your site load? How quick should they load? How do you make pages load quicker?
Why should you care?
The speed of pages loading on websites is often overlooked in web projects, and can be a major difference between two sites that otherwise look the same. Let's start with why you should care -- or rather, when you should care.
How fast should my Drupal site be, and why?
There is no universal answer to that question, but lots of generalities. The biggest question is, how motivated are your users to wait around? If they need the site to do their jobs, they might be willing -- although unhappy -- to wait around 30 or 40 seconds. But if your site is one option among many, and a primary sales tool, a site that slow will lose you tons of potential business. Search engines penalize sites that don't load within 10 seconds, but many quick browsers won't even wait that long -- if it takes longer than 3 or 4 seconds you might lose unmotivated surfers.
Do you care? How much are those surfers worth? If you have an ad-driven site, they might be a major source of your revenue, and that's critical. If your best customers are more patient, you might not care so much.
When we do a Drupal site assessment, we use a 1 - 5 scale based on what we think are substantial different tiers of performance. And these generally translate to how many potential visitors/users you have:
- If your site loads in under 1 second, you're doing really well. Your site feels quick, nimble, not laggy at all. Performance is probably not an issue you need to spend more time or money on, unless you're in an intense competitive situation where 1/10th of a second (or less) differences count -- and then be prepared to spend a lot more budget to get those diminishing returns.
- If your site loads in under 3 seconds, you're doing reasonably well. You're probably not losing site visitors due to having a slow site. There is room for improvement, but it's going to take some work to get there.
- If your site loads in 3 - 6 seconds, it's middle-of the-road for performance. You're probably only losing the people with serious attention-deficits, but there's definitely room for improvement, and this is an area you may want to consider putting some budget.
- If your site loads in 6 - 10 seconds, it's definitely on the slow side. If this is due to very large pages, you might especially be losing or frustrating some mobile users. This time frame is usual for processing-heavy web sites, e-commerce, custom portals, and other sites with a lot of content generated on the fly, and users who are already invested in what your site provides will stick around, but if you don't have a captive market you should at least get your landing pages responding quickly.
- If your site takes longer than 10 seconds to load, you have a real performance problem, and you're almost certainly suffering due to that. You need to take action, unless your users have no choice but to wait around on your system -- and then you should take action anyway to avoid revolt!
How do you measure Performance?
We do a very quick benchmark using the built-in Firefox network profile tool. If you have Firefox, you can do this yourself:
- Right-click anywhere on a web page, and click "Inspect Element."
- Click the "Network" tab.
- Click Clock icon to start the profiling:
- View the result:
Note that the page load time can vary from page to page of your site -- what's most important are the pages your visitors first view on your site. For us, a blog page is far more important to improve than our home page, as we get far more traffic to our blog than our home page. Think about what is most important and start there.
Also see that there are two different sets of measurement: "Primed cache" and "Empty cache". A primed cache shows what it takes to load the second and later page views -- the empty cache is the one that counts for new visitors.
But... that is only part of the story, and only one crude measure. What that measures is the time until the browser says the page has completed loading, and stops spinning the "loading" icon. Your site may well be readable for visitors long before then.
Other performance measures
Performance is a complex subject, and there's lots of different parts to measure. And you might have different reasons for measuring, and attempting to improve, each:
- Latency -- how long does it take from the time you click a link and your browser starts to get a response? This can be greatly affected by network conditions, including your local connection, as well as server issues, scalability, and other factors.
- Time until page renders -- how long does it take before the site "looks" like your site? This might be a lot quicker than the actual measured page load, and may be "good enough" for your needs.
- Time until a user can interact with your site -- once the page is visible, can your users click on links, open a menu, enter a term in a search box? Again, a user might find a portal site perfectly usable if they can click away to where they are going, before the page is completely loaded.
- All resources loaded -- Drupal 8 with the "BigPipe" module has the capability to load some content into the page after the page is loaded. And lots of "single-page" applications load content through Ajax, a technique to get content from the server after the page is in the browser, which can make even slow web applications feel very responsive.
How can you improve performance?
We start by identifying what the underlying problem is, and the visible symptoms. Most often we're brought in to fix pretty egregious issues -- sites that are fine when traffic is light, but bog down at peak times, or particular pages that take a long time to load. And then many customers comment on how much faster their sites run when we migrate them to new infrastructure where we've baked in many system-level improvements.
Generally, these are the areas we most often dig in to improve performance:
- System issues, hosting environment
- Database slowness on particular pages
- Code improvements to remove slow code
- Browser-side improvements to make user interfaces "feel" quicker
System and hosting environment improvements
System-level improvements can greatly improve performance, along with scalability. These improvements become imperative on successful sites as they grow to support more traffic.
Most shared hosting uses the old "LAMP" stack -- Linux, Apache, MySQL, and PHP. While perfectly adequate to get Drupal sites loading in under 10 seconds, getting under 6 seconds can take some tweaking, and getting under 3 seconds gets near impossible for a non-optimized Drupal 6 or 7 site (Drupal 8 has some really smart caching that is optimized out of the box).
Our newer favored stack, Linux, Nginx, Docker, PHP-FPM, MariaDB, can more easily get you under 3 seconds, and with some optimizations, getting under 1 second is pretty doable on most sites.
Hardware itself counts -- the amount of RAM on a server directly translates to how many simultaneous requests the server can handle, beyond which performance tanks entirely. Solid-State Disks (SSDs) can noticeably improve performance too.
We just launched a site in a "regular" hosting environment -- a dedicated VPS with CPanel and Apache/MySQL -- and it turns out our slow, old development server has faster load times without optimizations than the Cpanel server configured for production. And our usual production servers are 5 - 6 times faster than our dev server!
And there are more tools available to speed up page load times, and other techniques -- moving to a dedicated database server, putting assets on a "Content Delivery Network" (CDN), adding a caching proxy server (Varnish), adding a database caching server (Memcached or Redis), or a search engine (Solr, specifically to speed up searches).
When particular pages are slow, the first place we look is a slow-query log. Drupal's Views module generally does a great job at writing database queries that perform just fine -- but now and then you'll put something together that the database just doesn't know how to execute quickly.
For MySQL and MariaDB, you can turn on the "slow_query_log" and see database requests that take longer than a few seconds, or run without using an index. On several sites we've seen queries that take 30 - 40 seconds to run, and some will run 5 minutes or more.
In some cases adding a database index can make a huge difference. The "EXPLAIN SELECT" syntax will break down how the database is putting together the query, which existing indexes its using, how many different rows it has to consider, and whether it needs to create and populate a temporary table to get a result.
Sometimes adding an index on some un-indexed column makes all the difference -- we've used this technique several times to shorten 40-second queries to 2 - 3 seconds, and sometimes to well under a second.
Sometimes you can't fix a slow query with an index. You might be able to rewrite the query, but sometimes it's much easier to just periodically run the slow query and cache the result for everyone else. And in certain cases, you might just be able to resolve it with a memory cache like Memcached or Redis.
One case we were working on this week has a view that generates a bunch of summary pages. On our dev environment, we run MariaDB, and this database had no trouble with the query that Views generated. However, the production server running MySQL was MUCH slower -- 35 seconds compared to 1.5 on our server. (This is due to the query having a "subselect", which MySQL has always handled poorly, and MariaDB has greatly improved). The quick fix: cache the view for 6 days, and expire the cache when new content is added.
Unfortunately in this case the strategy didn't work -- all in all this view generates ~100 individual pages, because some of the categories have several hundred items and only 20 are shown per page -- there were just too many pages that needed the cache regenerated while they were loading content.
But turning on a Memcached server may well solve a problem like this, because it can load the entire result set into RAM, and essentially provide a much faster temporary table than MySQL could do writing to disk.
Code improvements to remove slow code
This is where we get to break out all the fun tools!
If we still have a slow query, we might be able to rewrite it to take advantage of things we can index. Drupal's query objects can be manipulated to add and remove joins, change the structure, do things behind the scenes in code to improve what Views can generate. This technique can be very effective, but can limit your ability to edit the view in the future, so we try to avoid doing this for anything more than a band-aid fix.
In some cases we may need to re-structure the data itself. For one client, there was a webform with over 100 fields, and they needed a view of those results for their staff to download and process applications. To do this in Webform (at least in Drupal 6) this meant joining one webform table a hundred times -- something there was no way to effectively index! And while it worked for a few dozen submissions, by the time they had a few hundred the report became completely unusable.
We did find some indexes to add that helped, and we bumped the processing limits up to 5 minutes so they could at least get the job done, but as soon as their season was over we re-implemented the functionality using regular Drupal content objects (this was Drupal 6), which made handling this content far faster.
On another project there was a custom module that used a new (for Drupal 7) programmer interface called "EntityFieldQuery" and the Entity API module's object wrappers. This is a quite popular way for many developers to write custom code for Drupal 7 -- I think because they have the mistaken belief that Views has poor performance.
To solve this problem, we used a code profiling tool, something that analyzes every function call and reports how much time is spent in each function. Using this tool we drilled right in to find that a chain of entity wrappers ended up doing a single database call over 10,000 times in a single web request! Again, the number of queries was exponentially increasing based on the total number of items in the database -- so it wasn't noticed when the database was empty, but once in production it quickly became a huge problem.
For that case, we replaced the object wrapping with a regular view, and cut the page load time from 60 - 65 seconds down to 3 seconds.
Browser-side, UX performance improvements
With these, the fun really starts! Sometimes the web app is just the tip of a much bigger iceberg of data that simply cannot be processed quickly enough for a user's comfort level. While we have some tools like "BigPipe" and "Ajax Shopping Carts" that are already smart enough to load some slow parts of the page after the main page has been delivered, in many cases these end up involving some custom work.
Infinite Scrolling is one of my favorite user-side performance improvements. One example is Pinterest, which loads just a few cards at first, and as you scroll down, more cards load and you may never reach the bottom -- and yet the site loads quickly with just enough data for what you're looking at. This technique can be used with large tables of data, if you're working with some sort of data/information system.
Other techniques involve pre-processing or batch-processing information so it can be shown directly, instead of calculating on the fly.
This is one of the most exciting parts about Drupal 8 -- how much better suited it is than any previous version for loading bits of content as needed, and without needing to bootstrap all of Drupal for a simple request. This opens up a lot of opportunities to provide customizations of the web front-end, to hugely improve performance on complex web applications.
When should you care about performance?
I've spoken with very senior Drupal developers working on extremely large, high-traffic sites, and they claim to not care one bit about performance -- they care about Scalability. Performance is how quick a page loads for a single user -- Scalability is how many visitors can a site have before performance starts to suffer. The two are a bit intertwined.
So here are some indications that you should consider improving performance:
- People are getting server timeouts.
- Some pages never finish loading.
- Users are frustrated because the site "feels" slow.
- You know having a fast site is necessary for your brand, reputation, competitiveness, or other concern, and you have room (and budget) for improvement.
If you're looking to improve the performance of your Drupal site, contact us! We have a lot of experience solving performance issues of all kinds, and we'd love to help!