Web Design

Real Time Drupal Performance

At work lately, I've been dealing with an interesting problem: real time performance on a Drupal website.  It's interesting because the standard solutions don't work.  (This is a support page for an upcoming Badcamp presentation.)

Standard solutions include Memcache, Varnish, Solr, and Boost.  However, those all involve caching content, which we can't do here.

Metrics

First, let's gather some data about exactly what's responsible for slowing the site down.  Useful tools include:

Plus there are some useful modules to collect more granular data:

Improvements

So, what specific things can you do to improve performance, without caching content?

  • APC
  • Remove unused modules
  • Move javascript to the bottom of the page, CSS to the top
  • Remember to turn off your data-gathering modules once you have the information you need.  They'll make your performance MUCH worse if you leave them on.
  • Bonus: Microcaching.  Can't do it with a standard LAMP stack.  Need nginx.

To move js to the bottom of the page, add this code to your template.php or custom module:



/**
 * Implementaion of hook_js_alter()
 * Override Glossy handling, new handling added by Jordan AIRS.
 * Move most javascripts to bottom of page, but allow overrides to keep certain js in 
 */
function glossy_js_alter(&$javascript) {
  // Collect the scripts we want in to remain in the header scope.
  $header_scripts = array(
    'sites/all/libraries/modernizr/modernizr.min.js',
    'sites/all/modules/timeline/js/timeline.js',
    'sites/all/libraries/simile_timeline/timeline_js/scripts/l10n/en/labellers.js',
    'sites/all/libraries/simile_timeline/timeline_js/timeline-bundle.js',
    'sites/all/libraries/simile_timeline/timeline_js/timeline-api.js',
    'sites/all/libraries/simile_timeline/timeline_ajax/simile-ajax-api.js',
    'sites/all/libraries/simile_timeline/timeline_ajax/simile-ajax-bundle.js',
    'misc/drupal.js',
    'sites/all/modules/jquery_update/replace/jquery/1.5/jquery.min.js',
    'sites/all/libraries/OpenLayers/OpenLayers.js',
    'sites/all/modules/openlayers/js/openlayers.js',
    'sites/all/modules/openlayers/plugins/layer_types/openlayers_layer_type_xyz.js',
    'sites/all/modules/openlayers/plugins/behaviors/openlayers_behavior_attribution.js',
    'sites/all/modules/openlayers/modules/openlayers_views/plugins/layer_types/openlayers_views_vector.js',
    'sites/all/modules/openlayers/plugins/behaviors/openlayers_behavior_cluster.js',
    'sites/all/modules/openlayers/plugins/behaviors/openlayers_behavior_layerswitcher.js',
    'sites/all/modules/openlayers/plugins/behaviors/openlayers_behavior_navigation.js',
    'sites/all/modules/openlayers/plugins/behaviors/openlayers_behavior_panzoombar.js',
    'sites/all/modules/openlayers/plugins/behaviors/openlayers_behavior_popup.js',
    'sites/all/modules/homebox/homebox.js',
    'sites/all/modules/homebox/includes/tipsy/jquery.tipsy.js',
  );
 
  // Change the default scope of all other scripts to footer.
  // We assume if the script is scoped to header it was done so by default.
  foreach ($javascript as $key => &$script) {
      if ($script['scope'] == 'header' && !in_array($script['data'], $header_scripts) && $script['type'] == 'file') {
        $script['scope'] = 'footer';
      }
    }
}

Mysql improvements

With so much data and so many Views, a lot of the burden is on the database.  Here's a list of improvements specifically related to the database:

  • Index mysql database columns
  • When possible, replace Rules php code with a mysql trigger
  • Host the sql database on a separate server
  • Improve RAM allocation to the mysql daemon
  • Install a multi-core processor on the server so it can run Apache & mysql simultaneously
  • Store the databse on a faster hard drive: RAID array, SSD, RAM disk, etc.

Modules to improve performance

I didn't use these modules but you may find them useful:

Bottom Line

"So, what should I use?"  The best answer is try everything.  Everyone will have a slightly different solution that works best for them.  If you really want an optimal solution, you'll have to put in some effort to get there.