Drupal und Memcache unter Debian GNU/Linux

Drupal und Pressflow fühlen sich am wohlsten, wenn ihnen zusätzliche Caching-Mechanismen zur Verfügung gestellt werden. Dazu zählt neben dem Opcode-Cache APC vor allem Memcache.

Das Aufsetzen des erforderlichen Stacks ist relativ einfach, aber nicht ganz trivial. Die nachfolgende Anleitung beschreibt eine mögliche Vorgehensweise unter Debian GNU/Linux ›Lenny‹.

Contents

Systemvoraussetzungen

Memcache wird in Drupal integriert über das Zusatzmodul Memcache API and Integration von Robert Douglass et al., setzt aber serverseitig eine funktionsfähige und sinnvoll konfigurierte Installation des Memcache-Daemons voraus.

Debian GNU/Linux ›Lenny‹ wird mit memcached 1.2.2 ausgeliefert; ›Lenny‹ enthält ebenfalls:

  • php5-memcache - memcache extension module for PHP5 (Version 3.0.1-1)
  • libmemcache0 - C client API for memcached memory object caching system (Version 1.4.0.rc2-1)
  • libmemcache-dev - development headers for libmemcache C client API (Version 1.4.0.rc2-1)

php5-memcached wird erst in ›Squeeze‹ (derzeit testing) bzw. ›Sid‹ (derzeit unstable) paketiert zur Verfügung stehen.

libmemcache-dev enthält folgende Dateien:

/usr/include/memcache.h
/usr/include/memcache/_buffer.h
/usr/include/memcache/buffer.h
/usr/lib/libmemcache.a
/usr/lib/libmemcache.la
/usr/lib/libmemcache.so
/usr/share/doc/libmemcache-dev/changelog.Debian.gz
/usr/share/doc/libmemcache-dev/changelog.gz
/usr/share/doc/libmemcache-dev/copyright

Memcache-Daemon

Den Memcache-Daemon installiert man auf dem Debian-üblichen Weg. Das mitgelieferte Init-Skript stellt jedoch nur eine Instanz des Daemons zur Verfügung, für Drupal benötigen wir jedoch mehr.

Robert Ristroph und David Strauss von Four Kitchen Studios haben jedoch ein Init-Skript von CentOS 5 angepasst: Replacement Init Script for memcached on Debian or Ubuntu

Den Code aus /etc/init.d/memcached ersetzt man mit diesem modifizierten Skript:

#! /bin/sh
#

PORT=11211
USER=nobody
MAXCONN=1024
OPTIONS=""
DAEMON=/usr/bin/memcached

RETVAL=0
prog="memcached"

start_instance() {
        echo -n $"Starting $prog (): "
        start-stop-daemon --start --quiet --pidfile /var/run/memcached/memcached..pid --exec $DAEMON -- -d -p $PORT -u $USER  -m  -c $MAXCONN -P /var/run/memcached/memcached..pid $OPTIONS
        RETVAL=$?
        echo
        [ $RETVAL -eq 0 ] && touch /var/lock/memcached.
        PORT=`expr $PORT + 1`
}

stop_instance() {
        echo -n $"Stopping $prog (): "
        start-stop-daemon --stop --quiet --oknodo --pidfile /var/run/memcached/memcached..pid --exec $DAEMON
        RETVAL=$?
        echo
        if [ $RETVAL -eq 0 ] ; then
            rm -f /var/lock/memcached.
            rm -f /var/run/memcached/memcached..pid
        fi
}
start () {
        # insure that /var/run/memcached has proper permissions
       mkdir -p /var/run/memcached
        if [ "`stat -c %U /var/run/memcached`" != "$USER" ]; then
                chown $USER /var/run/memcached
        fi

        start_instance default 64;
        start_instance block 16;
        start_instance content 128;
        start_instance filter 128;
        start_instance form 32;
        start_instance menu 16;
        start_instance page 8;
        start_instance update 8;
        start_instance views 8;
}
stop () {
        stop_instance default;
        stop_instance block;
        stop_instance content;
        stop_instance filter;
        stop_instance form;
        stop_instance menu;
        stop_instance page;
        stop_instance update;
        stop_instance views;
}

restart () {
        stop
        start
}

# See how we were called.
case "" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        status memcached
        ;;
  restart|reload|force-reload)
        restart
        ;;
  *)
        echo $"Usage: xx-tagmarker2-xx {start|stop|status|restart|reload|force-reload}"
        exit 1
esac

exit $?

Dadurch werden neun Memcached-Instanzen zur Verfügung gestellt:

  1. Port 11211: default (64 MB);
  2. Port 11212: block (16 MB);
  3. Port 11213: content (128 MB);
  4. Port 11214: filter (128 MB);
  5. Port 11215: form (32 MB);
  6. Port 11216: menu (16 MB);
  7. Port 11217: page (8 MB);
  8. Port 11218: update (8 MB);
  9. Port 11219: views (8 MB);

Hinweis: Das Init-Skript hat einige Bugs; es unterstützt u.a. den Parameter /etc/init.d/memcached status nicht.

Ergänzende Anmerkungen im Four-Kitchens-Wiki: Using memcached with Drupal or Pressflow on CentOS 5

Prüfen, ob der Daemon korrekt läuft:

# netstat -n -p -t -a | grep memcached
tcp   0   0 0.0.0.0:11211   0.0.0.0:*   LISTEN   3124/memcached
tcp   0   0 0.0.0.0:11212   0.0.0.0:*   LISTEN   3128/memcached
tcp   0   0 0.0.0.0:11213   0.0.0.0:*   LISTEN   3132/memcached
tcp   0   0 0.0.0.0:11214   0.0.0.0:*   LISTEN   3136/memcached
tcp   0   0 0.0.0.0:11215   0.0.0.0:*   LISTEN   3140/memcached
tcp   0   0 0.0.0.0:11216   0.0.0.0:*   LISTEN   3144/memcached
tcp   0   0 0.0.0.0:11217   0.0.0.0:*   LISTEN   3148/memcached
tcp   0   0 0.0.0.0:11218   0.0.0.0:*   LISTEN   3152/memcached
tcp   0   0 0.0.0.0:11219   0.0.0.0:*   LISTEN   3156/memcached


Einbindung in PHP5

Die Einbindung des Memcache-Daemons in PHP erfolgt über über eines der beiden PECL-Erweiterungsmodule:

Derzeit aktuelle Versionen:

# pecl search memcache
Retrieving data...0%
.MATCHED PACKAGES, CHANNEL PECL.PHP.NET:
=======================================
PACKAGE   STABLE/(LATEST) LOCAL
memcache  2.2.5 (stable)        memcached extension
memcached 1.0.2 (stable)        PHP extension for interfacing with
                                memcached via libmemcached library

Empfohlen wird das memcached-Erweiterungsmodul, das mit PECL gebaut werden kann. Das scheitert allerdings unter ›Lenny‹, da include/libmemcached/memcached.h zwingend benötigt wird. Diese Header-Files sind in libmemcache-dev nicht enthalten, also muss es das (ältere) memcache-Paket tun:

# pecl install memcache
...
Build process completed successfully
Installing '/usr/lib/php5/20060613/memcache.so'
install ok: channel://pecl.php.net/memcache-2.2.5
configuration option "php_ini" is not set to php.ini location
You should add "extension=memcache.so" to php.ini

Konfigurationsdatei für die memcache-Erwiterung findet sich unter /etc/php5/conf.d/memcache.ini:

extension=memcache.so

[memcache]
memcache.dbpath="/var/lib/memcache"
memcache.maxreclevel=0
memcache.maxfiles=0
memcache.archivememlim=0
memcache.maxfilesize=0
memcache.maxratio=0
memcache.hash_strategy="consistent"


Einbindung in Drupal

Der Memcache-Daoemon wird über das Zusatzmodul Memcache API and Integration in Drupal integriert. Das Modul wird Drupal-üblich installiert und muss nun noch in ./sites/default/settings.php konfiguriert werden:

$conf = array(
  'cache_inc' => './sites/all/modules/memcache/memcache.inc',
  'memcache_servers' => array(
    'localhost:11211' => 'default',
    'localhost:11212' => 'block',
    'localhost:11213' => 'content',
    'localhost:11214' => 'filter',
    'localhost:11215' => 'form',
    'localhost:11216' => 'menu',
    'localhost:11217' => 'page',
    'localhost:11218' => 'update',
    'localhost:11219' => 'views',
  ),
  'memcache_bins' => array(
    'cache' => 'default',
    'cache_block' => 'block',
    'cache_content' => 'content',
    'cache_filter' => 'filter',
    'cache_form' => 'form',
    'cache_menu' => 'menu',
    'cache_page' => 'page',
    'cache_update' => 'update',
    'cache_views' => 'views',
  ),
  'memcache_key_prefix' => 'meinschluessel',
);

Die verschiedenen Memcache-Instanzen finden sich mit einigen Statistiken im Administrationsbereich der Drupal-Website unter ./admin/reports/memcache, nachdem die Systemcaches geleert wurden.


Überwachung und Optimierung

Nachdem die Basisinstallation läuft, folgt das kontinuierliche Monitoring sowie die Feinabstimmungen der einzelnen Instanzenn. Sinnvolle Hilfswerkzeuge können hierfür beispielsweise sein: