Foto: Intricate Explorer, Unsplash
Heute erinnerte ich mich an einen meiner Lieblings- "Programmiermythen", der möglicherweise eine urbane Legende ist, und an meine eigene Version der "Black Box", die ein Debugging erforderte.
Die städtische Legende erzählt von radioaktiven Eisenbahnwaggons aus der Ukraine, die Fehler im Computersystem verursacht haben. Sie können sie hier lesen .
Wir beschäftigen uns mit den "Black Boxes" und mit dem, was sie heute sind
Eine Black Box ist ein beliebtes Programmierkonzept, bei dem davon ausgegangen wird, dass wir uns außerhalb eines Systems oder einer Komponente befinden und keinen direkten Zugriff auf den Code haben. Dies kann durch verschiedene Faktoren verursacht werden:
- Sie arbeiten mit Software von Drittanbietern, deren Entwickler den Code einfach nicht offenlegen.
- Sie interagieren mit einer API, deren interne Logik abstrahiert ist.
- Sie haben nicht die erforderlichen Berechtigungen, um auf das Git-Repository zuzugreifen.
- Selbst ein System mit vollem Zugriff kann aufgrund seiner Komplexität de facto zu einer Black Box werden.
- Ein Mitarbeiter, der alle Schlüssel und Kenntnisse besaß, wird plötzlich kündigen / verschwinden / sterben.
- Das Legacy-System besteht aus einer DLL, die auf dem Server "immer funktioniert" hat und nicht mit einem Versionskontrollsystem verbunden war. Um nur den Code zu betrachten, müssen Sie ihn natürlich, wenn möglich, dekompilieren.
All diese Faktoren laufen darauf hinaus, dass wir ein Problem haben, das wir nicht sofort beheben können, und wir wissen nicht, was der Fehler ist. Deshalb müssen wir uns an die Arbeit machen.
Unser eigenes Problem war eine Kombination aus all dem
Die oben aufgeführte Liste der Faktoren deckt wahrscheinlich nicht alle Situationen ab, da es sich um eine direkte Liste der Faktoren handelt, die unsere Situation beeinflusst haben. Wir hatten gerade einen Entwickler entlassen, ein komplexes System, das auf mehrere Server verteilt war, mit einer Kern-DLL, die „ihre Arbeit erledigt hat“, obwohl niemand wusste, warum oder welches.
Es wurden Dienste von Drittanbietern aufgerufen, es gab praktisch keine Anmeldung, und die einzigen Sicherungen, die wir hatten, waren die Speicher im Dateisystem mit dieser DLL
und ohne Code. Wie Sie verstehen können, konnte nichts davon beibehalten werden, und sie planten, das System zu gegebener Zeit neu zu schreiben, aber der Fehler war dringend und musste behoben werden.
Wir können sagen, dass das System die meiste Zeit fast vollständig mit der Arbeit fertig wurde, und wir könnten Teillösungen für das Problem in Kauf nehmen, wenn sie Konsistenz zeigten. Es stellte sich jedoch heraus, dass ungefähr jeder hundertste Datensatz falsche Ergebnisse lieferte, und das einzige, was wir tun konnten, war, sie von außen zu debuggen (jetzt erinnern wir uns mit einem Lächeln daran).
Dies ist eine dieser Zeiten, in denen ich für die chaotische Welt, in der ich aufgewachsen bin, dankbar war, weil die meisten Unternehmen nicht mit so ernsten Problemen konfrontiert werden und keinen neuen Absolventen ernennen werden, um sie zu lösen. In diesem Sinne hatte ich Glück und noch mehr Glück, denn ich hatte die Unterstützung erfahrener Entwickler, die mir während des gesamten Prozesses geholfen haben. Das war also unsere Lösung.
Wir reproduzieren den Fehler (idealerweise in mehreren Testfällen)
Sobald Sie wissen, was der eigentliche Fehler ist, ist das Problem fast gelöst, aber es kann unglaublich schwierig sein, ihn zu erreichen, wenn der Fehler unregelmäßig auftritt. Denken Sie noch einmal über das Zugbeispiel nach - wenn es nicht möglich wäre, das Muster zu identifizieren, wäre der Grund fast unmöglich zu finden. Denn das ist es, wonach wir in einer solchen Situation suchen - das Muster, wann ein Fehler auftritt.
In unserem Fall fanden wir es relativ einfach: Wir kannten die Art des Fehlers und er trat wiederholt auf, aber so selten, dass wir viele Male brauchten, um den Suchraum für Fälle einzugrenzen und ihre Logik aufzudecken.
Nachdem wir viele Testfälle identifiziert haben, die regelmäßig zu Fehlern führen, können Sie mit dem Debuggen beginnen. Hier ist ein Beispiel für einen anderen Prozess, bei dem wir die Suche nach der Ursache des Problems durch übereinstimmende Muster eingegrenzt haben: Eines der Systeme hing jeden Donnerstagabend, und die Protokolldateien enthielten nichts Seltsames:
- Wir wussten, dass unser System keine Fehlermeldungen ausgab, aber es hing.
- Wir haben Fälle verglichen, bis wir sicher waren, dass das Problem am Donnerstag und an keinen anderen Tagen aufgetreten ist.
- Wir haben überprüft, dass für diese Zeit keine automatischen Updates geplant sind, und alle automatisierten Aufgaben überprüft, die auf demselben Server ausgeführt werden - nichts.
- Wir haben uns angesehen, was das System auf Metaebene tat, und es auf ein Zeitlimit für gemeinsam genutzte Festplatten eingegrenzt, auf das alle zwei Wochen von einer Festplattenbereinigungsaufgabe zugegriffen wurde, die auf einem völlig anderen Server ausgeführt wurde, während unser Dienst ausgeführt wurde. Niemand dachte, dass beide um drei Uhr morgens anfingen zu starten.
Erstellen Sie eine Testumgebung (auch wenn es sich um eine Produktion handelt).
Sobald Sie eine Reihe von Fehlern haben, können Sie mit der Arbeit an der wahren Ursache und Lösung beginnen, für die ein Testsystem erforderlich ist.
Damit meine ich, dass Sie zwei Konstanten benötigen:
- Die verwendeten Daten sollten von anderen Systemen nicht geändert werden
- Mögliche Schäden sollten so weit wie möglich begrenzt werden
In unserem Fall konnten wir die Fehler auf dem Testserver nicht reproduzieren. Dies war offensichtlich, da sich die DLL-Bibliothek in einem völlig anderen Zustand befand als der Server in der Produktion. Die Rückkehr in diesen alten Zustand funktionierte nicht, weil andere ebenso wichtige Elemente zerstört wurden.
Also kamen wir zusammen und stellten die Frage: "Was ist das Schlimmste, was passieren kann, wenn wir das vermasseln?" Und schrieben dann ein Datenbankskript, das alle Ergebnisse in einen Fehlerzustand umschreibt, damit nachfolgende Systeme sie nicht verarbeiten.
Es war beispielsweise möglich, Server und Aufgaben zu trennen, den nächsten logischen Schritt aus dem Prozess zu entfernen und dergleichen, aber die Möglichkeit hierfür hängt von der Architektur eines bestimmten Systems ab.
Vergleichen Sie die Eingabedaten, um Ähnlichkeiten und Unterschiede mit den Arbeitsdatensätzen festzustellen
Obwohl wir nicht herausfinden können, was der Code im Fall einer "Black Box" genau tut, war es möglich, eine Art "Reverse Engineering" durchzuführen, das häufig ein gutes Verständnis der Ursachen von Problemen vermittelt.
In unserem Fall hatten wir den Luxus, einigermaßen gut formatierte JSON-Dateien aus dem vorherigen System zu verwenden, von dem unsere Eingabe abhing. Nachdem wir alles eingerichtet hatten, blieb es buchstäblich, einige Textdateien in Notepad ++ zu vergleichen, bis wir die Ähnlichkeiten zwischen den Dateien fanden, die die Fehler verursachten, und dann die Unterschiede zwischen ihnen und den korrekt funktionierenden Dateien.
Wir hatten hier Glück - wir konnten schnell herausfinden, dass der Fehler eine bestimmte Kombination von Kundenflags verursachte, und wir haben es sofort geschafft, diese zu umgehen, da dieser Fall mit ähnlichen, aber unterschiedlichen Flags "nachgeahmt" werden konnte. Da wir bereits wussten, dass das System neu geschrieben werden würde (tatsächlich hatten wir keine Wahl), wurde beschlossen, diesen Fehler zu umgehen, anstatt ihn zu dekompilieren und zu beheben.
Ändern Sie die Eingabe, um sicherzustellen, dass unsere Vermutung zu den erwarteten Ergebnissen führte (und den Schaden begrenzt).
Natürlich ist es eine schlechte Idee, Live-Daten in einer Datenbank in der Produktion zu ändern, in der Hoffnung, dass alles ohne echte Tests funktioniert, aber wir hatten keine andere Wahl.
Es hat großartig funktioniert, weil die Anzahl der Fälle gering war und die ersten Tests, die wir manuell durchgeführt haben, genau das waren, was wir wollten.
Am Ende haben wir nur eine weitere automatisierte Aufgabe geschrieben, um diese Probleme zu beheben, bevor sie auf das System kamen, und dann ein dreimonatiges Projekt gestartet, um dieses Programm von Grund auf neu zu schreiben, diesmal transparent, mit Versionskontrolle und Build-Pipelines.
Hier ist ein Abenteuer.
Fazit: Sie können viel über das System lernen, auch wenn Sie nur herumlaufen und es mit einem Stock stechen
Ich bin begeistert von dieser Art des Debuggens und Auffindens von Fehlern. Ich liebe es, wenn Programmieren mit einem Adrenalinstoß kombiniert wird.
Wenn Sie das Video zur SQL-Injection und zum Reverse Engineering der Datenbank bei Fehlermeldungen nicht gesehen haben, empfehle ich dringend , es anzuschauen . Die in diesem Video verwendeten Techniken sind fast identisch mit denen, die für nicht böswilliges Debuggen verwendet werden können.
Werbung
Sofort bestellen und arbeiten! Erstellung eines VDS für jede Konfiguration innerhalb einer Minute, einschließlich Servern zum Speichern großer Datenmengen bis zu 4000 GB. Episch :)
Abonnieren Sie unseren Chat auf Telegramm .