A few tips to accelerate Drupal

CleanTalk is a SaaS spam protection service for Web-sites. CleanTalk uses protection methods which are invisible for site visitors. Connecting to the service eliminates needs for CAPTCHA, questions and answers and other methods of protection, complicating the exchange of information on the site.

718bd6e973394d09991480d52fa558d2Drupal constantly criticized for its slowness, for the great number of database requests and clumsiness. Most often it is solved by using Memcached or Varnish. In this article I would like to add a few more tips, the use of which will not make Drupal even slower. Those who are interested, please welcome under the cut.

Use JS module

Together with the functionality of the site is growing and the number of consumed memory and the number of SQLrequests needed to perform a full load Drupal. If you need to do only one SQL request using AJAX, Drupal can spend a lot of time to fully load and execute code that may never be used in the request. JS module solves this problem by providing an alternative way to download Drupal only to the level required for a specific task. Including allowing you to connect the necessary files and modules to handle the request.

Drupal loads itself with each request through a series of phases of the boot. All phases of the download are defined in the file bootstarp.inc:

  • DRUPAL_BOOTSTRAP_CONFIGURATION: In this phase filled an internal array of configurations Drupal, set the base URL, analyze settings.php file, etc.
  • DRUPAL_BOOTSTRAP_PAGE_CACHE: An attempt to provide a page from the cache, if enabled page caching for anonymous users.
  • DRUPAL_BOOTSTRAP_DATABASE: Determine the type of database and the connection to request the database.
  • DRUPAL_BOOTSTRAP_VARIABLES: Initialization of variables.
  • DRUPAL_BOOTSTRAP_SESSION: Initialization treatment of sessions.
  • DRUPAL_BOOTSTRAP_PAGE_HEADER: Setting the page title.
  • DRUPAL_BOOTSTRAP_LANGUAGE: Definition of the language of the page.
  • DRUPAL_BOOTSTRAP_FULL: Loading modules and initialization of issues.

For example, if you only need to use the function variable_get () in the AJAX callback will be enough level DRUPAL_BOOTSTRAP_VARIABLES, and if you need access to the current user object $user you need to use DRUPAL_BOOTSTRAP_SESSION etc.

To work with the module JS enough to realize hook_js (), in which to describe what modules you need to connect, what phase of the bootstrap to use:

/**
 * Implements hook_js().
 */
function js_example_js() {
  return array(
    'results' => array(
      'callback' => 'js_example_ajax_results', // The callback function is required to display the results
      'includes' => array('unicode', 'locale', 'language'), // Which files to download from a directory /includes
      'dependencies' => array(), // List of modules to be loaded
      'bootstrap' => DRUPAL_BOOTSTRAP_DATABASE, // Required loading phase Drupal
      'file' => 'js_example.ajax.inc', // File that contains the callback
      'access callback' => 'js_example_ajax_results_access', // The callback function to check the access rights
      'access arguments' => array(), // The argument list for the access callback
      'page arguments' => array(), // The argument list for the callback
      'skip_hook_init' => TRUE, // A flag that allows you to skip the execution hook_init(),
      'i18n' => FALSE, // A flag that lets you enable or disable support for i18n
    ),
  );
}

It is important to understand that it is quite difficult to perform the control of access rights in the initial stages of loading Drupal, so it is necessary to closely monitor the security of their code.

Loading entities

It is often necessary to add fields from the user profile in the node and the most simple solution for this use the hook template_preprocess_node():

template_preprocess_node(&$variables){
$node = $variables['node'];
$variables['account'] = user_load($node->uid);
}

But when displaying a large number of nodes, this approach will create a large number of database requests. Get the same functionality without sacrificing performance by using the hook hook_entity_prepare_view():

hook_entity_prepare_view($entities, $type, $langcode{
  if ($type != 'node') {
    return;
  }
  $uids = array();
  foreach ($entities as $entity) {
    $uids[] = $entity->uid;
  }
  $accounts = user_load_multiple($uids);
  foreach ($entities as $entity) {
    $entity->account = $accounts[$entity->uid];
  }
}

After that, $ entity-> account will be available in preprotsesse:

template_preprocess_node(&$vars) {
  $account = $vars['node']->account;
}

Use drupal_static()

When the code is executed multiple times during a single request, it is very convenient to use static variables to cache (more on static variables in PHP can be found here and here). Drupal core provides an excellent solution for the realization of static caching – function drupal_static(). Function drupal_static() provides a central static variable to store data. The first call drupal_static () returns NULL, but any changes in this variable will be saved for the next call to this function. This way we can check whether the variable is already installed and get it instantly without doing almost no work at the same time.

function my_module_function() {
  $foo = &drupal_static(__FUNCTION__);
  global $user;
  if (!isset($foo[$user->uid])) {
    $foo[$user->uid] = something_expensive();
  }
  return $foo[$user->uid];
}

Frequent use of variable_set () affect performance

Variables in Drupal are stored in a special table in the format: name – the serialized value. For each request, all variables are loaded from the cache in the global variable $conf.

During saving of each variable the following happens:

  • The record is updated in the database
  • Ceared cache
  • When the next request finds that there is no cache for table variables, all variables are loaded and stored in the cache.

With a large number of variables it can take a lot of time. In Drupal is realized locking system and any long-running operations in parallel which, most likely, will come other requests should try before work to get a lock. If the previous request to clear the cache variables, the following request will rebuild it, so it is very frequent use functions variable_set() can lead to mass table lock, due to the fact that tens of requests waiting for a new record cache table of variables that can become out of date before it will extract for use.

Reduction of the table sessions

Drupal stores user sessions in the database instead of files, so if a site with a large attendance, this table can quickly grow to enormous size. If the table session was very large, you can increase the frequency of garbage collection for PHP-sessions in settings.php:

ini_set('session.gc_maxlifetime', 86400); 

I hope that not all of this list is just too obvious things and this is useful to someone.

This text is a translation of the article “Несколько советов по ускорению Drupal” by afi13 published on habrahabr.ru.

Forums and blogs without spam

CleanTalk is a SaaS spam protection service for Web-sites. CleanTalk uses protection methods which are invisible for site visitors. Connecting to the service eliminates needs for CAPTCHA, questions and answers and other methods of protection, complicating the exchange of information on the site.

Leave a Reply

Your email address will not be published. Required fields are marked *