Übung 1.3 Problembehandlung bei einem Absturzproblem – Erfassen der wichtigsten Absturzabbilder mit dem tool createdump
Gilt für: .NET Core 2.1, .NET Core 3.1, .NET 5
In diesem Artikel wird erläutert, wie Sie mit dem Tool createdump .NET Core-Absturzabbilddateien in Linux erfassen und dann lldb verwenden, um das Absturzproblem zu diagnostizieren.
Voraussetzungen
Die Mindestanforderung für die Durchführung dieser Problembehandlungslabore besteht darin, über eine ASP.NET Core-Anwendung zu verfügen, um Leistungsprobleme mit geringer CPU- und hoher CPU-Leistung zu demonstrieren.
Sie finden mehrere Beispielanwendungen, um dieses Ziel im Internet zu erreichen. Sie können beispielsweise das einfache Webapi-Beispiel von Microsoft herunterladen und einrichten, um unerwünschtes Verhalten zu demonstrieren. Alternativ können Sie auch ASP.NET Core Anwendung als Beispielprojekt verwenden.
Wenn Sie die vorherigen Teile dieser Reihe befolgt haben, sollten Sie das folgende Setup bereit haben:
- Nginx ist so konfiguriert, dass zwei Websites gehostet werden:
- Der erste lauscht auf Anforderungen mithilfe des Hostheaders "myfirstwebsite" (
http://myfirstwebsite) und Routinganforderungen an die Demo ASP.NET Core Anwendung, die auf Port 5000 lauscht. - Der zweite lauscht auf Anforderungen mithilfe des hostsamb-Hostheaders (
http://buggyamb) und Routinganforderungen an die zweite ASP.NET Core Beispielanwendung, die auf Port 5001 lauscht.
- Der erste lauscht auf Anforderungen mithilfe des Hostheaders "myfirstwebsite" (
- Beide ASP.NET Core Anwendungen sollten als Dienste ausgeführt werden, die automatisch neu gestartet werden, wenn der Server neu gestartet wird oder die Anwendung nicht mehr reagiert.
- Die lokale Linux-Firewall ist aktiviert und so konfiguriert, dass SSH- und HTTP-Datenverkehr zulässig ist.
Hinweis
Wenn Ihr Setup noch nicht bereit ist, wechseln Sie zu"Teil 2 Erstellen und Ausführen ASP.NET Core Apps".
Um diese Übung fortzusetzen, benötigen Sie mindestens eine problematische ASP.NET Core Webanwendung, die hinter Nginx ausgeführt wird.
Ziel dieser Übung
Automatisch generierte Kernabbilddateien sind nicht nützlich, da sie nicht alle Verwalteten Statusinformationen enthalten. Das empfohlene Tool zum Erfassen von .NET Core Core-Absturzabbilddateien wird erstelltump.
In diesem Teil erfahren Sie, wie Sie eine Absturzabbilddatei mithilfe von createdump erfassen und die Datei in lldb öffnen, um das Absturzproblem zu diagnostizieren.
Konfigurieren von createdump für die Ausführung beim Beenden des Prozesses
Createdump wird automatisch zusammen mit jeder .NET Core-Laufzeit installiert.
Wie in der Dokumentation zur createdump-Konfigurationsrichtlinie erläutert, können Sie Konfigurationsoptionen mit Umgebungsvariablen festlegen. Diese werden als Parameter an den "createdump"-Befehl übergeben. Die folgenden Umgebungsvariablen werden unterstützt:
COMPlus_DbgEnableMiniDump: Wenn der Wert auf 1 festgelegt ist, wird die automatische Generierung des Kernabbilds nach Beendigung aktiviert. Der Standardwert ist 0.COMPlus_DbgMiniDumpType: Dies ist der Typ der Miniabbilddatei, die erstellt wird. Der Standardwert hierfür ist 2 (oder ein Enumerationstyp vonMiniDumpWithPrivateReadWriteMemory). Dies bedeutet, dass die generierte Abbilddatei die GC-Heaps und die erforderlichen Informationen enthält, um Stapelüberwachungen für alle vorhandenen Threads in einem Prozess zu erfassen.COMPlus_DbgMiniDumpName: Falls festgelegt, verwenden Sie diese als Vorlage, um den Pfad und den Dateinamen der Speicherabbilddatei zu erstellen. Die PID kann mithilfe des Parameters in den Namen eingefügt%dwerden. Die Standardvorlage ist /tmp/coredump.%d . Mithilfe dieser Umgebungsvariablen können Sie das Ausgabeverzeichnis konfigurieren.COMPlus_CreateDumpDiagnostics: Aktiviert bei 1 die Diagnosemeldungen des Tools "createdump" (TRACE-Makro). Diese Einstellung kann hilfreich sein, wenn createdump nicht wie erwartet funktioniert und keine Speicherabbilddatei generiert.
Details zu diesen Variablen finden Sie in der createdump-Konfigurationsrichtlinie.
Die wichtige Variable ist hier COMPlus_DbgEnableMiniDump . Sie müssen diese Umgebungsvariable auf 1 festlegen. Es gibt mehrere Methoden zum Festlegen dieser Umgebung:
- Legen Sie es in der Konfigurationsdatei Ihrer Anwendung fest.
- Verwenden Sie den
export COMPlus_DbgEnableMiniDump=1Befehl, um ihn festzulegen. Diese Einstellung wird nach einem Neustart des Betriebssystems nicht beibehalten. Daher müssen Sie sie als beständig festlegen, wenn Sie die Einstellung nach einem Neustart aktiviert lassen möchten. - Legen Sie ihn in der ASP.NET Core Diensteinheitsdatei fest.
Das Festlegen dieser Variablen in ASP.NET Core Diensteinheitsdatei ist die einfachste Methode. Der Nachteil ist, dass der Dienst neu gestartet werden sollte. In diesem Abschnitt zur Problembehandlung wird dies die Option sein, die veranschaulicht wird.
Öffnen Sie die Dienstdatei der Webanwendung, und fügen Sie die COMPlus_DbgEnableMiniDump=1 Umgebungsvariable hinzu. Dies ist identisch mit den vorherigen Kapiteln dieser Schulung, die Sie mehrmals durchgeführt haben.
Sie müssen die Dienstkonfiguration neu laden, da die Konfiguration geändert wurde. Starten Sie dann den Computersamb-Dienst neu.
Nachdem Sie diese Änderungen vorgenommen haben, reproduzieren Sie das Absturzproblem. Wenn createdump funktioniert, sollte die Speicherabbilddatei als Coredump <PID> in das Verzeichnis /tmp/ geschrieben werden. Führen Sie die gleichen Schritte aus, um das Problem zu reproduzieren:
- Wählen Sie Absturz 3 aus. Die Seite wird ordnungsgemäß geladen, gibt jedoch eine falsch angeleitete Meldung zurück, die darauf hindeutet, dass der Prozess abgestürzt sein sollte.
- Wählen Sie "Langsam" aus. Dadurch wird anstelle der Produkttabelle der Antwortcode "HTTP 502" (ungültiger Gatewayfehler) generiert.
- Nachdem das Problem aufgetreten ist, wird keine der Seiten gerendert, und Sie erhalten die gleiche Fehlermeldung für 10-15 Sekunden.
- Nach 10 bis 15 Sekunden funktioniert die Anwendung ordnungsgemäß.
Sie sollten nun über eine zentrale Speicherabbilddatei im Verzeichnis "/tmp" verfügen.
Wenn Sie über keine Kernabbilddatei verfügen, stellen Sie sicher, dass Sie die Datei ordnungsgemäß konfiguriert buggyamb.service haben. Außerdem müssen Sie die Dienstkonfiguration neu laden und den Dienst neu starten.
Öffnen Sie die Kernabbilddatei in lldb.
Es wird empfohlen, die Speicherabbilddatei in Ihren ~/dumps/ Ordner zu verschieben, um sie zusammen mit der Beispielanalyse zu befolgen. Führen Sie zum Öffnen der Speicherabbilddatei lldb --core ~/dumps/coredump.<10354> . Ersetzen Sie in diesem Befehl den Platzhalter 10354 durch die PID Ihres Prozesses.
Hinweis
Wenn Sie zuvor eine Speicherabbilddatei geöffnet und mit lldb gearbeitet haben, haben Sie bereits Symbole eingerichtet und SOS installiert. Sie können dieselbe .NET Core-Versionsabbilddatei öffnen, ohne die Symbole erneut herunterladen zu müssen. Wenn Sie jedoch eine andere .NET Core-Versionsabbilddatei öffnen, für die die Symbole noch nicht heruntergeladen wurden, müssen Sie die Symbole für diese Version herunterladen, bevor Sie mit der Analyse beginnen können.
Führen Sie den SOS-Befehl clrstack aus, um den verwalteten Aufrufstapel anzuzeigen. Denken Sie daran, dass beim Ausführen desselben Befehls mithilfe einer vom System generierten Kernabbilddatei ein Fehler aufgetreten ist. Dieses Mal sollte der richtige verwaltete Aufrufstapel angezeigt werden.
Dies ist ein guter Anfang. Der angezeigte Aufrufstapel gehört jedoch zum Hauptthread unseres debuggen Prozesses. Es ist nicht der Thread, in dem die Ausnahme ausgelöst wird.
Hinweis
Wenn wir eine Absturzabbilddatei in WinDbg auf Windows öffnen, würde WinDbg direkt den Thread auswählen, der den Absturz verursacht hat. Dies ist in lldb jedoch nicht der Fall. In lldb wählt WinDbg nicht automatisch den Thread aus, der den Debugger ausgelöst hat, um das Speicherabbild zu generieren.
Obwohl dieses WinDbg-Verhalten beim Debuggen nützlich ist, ist das Fehlen dieses Features in lldb nicht das Ende der Welt. Stattdessen können Sie alle Threads untersuchen, um zu ermitteln, wo die Ausnahme ausgelöst werden kann. Beginnen Sie, indem Sie die systemeigenen Threads mithilfe des thread list Befehls untersuchen.
Es ist immer ratsam, zunächst eine schnelle Überprüfung aller Threadaufrufstapel auszuführen, damit Sie verstehen können, was zum Zeitpunkt der Generierung der Speicherabbilddatei ausgeführt wurde. Sehen Sie sich zuerst die systemeigene Threadliste mit dem thread list Befehl an.
Hinweis
Das Sternchen (*) in der Nähe des ersten Threads in der Liste ( thread #1 ) gibt an, dass es sich um den aktiven Thread handelt.
Die überprüfung des nativen Threads zeigt nicht viel. Da es sich um eine .NET Core-Anwendung handelt, überprüfen Sie die Liste der CLR-Threads, indem Sie den SOS-Befehl clrthreads ausführen. Dieser Befehl listet die verwalteten Threads auf, die in der Anwendung ausgeführt werden.
Dieser Screenshot zeigt nicht alle verwalteten Threads. Das Detail, auf das Sie sich konzentrieren sollten, ist jedoch im Screenshot aufgeführt. Thread #15 hat eine Ausnahme, die wir in unseren Systemprotokollen gesehen haben.
Überprüfen Sie den Aufrufstapel dieses Threads. Dazu müssen Sie zuerst den betreffenden Thread auswählen. In der Speicherabbildanalyse, die Sie ausführen werden, ist die Threadnummer höchstwahrscheinlich unterschiedlich. Um einen anderen Thread als aktiven Thread auszuwählen, verwenden Sie den thread select Befehl, und übergeben Sie die lldb dbg-Thread-ID. Führen Sie dies beispielsweise aus, thread select 15 um zu Thread 15 zu wechseln. Anschließend befindet sich jeder nachfolgende Befehl, den Sie ausführen, im Kontext dieses Threads. Um den systemeigenen Aufrufstapel anzuzeigen, führen Sie den bt Befehl (Zurück-Ablaufverfolgung) aus.
Wie Sie in diesem Screenshot sehen können, ist dieser Thread mit Sicherheit der Thread, der den Absturz ausgelöst hat.
PROCEndProcessundPROCAbort()werden nach einer unbehandelten Ausnahme aufgerufen.POCCreateCrashDumpteilt uns mit, dass ein Absturzabbild von .NET Core geschrieben wurde.
Sie können den verwalteten Aufrufstapel überprüfen, indem Sie den clrstack Befehl ausführen. Dies wird jedoch nicht viel aufdecken. Führen Sie den pe Befehl aus, um die Ausnahmedetails abzurufen.
Diese Informationen deuten darauf hin: A System.Net.HttpWebRequest wird auf der Crash3-Seite in der LogTheRequest() Methode ausgelöst. Dies ist eine wichtige Information, um das Problem zu finden. Aber was geschieht, wenn Sie die URL der HTTP-Anforderung finden möchten? Um fortzufahren, überprüfen Sie die Objekte, auf die im Stapel verwiesen wird, um festzustellen, ob Sie weitere Informationen aus dieser Liste sammeln können. Um alle verwalteten Objekte anzuzeigen, die sich innerhalb der Grenzen des aktuellen Stapels befinden, führen Sie dso .
Dies ist nicht hilfreich. Es sollten keine Instanzen angezeigt System.Net.HttpWebRequest werden. Es gibt Instanzen der Ausnahme, die Sie bereits überprüft haben. Daher lieferte dieser Befehl keine neuen Informationen, die sich auf die Ursache beziehen.
Alle verwalteten Objekte werden in einem verwalteten Heap gespeichert, und wir können den verwalteten Heap durch Ausführen dumpheap betrachten. Führen Sie keinen dumpheap Parameter aus, da der Befehl dann alle Objekte innerhalb des verwalteten Heaps auflistet (eine große Liste). Stattdessen können Sie die Statistiken des Heaps mithilfe des dumpheap -stat Befehls abrufen.
Sie können eine weitere Taktik verwenden, um die Statistiken einzugrenzen, indem Sie den Befehl im folgenden Format ausführen:
dumpheap -stat -type System.Net.HttpWebRequest
Der folgende Screenshot zeigt die Statistiken für die verwalteten Objekte, die die Zeichenfolge System.Net.HttpWebRequest in ihrem Namen enthalten.
In der Beispielanwendung ist nur ein System.Net.HttpWebRequest Objekt auf dem verwalteten Heap vorhanden. In der vorherigen Liste ist die Adresse, die neben dem Eintrag angezeigt HttpWebRequest wird, nicht die Adresse dieses Objekts im Speicher. Stattdessen ist es die Adresse, die der "Methodentabelle" von Objekten des Typs System.Net.HttpWebRequest entspricht. Um die tatsächliche Liste der Objekte abzurufen, können Sie diese Methodentabelle (MT)-Adresse wie folgt an dumpheap den Befehl übergeben:
dumpheap -mt <address>
Führen Sie z. B. die Ausführung aus, dumpheap -mt 00007f53623cb640 um die Adresse des Objekts zu suchen.
Jetzt können Sie die Adresse des problematischen Objekts identifizieren. In diesem Beispiel ist dies 00007f51300c0868 . Sie können die Eigenschaften des Objekts untersuchen, indem Sie diese Adresse an den dumpobj Befehl übergeben. Dadurch werden die Eigenschaften dieses Objekts aufgelistet. Führen Sie in diesem Beispiel die dumpobj 00007f51300c0868 Ausführung aus, um die Eigenschaften des Objekts zu untersuchen.
Hinweis
Sie untersuchen ein System.Net.HttpWebRequest Objekt, und eine seiner Eigenschaften ist _requestUri . Dies ist ein Objekt des System.Uri Typs. Sie möchten den URI ermitteln. Übergeben Sie daher die Adresse der _requestUri Eigenschaft an den dumpobj Befehl.
Kopieren Sie die Adresse des System.Uri Objekts, und untersuchen Sie sie dumpobj erneut. Führen Sie dumpobj 00007f51300bfbb8 aus. Die Adresse des Objekts in der Speicherabbilddatei, die Sie generiert haben, ist mit großer Sicherheit unterschiedlich. In der Liste wird die _string Eigenschaft von System.Uri angezeigt.
Kopieren Sie die Adresse von _string , und führen Sie dann erneut den Befehl dafür dumpobj aus. Führen Sie dumpobj 00007f51300bfb40 aus. Das Ergebnis wird im folgenden Screenshot aufgeführt.
Schließlich können Sie die URL von HttpWebRequest finden: http://buggyamb/Problem/Api/NotExistingLoggingApi . Wie der Name schon sagt, ist dies wahrscheinlich keine vorhandene Seite innerhalb der Anwendung.
Abschließend lautet die These, wie der Absturz aufgetreten ist, wie folgt:
- HttpWebRequest wird zu einer nicht vorhandenen URL in der
LogTheRequest()Methode auf der Crash3-Webseite erstellt. - In einer realen Anwendung besteht die Lösung zum Beheben dieses Problems darin, die Fehler zu behandeln, wenn
HttpWebRequestsie vorgenommen werden. In diesem Fall ist die Lösung jedoch viel einfacher: Stellen Sie keineHttpWebRequestAnforderung an eine nicht vorhandene Seite.
An diesem Punkt sollten Sie wahrscheinlich weitere Fragen dazu haben, was den Absturz verursacht hat. Warum wurde beispielsweise der Absturz ausgelöst, nachdem Sie den Link "Slow" ausgewählt haben?
Sie können die Untersuchung selbst fortsetzen. Der nächste vorgeschlagene Schritt wäre das Ausführen des gcroot Befehls mithilfe der HttpWebRequest Objektadresse, um herauszufinden, wo er gerootet ist. Dies kann Ihnen helfen, ein Bild davon zu entwickeln, wie der Absturz aufgetreten ist.
Damit wird die Übung abgeschlossen. Drücken Sie STRG+C, oder verwenden Sie den q Befehl, um den lldb-Debugger zu beenden.
Nächste Schritte
Übung 2.1 Beheben von Leistungsproblemen mithilfe von createdump unter Linux