Zabbix Webseitenperformance Realtime-Monitoring

Webseitenrealtimemonitoring

Die Grenzen von Webscenarien und Regressionstest

Mit zwei kleinen Hilfsscripten ist Zabbix in der Lage, Webseiten in Realtime zu monitoren. Sie sehen auf Graphen wie viele Kunden auf Ihrer Webseite sind, was diese Kunden gerade tun, welchen Umsatz Sie machen etc.

Diese Informationen sind nicht nur zu statistischen Zwecken sinnvoll, sondern auch um Fehler in Ihrer Webseite und der dahinter liegenden Applikation zu entdecken. Bricht der der Besucherstrom schlagartig ab, ist dies oft der Hinweis auf einen Apllikationsfehler.

Das Prüfen der Verfügbarkeit von Webseiten ist nur ein Teil von Webseitenmonitoring. Die Webscenarien von Zabbix oder auch andere Tools zum Testen von Webseiten wie Selenium können keine hundertprozentige Sicherheit geben, dass Ihre Webseite ordnungsgemäß funktioniert.

Stellen Sie sich vor, ein Graphiker ändert den finalen "Jetzt-Kaufen-Button" und stellt weiße Schrift auf einen weißen Hintergrund. Die Conversion-Rates werden einbrechen. Zabbix aber wird Ihnen melden, dass die Seite ordnungsgemäß funktioniert.

Was ist Realtimemonitoring

Jeder Klick bzw. jede Page-Impression wird gezählt und von Zabbix ausgewertet. Zabbix beobachtet und registriert dann die Zugriffe pro Sekunde/Minute pro Seite oder Seitengruppe.

Aber auch wie oft Conversionelemente wie Kaufabschlüsse, Newsletterregistrierungen o. Ä. pro Zeiteinheit werden gemessen. Weichen die gemessenen Werte von definierten Schwellenwerten ab, können Sie sich benachrichtigen lassen.

Fehler wie das oben beschriebene Beispiel können Sie mit solch einer Art Monitoring aufdecken.

Pageimpressions messen

das Prinzip

Das Prinzip zur Messung aller Pageimpressions ist denkbar einfach. Ähnlich wie die Performance-Counter von MySQL oder Apache wird pro URL oder URL-Gruppe bei jedem Seitenaufruf ein Zähler um Eins erhöht.

Zabbix bildet zum Beispiel alle 60 Sekunden die Differenz der letzten beidem Messungen und so ergeben sich die Pageimpressions pro Minute.

Einen solchen Zähler können Sie mit jeder Programmiersprache mit wenigen Zeilen Code realisieren. Im folgenden Beispiel wird PHP verwendet, wobei der Zähler komplett im Arbeitsspeicher liegt, so dass so wenig wie möglich Last auf dem Zählserver erzeugt wird.

PHP und APC installieren

APC wird im folgenden Beispiel sowohl als Key-Value-Store im Arbeitsspeicher als auch als Opcode-Cache verwendet. Das Zählscript wird also nicht bei jedem Aufruf vom PHP-Interpreter kompiliert, und muss auch nicht bei jedem Aufruf eine Datei öffnen und schließen oder eine Datenbankverbindung verwalten.

APC bringt bereits alle Funktionen mit um einen hochperformanten Zäher zu implementieren.

Installieren Sie über den Paketmanager einen Webserver und aktivieren Sie die PHP-Unterstützung.

Wenn Sie mit sehr vielen Pageimpressions zählen wollen sollten Sie zu Lighttpd oder Nginx anstatt Apache greifen. Schalten Sie das Access-Log des Webservers aus, da es unnötige IO-Last erzeugt. Im Lighttpd kommentieren Sie dazu das Laden des Moduls mod_access und die Pfadangabe zum Logfile in der Datei /etc/lighttpd/lighttpd.conf aus.
aptitude install lighttpd php-5 php5-cgi php5-dev php-pear libpcre3-dev gcc make curl

Installieren Sie dann APC per Pecl

pecl install apc

Die zwei Fragen, die pecl während der Installation stellt, können Sie einfach mit Enter beantworten.

Installieren Sie unter Debian Lenny nicht das APC-Debian-Paket. Dieses ist zu alt! Die benötigte Function apc_inc() ist in dieser alten Version noch nicht enthalten.

Aktivieren Sie die APC-Extension mit

echo "extension=apc.so">/etc/php5/cgi/conf.d/apc.ini

und starten Sie den Webserver neu.

Tracker-Script anlegen

Ein Tracker-Script könnte zum Beispiel so aussehen:

<?php
/*
 tracker.php
 Increments a counter for each submitted URL.
 URL are typically summited by a javascript xhmtl-request (ajax call)
 from within any website you like.
*/

$url = inputfilter($_GET['url']); 

// Add the whole URL to the counter
$counter_keys[] = $url;
// Example: Build a group
if(preg_match("/add_to_shoppingcard\?/",$url))
{
	$counter_keys[] = 'SHOPPING_CARD_STEP_1';
}
// Example: Submit the group of the Website directly from the site to be counted
if(isset($_GET['g']))
{
	$url_group = inputfilter($_GET['g']);
	$counter_keys[] = $url_group;
}
// push all counter_keys to the APC-cache store,
// if the counter_key alread exists it will be incremented 
foreach($counter_keys as $counter_key)
{
	
        // Try to increment an existing key
	if( ! apc_inc($counter_key))
	{
                // Create a new counter, if not exists
		apc_add($counter_key,1);
		// Add the key to an array with all counter_keys because
		// apc does not provide any method the read its content recursivly
		$inventory = apc_fetch('inventory');
		$inventory[] = $counter_key;
		apc_store('inventory',$inventory);
	}
}

// Filter the input for your needs.
function inputfilter($input)
{
	
	$input = strip_tags($input);
	$input = addcslashes($input,';.,');
	return $input;
}

Über die Funktion apc_inc() wird ein Zähler im APC Cache erhöht. Schlägt das Erhöhen fehl, weil der Zähler noch nicht existiert, wird dieser mit apc_add() angelegt.

Da es keine Möglichkeit gibt, den APC-Cache rekursiv auszulesen, müssen wir Buch darüber führen, welche Zähler sich im Speicher befinden. Dazu wird das Array inventory gepflegt. Jeder neue Zähler wird zu diesem Array hinzugefügt.

Tracker aufrufen

Fügen Sie nun am Ende auf jeder Seite, die Sie tracken möchten, folgenden Javascript-Codeblock ein.

<script type="text/javascript">
window.onload = track()
function track() {
    var g = 0; // Set a group for this page
    if      (window.XMLHttpRequest) { var r = new XMLHttpRequest();                   } // nearly all
    else if (window.ActiveXObject)  { var r = new ActiveXObject("Microsoft.XMLHTTP"); } // IE6
    r.open("GET", 'tracker.php?url='+window.location+'&g='+g, true); // Replace correct tracker URL
    r.send(null); }
</script>

Alternativ können Sie auch einen Javascript-Include verwenden.

<script src="/tracker.js"></script>

Zabbix Items einrichten

Tracker auslesen

Mit folgendem Script können Sie die Werte des Trackers auslesen:

<?php
/*
 counter.php
 Script to read the values and all contents of your counter
*/
// Restrict access
if($_SERVER['REMOTE_ADDR'] != '127.0.0.1' ) die('not allowed.');
// Print out a specific counter
$key = $_GET['key'];
echo apc_fetch($key);
// Print all keys and values from the inventory
if(isset($_GET['INVENTORY']))
{
	$inventory = apc_fetch('inventory');
	foreach($inventory as $key)
	{
		echo $key.":".apc_fetch($key)."<br>";
	}
}

Testen Sie den Tracker zum Beispiel mit

curl http://127.0.0.1/counter.php?INVENTORY

Userparamter im Zabbix-Agenten einrichten

Fügen Sie einen UserParamter zur Konfiguration des Agenten hinzu, der so aussehen könnte:

UserParameter=tracker.counter[*],UserParameter=tracker.counter[*],curl http://127.0.0.1/counter.php?key=$1

Den im Zabbix-Agenten integrierten HTTP-Client web.page.get[] kann man leider nicht verwenden, weil dieser Neben dem Inhalt der Webseite auch die Header zurück liefert. Der Zabbix-Server muss den Wert aber als Numeric interpretieren und darf deshalb als Rückgabe nur eine Zahl bekommen.

Items einrichten

Stellen Sie sicher, dass auf dem Tracker-Server ein Zabbix-Agent läuft.

Mit einem Item vom Typ tracker.counter[<counter_key>] können Sie nun die Zähler an Zabbix übergeben. Zum Beispiel

tracker.counter[www.testpage.de]

Tracker item.png

Testen und Tunen

Testen Sie den Tracker mit dem Apache-Benchmar-Tool, welche massenhafte Zugriffe simulieren kann.

ab -n 200000 -c 10 http://url_of_your_tracker/tracker.php?url=www.testpage.de

Damit werden 10 parallele Verbindungen aufgebaut und 200.000 Requests "abgefeuert".

Erhöhen Sie die Anzahl der parallelen Verbindungen und die Anzahl der Requests, bis Sie die zu erwartende Anzahl von Requests erreicht haben.

Wenn Der Tracker alle Anfragen beantworten konnte, dann ist Ihr Trackingserver jetzt einsatzbereit.

Beobachten Sie das Errorlog Ihres Webservers.

(mod_fastcgi.c.2900) backend is overloaded; 
we'll disable it for 2 seconds and send the request to another backend instead: 
reconnects: 0 load: 267 

Finden Sie solche Meldungen von Lighttpd sollten Sie die Anzahl der Fastcgi-Backends erhöhen.

Je nach Anzahl der Requests wird ggf. ein Server nicht reichen.

Tracker graph.png