Drupal 8 has been released more than one year ago, but Drupal 7 is still widely used: it's totally stable, feature-rich, actively maintained and has tons of available modules for a functionality extension, and these modules are very stable as well. In this article, I would love to draw your attention to Drupal 7 performance only. You can find a lot of information on Drupal 7 performance over the Internet since Drupal 7 is available for a long time, but anyway, things change and new options appear. I'd like to highlight these options.
Website performance is very important because it can lead to higher conversion rates, higher search ranking and hosting costs reduction. In this article, we'll look at the different ways and remember how Drupal 7 performance can be improved. I'll focus on Drupal 7 performance on the server side, but there are other areas where website performance can and should be improved including front-end, a database, etc. Some improvements are easier to implement than others though.
Let's start with the easiest settings to set.
CSS / JS
This is the only exception from other aspects in this article since it's about front-end performance i.e. page load improvements after a response is delivered to a browser. People complain sometimes that Drupal is slow, but I saw many sites hadn't had JS or CSS aggregation enabled which is just 2 checkboxes in the settings which noticeably decreases a number of files to load: this setting is very easy to change so don't neglect it.
When it comes to back-end tips, you'd better use relevant software releases. Drupal 7 officially supports PHP 5.2.5 or higher (5.4 or higher recommended), but currently maintained PHP versions are 5.6, 7.0 and 7.1. PHP 5.5 is unsupported since July 21, 2016, so it doesn't receive any updates including security fixes. Also, PHP is shipped with a Zend OPcache bytecode engine starting from the version 5.5, and that noticeably improves PHP code execution performance.
PHP 7 is significantly faster and less memory consuming in comparison with PHP 5.6 and officially supported since Drupal 7.50: that means there are no known issues with PHP 7 in Drupal core. Popular contrib modules also work with PHP 7 very well and there is a very low probability that the contrib project you want to utilize doesn't support PHP 7, and maybe you'll need to adapt custom code.
Also, decide if you need HTTP/2 or not. It can noticeably improve a page load time, but it’s supported by browsers over TLS only and makes HTTP 1.1 specific optimizations like image sprites, domain sharding, etc. at least useless, and makes some of them affecting performance badly.
We agreed that the recent software is a must. The same applies to the latest Drupal updates.
Drupal core and modules
New Drupal and contrib project releases can contain not only bug fixes, new features and security fixes (please update as soon as possible in this case), but also performance improvements, so you should use the latest available versions and update regularly.
Unused / missing modules
Usually, a site runs in different environments: local and development for development purposes, staging for testing purposes (before moving updates to production), and production - but there may be more environments. And it's very natural that they have different settings and lists of enabled and disabled modules. For example, the local and development environments usually have some development-helper modules enabled like Devel, disabled caching, CSS / JS aggregation and many other. In the production environment, you definitely should not have development-helper modules enabled, but there'll be some other, for example, Google Analytics, which you'll probably have enabled on the production only.
So, don't forget to disable the modules that you don't use to avoid loading needless code which takes an additional time. If any module is not used in all environments (for example, it was added during development just for an experiment) then remove it from a source, but first, don't forget to uninstall it properly because missing (improperly removed) modules may affect performance badly.
Drupal core caching
Drupal core provides options to cache blocks (which should be enabled if possible) and also to cache whole pages for anonymous users which are very useful for content sites on which the most of regular users are anonymous.
Drupal is used with many contrib modules, and it's important for them to utilize caching and provide their own caching, related configuration possibilities and related configuration.
Views is the most popular Drupal contrib module and many website outputs are built with a help of it. Views retrieve results from a data storage, and in case of a complex condition, sorting or applied aggregation options it may become heavy in terms of performance. In case of the complex output with a lot of fields, it may be heavy as well.
Views provide a time-based (with a specified cache lifetime) cache and both the raw query result and a resulting output can be cached.
Since mostly Views is used to display regular content (nodes) of the particular type(s), views cache can be flushed/rebuilt only when corresponding content is updated. This results in better cache utilization in comparison with a time-based caching. And the Views content cache contrib module provides a caching mechanism for Views which works in this way. In case updates on the site happen not frequently (for example, blog with a few new posts per week) cache may live for days and even weeks and reflect content updates immediately in comparison with the time-based cache where lifetime is usually limited to a few hours at the maximum.
A pages cache for anonymous users provided by the Drupal core requires a partial bootstrap to deliver the cache from Drupal. When it’s possible Varnish is a better option to cache pages for the anonymous users, it delivers the cache to users without even triggering Drupal. In advanced usage, Varnish can be utilized to cache content for logged-in users as well.
You'll need the Varnish module for an integration, and the Cache Expiration and the Purge additional modules are recommended for cache expiration and cleaning. Please see the module's documentation for configuration details.
Varnish integration with Drupal may differ depending on hosting actually. For example, on Acquia you will not need the Varnish module, it just will not work. Note configuration code example:
$conf['cache_backends'] = 'includes/cache-install.inc'; $conf['cache_backends'] = './sites/all/modules/memcache/memcache.inc'; $conf['cache_default_class'] = 'MemCacheDrupal'; $conf['cache_class_cache_form'] = 'DrupalDatabaseCache'; $conf['cache_class_cache_page'] = 'DrupalFakeCache';
Page cache handler is set to the DrupalFakeCache class, so Drupal returns proper cache control headers, but a response is cached only once by Varnish and not cached by Drupal itself. Please check your hosting documentation first to configure Varnish properly.
When Varnish is not available, there is one more simple option to cache whole pages for anonymous users for better performance: the Boost module which caches pages to regular .html files and delivers just these static files as a cache when possible. Please see the module's README.txt for more info on installation and configuration. Again, Cache Expiration and Purge are recommended as additions.
Entities are the crucial part of Drupal, and they are very handy to deal with different kinds of data. In Drupal core nodes, comments, users, taxonomy terms, taxonomy vocabularies, and files are the entities. Many other types of entities are defined by contrib modules, and the entities defined by custom code are very useful as well.
Fieldable entities, especially when there are many fields attached, may be too heavy to load them fast. When entities are frequently loaded on a website, for example, because of some processing as a reaction to some users' actions, it's better to cache the entities. Drupal caches the entities via the core's field cache by default, but the Entity cache module provides a more efficient solution for an entity caching. But it's highly recommended to use it with Memcached or Redis as a cache storage to achieve the maximum performance improvements.
Drupal provides search functionality from its core and stores a search index in a database, and maybe not performant enough when there is a lot of content on a website. The Apache Solr Search module extends Drupal core search functionality to allow using an Apache Solr search platform instead of the database for a better performance and scalability. It also adds some new features to Drupal search functionality.
One more solution to build search functionality in Drupal is the Search API module. Search results and filters are usually output via Views when the module is used, and this adds more flexibility. Search API separates "search index" and "search server" terms and implements a pluggable system for search backends so there are many options available: Solr, Sphinx, Database and other.
You should never implement full-text search functionality by building the output via the Views module and querying results from the database using "contains" conditions.
Drupal performs different tasks on cron, including a cleanup, particular tasks are implemented via a hook_cron() hook. Basically, there is no need to execute all of these tasks at the same time (which is the default behavior), especially when you need to execute some of the tasks very frequently, for example, a scheduled content publication, subscriptions' expiration or queue processing. In such cases, cron tasks running simultaneously may cause performance issues and a frequent execution of tasks which shouldn't be done that often: all of these may slow down other tasks execution which really need to run frequently.
The Elysia Cron and the Ultimate Cron modules allow to schedule each cron task individually for proper tasks distribution in time and to avoid high load at a single cron run.
Entities without revisions
When you have the process on a site that creates or updates many entities, for example, nodes, and you need to speed up this process, for instance, because a user awaits the result of this process, the Field SQL norevisions module may be helpful in case created/updated entities do not use revisioning. This module halves an amount of executed database queries needed to insert/update entities' field values. Please read the Fields with no revisions article for more information on the problem and solution.
When you deal with entities in code, use entity_load() and node_load_multiple() to load several entities and particularly nodes instead of entity_load_single() (provided by the Entity API module) and node_load()in loops.
Utilizing cache in code
Use cache_get() and cache_set() to get and save a cache to a common cache bin or your custom bin. For example, you may want to cache some meta information received from a third party service.
Use drupal_static() to cache data that is frequently used during a single page request. Use more advanced technique via $drupal_static_fast covered on the same documentation page for the cases when data is requested a lot of times (hundreds and more) during one process.
As I mentioned at the beginning of the article, website performance is very important. This article covers several ways to improve Drupal performance on the server side, but it's not a complete list, of course: there are many other options, some of them applicable to specific needs. Drupal performance can be greatly improved, and there are a lot of options for improvements, many of them are easy to implement and require additional module installation and configuration only, with no other effort.