Wir verwenden mittlerweile bei morphex load balancing per DNS um die User auf unsere Webfrontends so gut wie möglich zu verteilen. Damit wir bei einem Ausfall einer oder mehrerer der Server schnell reagieren können, verwenden wir eine recht geringe Time To Live (TTL) von 1000 Sekunden, was dazu führt, das die User im Schnitt alle 1000 Sekunden den Server “wechseln”, wenn nicht irgendein DNS Cache dazwischen sitzt.
;; ANSWER SECTION:
www.morphex.eu. 949 IN A 88.198.193.106
www.morphex.eu. 949 IN A 78.47.243.234
www.morphex.eu. 949 IN A 78.47.243.242
www.morphex.eu. 949 IN A 88.198.193.98
Der Server der jetzt die Anfragen des Clients beantwortet weiß natürlich nichts von diesem, der User sendet zwar ein Cookie mit einer PHP Session ID, diese ist dem Server jedoch nicht bekannt, daraus resultiert das diverse Informationen aus der Datenbank erneut vom Server in die Session eingelesen werden müssen.
Um dieses Problem zu umgehen habe ich mehrere Varianten durchprobiert, die einfachste war, das lokale /tmp Verzeichniss in dem PHP bei uns die Session Daten speichert auf unserem zentralen NFS-Server zu speichern. Diese Methode habe ich schnell wieder verworfen, weil die Geschwindigkeit nicht optimal war und mir zu viele i/o’s auf dem NFS-Server erzeugt wurden.
Als zweites habe ich probiert die Session Daten in einer Datenbank auf einem unserer Mysql Server zu speichern, dies funktionierte auch sehr gut.
Obwohl die 2te Variante sehr gut lief, habe ich zum Testen auch meine 3te Idee getestet, die Session Daten auf einem Memcached Server zu speichern. Wir verwenden bei morphex an verschiedenen Stellen, weil es durch sein Prinzip Daten nur im Ram zu speichern sehr schnell und ohne große CPU Auslastung Daten anliefern kann.
Damit die folgenden Schritte funktionieren muss man das PHP Memcached Modul installiert haben, unter Debian geht das z.B so:
apt-get install php5-memcache
Jetzt muss das Projekt angepasst werden, ich habe mir folgende Funktionen gebaut:
function mpx_ses_open($path, $name)
{
}
function mpx_ses_close()
{
$memcache_obj = new Memcache;
$memcache_obj->addServer(’10.10.1.201′, 11211);
$memcache_obj->set(session_id(), $GLOBALS['__session'], false, 1200) or die (“Failed to save data at the server”);
}function mpx_ses_read($id)
{
$memcache_obj = new Memcache;
$memcache_obj->addServer(’10.10.1.201′, 11211);
$re = $memcache_obj->get(session_id());
return $re;
}function mpx_ses_write($id, $data)
{
$GLOBALS['__session'] = $data;
}function mpx_ses_destroy($id)
{
}function mpx_ses_gc($maxlt)
{
}
Eine weitere Funktion sorgt dafür, das PHP die Session Daten mit meinen eigenen Funktionen verwalten soll:
function get_session()
{
if (!isset($_COOKIE[session_name()]) && !isset($_GET[session_name()]))
{
$ses_id = str_replace(‘.’, ”, $_SERVER['REMOTE_ADDR']) . md5(time() . $_SERVER['REMOTE_ADDR']);
session_id($ses_id);
}
if (!session_set_save_handler (‘mpx_ses_open’, ‘mpx_ses_close’ , ‘mpx_ses_read’, ‘mpx_ses_write’, ‘mpx_ses_destroy’, ‘mpx_ses_gc’))
{
die(‘Set handling for WS sessioning failed…’);
}session_start();
};
Die Funktionen kann man bequem in eine externe Datei verlagern und includieren. Wenn man nun eine PHP Session benötigt kann man nachdem includieren einfach
get_session();
aufrufen und kann ganz normal PHP Sessions benutzen, jedoch werden diese jetzt per memcached verwaltet. Ich habe meine Funktionen hier etwas vereinfacht, damit man sie leichter kopieren kann. In unserm Fall wird z.B bei jedem Seitenaufruf eine Verbindung zu den Memcached Servern hergestellt, weswegen diese nicht erst in den Funktionen für die Session aufgebaut wird.
Related posts:
June 5th, 2007 on 16:21
Hallo
Zufälligerweise habe ich mich grade eben auch mit Memcache beschäftigt und bin über diesen Eintrag gestolpert.
Ich verstehe nun leider nicht, warum Du den Session-Client selbst geschrieben hast, anstelle die Variablen “session.save_handler=memcache” und “session.save_path=blablabla” zu benutzen.
Hat Deine Vorgehensweise einen Vorteil, den ich übersehen habe?
June 5th, 2007 on 16:29
Hi,
Ich habe mich für diesen Weg entschieden, weil der andere “einfache” Weg mir zu undokumentiert war und momentan auch noch ist. Die von mir / uns momentan genutzte Variante mit eigenen “Funktionen” lässt sich bei Fehlverhalten einfacher debuggen.
Ich denke beide Versionen haben aus persönlicher Sicht Vorteile, in Sachen Perfomance könnte die Variante per php.ini minimal schneller sein.
Mfg
June 6th, 2007 on 00:16
Ok, debuggen ist so ein Thema. Wenn man den memcache daemon nicht mit -vv startet, dann erscheint bei mir genau garnichts im logfile. Laufen tut er aber artig.
Magst Du Erfahrungswerte für die cachegröße nennen? Ich habe rund 30.000 visits jeden Tag und zunächst mal blind 128MB eingetragen. Langt das?
Hast Du dir auch schon ein Munin Plugin geschrieben? Ich habe in einem anderen post gesehen, dass Du munin verwenden zu scheinst.
Grüße
Sebastian
June 7th, 2007 on 01:02
Gute Frage, das kommt natürlich darauf an, wie viele Daten du ablegen möchtest.
Ich werde in meinem nächsten Projekt komplette Templates mit memcached cachen. Momentan verwende ich auf 2 Maschienen jeweils 4*128MB für http://www.morphex.eu. Diverse Querys werden wenn sie im memcached schon vorhanden sind nicht mehr aus der Datenbank ausgelesen.
Munin benutze ich momentan noch nicht zur Überwachung von memcached, auf deinen Anstoß hin werde ich mir nun aber mal anschauen, was da so möglich ist
Bisher habe ich die direkte Ausgabe der Debug Infos per PHP ab und an verwendet um zuschauen wie das Verhältnis Lesen/Schreiben ist.
June 9th, 2007 on 13:48
Hallo Simon
Ich habe auf der Munin Seite fertige Plugins für memcache gefunden.
Von dem neueren Skript funktionieren bei mir leider nur 2 der 3 Aufrufarten. Vielleicht hast Du ja mehr Glück.
Die 128MB haben bei mir bisher wunderbar ausgereicht für Session-Daten. Das Cachen von Datenbankabfragen überlasse ich eh MySQL.
Grüße
Sebastian
June 10th, 2007 on 11:20
Okay, dann werde ich mal gleich auf der Munin Seite nachschauen
Der Mysql Query Cache arbeitet leider nicht 100% gut bei uns. Ich habe mich vor einiger Zeit mal eingelesen in das Thema, anscheinend wird der Query bei jeder Änderung der Gesamt Tabelle aus dem Cache gelöscht, was bei einem Query alla “SELECT * FROM tabelle” ohne where oä ganz sinnvoll sein kann. Das Problem bei uns is das wir einige große Tabllen haben ( 400-500MB ) die sich mehrmals in der Sekunde ändern, wodurch der Query Cache quasi nutzlos wird, wenn ich meinen eigenen Memcached Cache nutze, entscheide ich per gecachtem Datensatz, wann dieser gelöscht bzw neu aus der Datenbank eingelesen wird.
mfg