Uptime - Wie wichtig Backups und gutes Monitoring sind

30. May 2012. Tagged tools, experience, work.

Tja, am Wochenende hatten wir eine ziemlich ungute Situation. Die Datenbank hatte einen Schluckauf und ich war unterwegs und niemand hat wirklich gründlich versucht mich zu erreichen. Vielleicht wurde es auch versucht, und es hat nicht geklappt. So genau lässt sich das nicht mehr sagen.

Fest steht, dass die Seite etwa 16 Stunden nicht erreichbar war, naja, viel schlimmer. Sie war zwar erreichbar, aber die Webseite hat furchtbar ausgesehen, da das Layout aufgrund der Datenbankmängel nicht richtig funktionierte und aus dem selben Grund konnte sich niemand einloggen, was natürlich zu Panik führte. Wenn stattdessen wenigstens eine statische Notfall.html platziert worden wäre. Naja, wäre. So viel dazu.

Das Ergebnis war dann, dass das Backup von Tag zuvor eingespielt werden musste (wenigstens das gab es, vielen Dank an den Hoster) und ein Haufen Daten weg waren. Aber das ist natürlich eine enorm blöde Situation.

Was man im Fall von Downtime und Datenbankausfällen tun kann

Wichtig ist es sich nicht im Nachhinein darüber zu ärgern. Das ganze ist gelaufen und man kann nichts daran ändern. Ich denke wir haben eine Menge für die Zukunft daraus gelernt, auch wenn ich unglücklicherweise nicht in der Lage war herauszufinden, wie das Ganze zu Stande gekommen ist. Um so wichtiger war mir, in Zukunft schnell reagieren zu können.

Datenbankbackups

Ich persönlich fand, dass ein Tag Datenverlust im schlimmsten Fall einfach zu viel ist. Darum wird von runwhen jetzt stündlich folgendes Script ausgeführt:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
NOW=$(date +"%m-%d-%Y") # mm-dd-yyyy format
BAJ="/home/<username>/mysqldumps"
BAK="${BAJ}/${NOW}" # Path to backup dir on $NAS

# mysql user
MUSER="<mysqluser>"
 
# mysql Pass
MPASS="<mysqlpass>"

# mysql host
MHOST="127.0.0.1"

# make sure that the backup path exists
if [ ! -d $BAK ]; then
  mkdir -p $BAK
fi
 
# get either all the databases or specify a list manually
DBS="$(mysql -u $MUSER -h $MHOST -p$MPASS -Bse 'show databases')"

# dump databases
for db in $DBS
do
 FILE=$BAK/mysql-$db.$NOW-$(date +"%T").gz
 # gzip compression for each backup file
 mysqldump -u $MUSER -h $MHOST -p$MPASS $db | gzip -9 > $FILE
 cp $FILE $BAJ/$db-latest.gz
done

Damit haben wir im schlimmsten Fall ab sofort immer ein maximal 60 Minuten altes Backup. Jetzt könnte man sich fragen, wieso in der vorletzten Zeile eine zweite Version in $BAJ/$db-latest.gz abgelegt wird, das ist nachher für das Monitoring von wichtiger Bedeutung.

Monitoring

Naja, jetzt hat man zwar immer ein aktuelles Backup, aber was nützt es einem, wenn man trotzdem 16 Stunden weg ist? Also habe ich mir ein Monitoring-Tool gesucht und bin aufgrund ausgreifender Konfigurationsmöglichkeiten und einfachem Setup auf monit gestoßen.

Wichtig ist es auf der Seite monit nicht mit m/monit zu verwechseln, das man braucht um mehrere monit-Instanzen übersichtlich gleichzeitig zu betrachten und kostenpflichtig ist, während monit gratis ist.

Runtergeladen, mit den daemontools eingerichtet und jetzt zur Konfiguration. Das wichtigste beim Monitoring ist es wirklich sinnvolle Kriterien zu definieren, die nicht bei jeder Kleinigkeit sofort losschlagen, aber auch nicht still sind, wenn es zur Katastrophe kommt. Außerdem sollte man sich genau überlegen, was man eigentlich überwachen will. Und dann sollte man sich überlegen, welche Maßnahmen das Tool dann ergreifen soll. Monit kann in solchen Fällen benachrichtigen, Skripte ausführen und viele andere Dinge.

Ich habe verschiedene Sachen beschlossen. Zunächst ein mal die Last allgemein auf dem Server. Ist denke ich wichtig, denn wenn die Last all zu hoch steigt, dann steht zu befürchten, dass sich auch auf der Website Probleme ergeben. Des Weiteren checkt das Tool ob die MySQL-Backups aktuell sind (siehe die spezielle Kopie im Backupscript). Ist der Timestamp der Dateien älter als 65 Minuten (um kleinere Verzögerungen auszuschließen), benachrichtigt das Tool mich und ich kann es überprüfen.

Anders verhält es sich bei dem Status der Website. Monit bietet auch die Möglichkeit den Status eines HTTP-Hosts zu prüfen (auch SSL wird unterstützt). Mein Monit macht genau das. Allerdings ist auch hier eine gewisse Toleranz gewährleistet. Kleinere Ausfälle kommen bei Server Neustarts vor, und ich will nicht von jedem wissen. Bekommt Monit bei 5 Versuchen in 5 Minuten niemals ein 200 vom Webserver (was so viel heißt wie OK), dann benachrichtigt es mich.

Aber nicht nur das: Es installiert auch eine statische Notfall.html mit Kontaktdaten und ähnlichem. Sollte der Webserver selbst sich verabschiedet haben, nützt das natürlich nicht viel, liegt es allerdings an der Datenbank o.ä. sind wir schon wieder einen Schritt weiter.

Zusätzlich benachrichtigt monit nicht nur mich, sondern auch ein paar Mitarbeiter und fügt eine Nachricht mit hilfreichen technischen Details an den Hoster an, so dass diese Mail einfach weiter geleitet werden kann, sollte ich nicht erreichbar sein. Dann kümmert sich zumindest irgendjemand drum.

Nachdem ich benachrichtigt wurde, misst das Tool aber weiter. Sobald es wieder ein 200 bekommt, entfernt es wieder die Notfall.html und die normale Webseite tritt an ihre Stelle. So viel zu (hoffentlich) gutem Monitoring.

Zur Sicherheit überprüfe ich noch die Checksums von ein paar .phps der Seiten um sicher zu gehen, dass da nicht aus Versehen (oder extra von einem Hacker o.ä.) eine Änderung vorgenommen wurde.

Ihr seht also, ich bin für viele Fälle gewappnet, wenn auch lange nicht für alles für das ich gerne gewappnet wäre. Auf jeden Fall stehen wir jetzt wesentlich besser da als vorher und ich hoffe, dass wir das richtige aus dem Ganzen gelernt haben.

Und zur Illustration noch ein Screenshot von meinem Monit:

Monit in Aktion

Praxis

Zur Deko füge ich noch ein paar Auszüge aus meiner .monitrc ein, die interessant sein könnten:

Folgender Code überprüft ob eine Datei älter als eine Stunde ist oder die Datei sehr klein ist (was auf einen Fehler hindeutet), und benachrichtigt mich, wenn ja:

1
2
3
4
5
check file mysql_backup
  with path /home/notube/mysqldumps/database-latest.gz
  if timestamp > 65 minutes then alert
  if size < 1 MB then alert
  group backup

Folgender Code benachrigt mich, wenn der Webserver nach 5 Versuchen in 5 Minuten kein 200 ausgegeben hat, installiert eine Notfall.html und entfernt sie wieder, wenn es wieder zu gehen scheint.

1
2
3
4
5
6
7
8
9
10
check host homepage with address www.homepage.com
  if failed host www.homepage.com
    port 80
    protocol http 
    and request "/index.php"
    with timeout 40 seconds
    5 times within 5 cycles
      then exec "/home/<user>/bin/rescue/public-http"
  else if succeeded
      then exec "/home/<user>/bin/unleash/public-http"

Und hier das ganze nochmal für SSL:

1
2
3
4
5
6
7
8
9
10
11
check host internal with address www.homepage.com
  if failed host www.homepage.com
   port 443 
   type tcpssl
   protocol http
   and request "/index.php"
   with timeout 40 seconds
   5 times within 5 cycles
     then exec "/home/<user>/bin/rescue/public-http"
  else if succeeded
     then exec "/home/<user>/bin/unleash/public-http"

Das Monitoring von generellen Systemparametern wie load usw. ist in der default .monitrc schon aktiviert, deswegen gibt es hier kein Beispiel dazu.

Wenn man root hat kann man noch viele Sachen mehr überwachen, wie Prozesse usw. und diese auch automatisch neustarten u.ä.. Leider ist mir diese Macht nicht gegeben, aber man kann nicht alles haben.

Für alle die mehr wollen: Die Monit Doku kennt noch viele praktische Checks und Optionen.