Memcached im Einsatz
Aus AdminWiki
Inhaltsverzeichnis |
Überlegung
Natürlich macht der Einsatz von memcached nur Sinn, wenn wir Daten in einer Datenbank haben, aus der deutlich mehr gelesen als hineingeschrieben wird. Das bedeutet, der Anteil von SELECT's sollte deutlich größer sein als der mit UPDATE's oder INSERT's. Im Idealfall haben wir Daten, die sich verhältnismäig wenig ändern und anhand eines Primärschlüssels abgefragt werden können.
Beispiel für einen Idealfall:
SELECT * FROM artikel WHERE id = 123;
Sofern der Artikel einmal geschrieben ist, wird es sich in der DB so schnell nicht ändern. Dennoch erzeugt es natürlich eine nicht unerhebliche Last auf dem Datenbankserver, wenn diese Anfrage tausendfach ausgeführt wird.
Außerdem brauchen wir natürlich freien RAM. Und zwar nur freien RAM. Memcached verbraucht quasi null CPU-Zeit und auch sonst keinerlei Ressourcen. Im Netzwerk entsteht natürlich ein gewisser Traffic, der ist aber zu vernachlässigen, denn dafür wird ja Traffic zum DB-Server gespart. Im Grunde kann man auf jedem Server, der viel ungenutzen RAM hat, problemlos eine memcached-Instanz laufen lassen.
Limitationen
Bei memcached gibt es vor Allem eine Limitation, die man zwingend beachten sollte:
Datensätze dürfen nicht größer als 1 MByte sein (1024 KByte)
Das sollte aber bei normale SQL-Ergebnissen kein Problem darstellen.
Umgebung
Ein oder mehrere Linux-Server (in diesem Fall Debian) mit installiertem MySql, PHP5 und Apache-Webserver aus Debian-Paketen.
Unser beispielhafter memcached-Host hat als IP hier die 192.168.10.210.
Installation
Installation libevent
Memcached benötigt libevent. Unter Debian tut es ein simplesapt-get install libevent-dev
Natürlich kann man libevent auch von Hand installieren, die Sourcen gibts hier: http://monkey.org/~provos/libevent/
Installation memcached
Hier verwenden wir absichtlich nicht das Debian-Paket, da dieses leider veraltet ist. Es lohnt aber auf jeden Fall, immer das neueste Release von memcached einzusetzen. Wir besorgen uns also die neueste Version von http://www.danga.com/memcached/download.bml via wget und entpacken das File irgendwo bei uns auf dem Server (/usr/src z.B.).
Anschließend wird via
./configure;make;make install;
memcached installiert (natürlich kann man Installationspfad usw. im ./configure anpassen ...)
Das Binary memcached ist dann unter /usr/local/bin/memcached zu finden (siehe: which memcached).
Installation PHP-Erweiterung
Um komfortabel via PHP in den memcache schreiben bzw. daraus lesen zu können, benötigen wir noch das PECL-Paket (http://pecl.php.net/package/memcache).
Als Debian-User kann man natürlich die einfache Variante
apt-get install php5-memcache
wählen. Nach einem Apache-Neustart sollte das Modul aktiv sein, siehe auch phpinfo().
Mini-Initscript samt Config
Da es für memcached kein Configfile gibt, passiert die gesamte Konfiguration beim Start. Daher ist es sinnvoll, ein kleines Initscript zu verwenden, welches die Config beinhaltet und memcached, sofern gewünscht, gleich beim Systemstart mit hochfährt.
Beispielscript:
#!/bin/sh echo "Starte memcached als www-data ..." # 15872 MB = 15,5 GB memcached -d -m 15872 -c 4096 -l 192.168.10.210 -p 11211 -u www-data
Der Parameter -d lässt memcached als Daemon laufen.
-m gibt in MegaByte den maximal verwendeten Speicher an (soviel RAM sollte vorher mindestens frei sein, siehe free -m!!!)
-c legt die maximale Anzahl der gleichzeitigen Connections fest.
-l ist besonders wichtig. Es definiert das Interface (bzw. die IP), auf der memcached lauscht. Dies ist die einzige Sicherheitsfunktion und sollte daher unbedingt gesetzt werden, idealerweise auf ein internes LAN-Interface. Offene Zugriffe von außen auf memcached sollten auf jeden Fall unterbunden werden.
-p gibt den Port an (Default: 11211)
-u legt den User fest, unter dem memcached läuft. Als root wird es sich weigern zu starten. Wir nutzen hier den Debian-Webuser www-data. Ansonsten kann ein beliebiger User angelegt werden.
Anschließend kann via ./memcached der Daemon via Script gestartet werden. Idealerweise kopiert man das Script nach /etc/init.d
Test-Connect via PHP
Um zu testen, ob der Daemon ordnungsgemäß läuft, kann man ein simples PHP-Script bemühen:
<?php
$mc = memcache_connect("192.168.10.210"); // unser memcached-Host
var_dump( memcache_get_stats($mc) );
?>
Die Ausgabe sollte dann sowas bringen wie dies:
array(22) {
["pid"]=>
string(4) "7735"
["uptime"]=>
string(7) "124"
["time"]=>
string(10) "1228988970"
["version"]=>
string(5) "1.2.6"
[ ... ]
}
PHP kann sich also problemlos zu unserem memcached-Host connecten.
In die Website/Scripte einbauen
Nun ist es an der Zeit, den memcache auch in die vorhandenen PHP-Scripte zu implementieren.
Wie auch bei einem Datenbankserver bedarf es anfangs einer Verbindung zum memcached-Host:
$mc = memcache_pconnect('192.168.10.210', 11211);
Man kann entweder memcache_connect() für normale- oder memcache_pconnect() für persistente Connections verwenden.
Nehmen wir nun an, wie haben wieder das obige Query in unserem PHP-Code. Das könnte z.B. so aussehen:
$q = mysql_query("SELECT * FROM artikel WHERE id = $id LIMIT 1");
$row = mysql_fetch_array($q));
Um dieses Query mittels memcached abzufangen, bedienen wir uns folgender Logik:
$ergebnis = memcache_get($mc, $id);
if(!$ergebnis) {
$q = mysql_query("SELECT * FROM artikel WHERE id = $id LIMIT 1");
$row = mysql_fetch_array($q));
$ttl = 3600; // time to life (TTL) in Sekunden, 1h
memcache_set($mc, $id, $row, MEMCACHE_COMPRESSED, $ttl);
}
Es wird also immer zuerst versucht, die Daten aus dem memcache zu laden (via memcache_get() ). Sind dort keine Daten vorhanden, gibt diese Funktion false zurück. In diesem Fall fügen wir einen neuen Datensatz via memcache_set() in den memcache ein.
Hinweise dazu:
- $id ist die eindeutige ID für den jeweiligen Datensatz im Memcache. Es eignet sich daher besonders gut der INT-Wert einer Primary-Spalte aus der Datenbank oder ein MD5-Hash z.B. von einem Suchbegriff. Auf jeden Fall ist zu beachten, dass jeder neue Datensatz eine eigene ID bekommt. Verwendet man eine vorhandene ID, wird diese einfach überschrieben!
- Die TTL ($ttl) wird in Sekunden angegeben. Default werden die Einträge nach maximal 2592000 Sekunden, also 30 Tagen entfernt.
- Das Flag MEMCACHE_COMPRESSED ist optional und bewirkt bei installierter zlib-Erweiterung die Komprimierung der Daten im RAM. Soll es nicht verwendet werden, einfach z.B. false einfügen.
Die Daten werden dann serialisiert an memcached gesendet. Es macht also keinen Sinn, vorher serialize() anzuwenden. Prinzipiell sind aber alle Datentypen möglich.
Die Funktionsreferenz für die memcache_* PHP-Funktionen findet sich hier: http://de2.php.net/manual/de/ref.memcache.php
Weblinks
- Official Site
- Installing memcached auf ajohnstone.com
- Eintrag im Admin-Blog.com zu diesem Wiki-Eintrag
- Vergleich von Cachine-Methoden (memcached, MEMORY-Tabellen, Flatfiles etc. im Admin-Blog.com
