Von der Firmware besiegt

Heute Morgen rief mich ein alter Bekannter aus Uni-Zeiten an: Er ist mittlerweile bei einem Unternehmen beschäftigt, die Kunden in Deutschland eine bestimmte Webapplikation bereitstellen. Und der Grund seines Anrufs war pure Verzweiflung, denn besagte Applikation war mehr oder weniger down, weswegen er mich um Hilfe beim Debugging gebeten hat.

Fangen wir mal mit einem Überblick über den Aufbau an: Die Server für die Applikation stehen in drei Rechenzentren, namentlich Berlin, Frankfurt und Nürnberg. Diese Rechenzentren haben die üblichen Redundanzen für IP, Strom, Klima etc. An jedem Standort gibt es vier Arten von Servern:

  • Web-/Applikationsserver: Nichts spektakuläres hier, ein ganz normaler Apache-Tomcat-Stack. Verteilt wird die Last von zwei Loadbalancern pro Rechenzentrum, die Tomcat-Cluster können dem LB signalisieren, für welche Arten vom Operationen sie zur Verfügung stehen.
  • Zwei Storage-Server: Diese stellen Speicherplatz für die Server im lokalen Rechenzentrum bereit. Die Applikation (genauer: das Persistenz-Framework) üerbnimmt hier das Clustering. Sie prüft regelmäßig, ob beide Server verfügbar sind und lässt die Finger von einem Server, der kaputt ist. Sind beide Server wieder verfügbar, so repliziert sie die Änderungen auf den Server, der ausgefallen war. Eine weitere Ebene des Applikations-Frameworks kümmert sich auch um die Replikation von Änderungen zwischen den verschiedenen Standorten. Fallen an einem Standort beide Knoten aus, so signalisieren die Applikationsserver dem Loadbalancer, daß sie für Aktionen, die Filesystem-Zugriffe benötigen, nicht zur Verfügung stehen.
  • Cassandra-Knoten: Auch hier nichts besonderes, die Replikation unter den Knoten läuft bei Cassandra ja bekannt unspektakulär. Für den Ausfall aller Cassandra-Instanzen an einem Standort gilt das gleiche wie bei den Fileservern.
  • PostgreSQL-Cluster: Für einige Teile der Applikation braucht man ein echtes RDBMS - hier kommt PostgreSQL zum Einsatz. Die Applikation repliziert Änderungen auf je einen PostgreSQL-Knoten pro Standort, dieser repliziert die Änderungen dann auf jeweils drei Slaves. Steht an einem Standort kein PostgreSQL-Server mehr zur Verfügung deaktiviert sich die Applikation an diesem Standort.

Die Architektur hier gefällt mir ziemlich gut, man kann laut meinem Bekannten erfahrungsgemäß über zwei Drittel der Server abschießen, ohne daß alles stehen bleibt. Normalerweise. Heute Nacht hat die Applikation dann begonnen, neue Datensätze nicht mehr korrekt zu verarbeiten. Nach einer kurzen initialen Diagnose hat sich herausgestellt, daß die PostgreSQL-Replikation Schuld war: Auf den Slaves kamen Datensätze an, deren Primärschlüssel bereits vorhanden war. Wer sich mit Datenbanken ein bißchen auskennt, weiß, daß das der absolute Super-GAU ist - und eine Situation, die so eigentlich niemals passieren dürfte. Man kann das gut mit diesem Bild hier beschreiben. Leider haben die Jungs auch nach stundenlangem Debuggen nicht herausgefunden, was das Problem ist. Schlimmer noch, die Fehler betrafen nicht mehr nur die Replikation von den Mastern auf die Slaves, auch die Master untereinander begannen, voneinander abzuweichen.

Gott sei Dank loggt diese Firma wirklich alles, was sie tun. Ich konnte das Problem nach knapp einer Stunde auf ein Update der RAID-Controller-Firmware zurückführen: Diese hatte die Schreibzugriffe zwar bestätigt, aber nichts geschrieben. Der Fehler tritt anscheinend auch nur bei spezifischen Zugriffsmustern auf - war halt mal wieder Pech. Nach einem Downgrade, und einem Restore lief alles wieder so, wie es sollte. Manchmal fragt man sich schon, was die Hersteller von “Markenhardware” sich so den lieben langen Tag denken…