Поделиться через


Лаборатория 1.3. Устранение неполадок сбоем — сбор основных дампов аварийного сбоя с помощью средства createdump

Область применения: .NET Core 2.1, .NET Core 3.1, .NET 5

В этой статье описывается, как использовать средство createdump для записи файлов аварийного дампа .NET Core в Linux, а затем использовать lldb для диагностики проблемы сбоя.

Предварительные требования

Минимальное требование для выполнения этих лабораторий устранения неполадок заключается в наличии приложения ASP.NET Core для демонстрации проблем с низкой производительностью ЦП и высокой производительности ЦП.

Вы можете найти несколько примеров приложений для достижения этой цели в Интернете. Например, вы можете скачать и настроить простой пример webapi Корпорации Майкрософт, чтобы продемонстрировать нежелательное поведение. Кроме того, в качестве примера проекта можно использовать приложение BuggyAmb ASP.NET Core.

Если вы последовали за предыдущими частями этой серии, вам потребуется выполнить следующую настройку:

  • Nginx настроен для размещения двух веб-сайтов:
    • Первый прослушивает запросы с помощью заголовка узла myfirstwebsite (http://myfirstwebsite) и запросов маршрутизации в демонстрационное приложение ASP.NET Core, которое прослушивает порт 5000.
    • Второй прослушивает запросы с помощью заголовка узла buggyamb (http://buggyamb) и запросов маршрутизации во второй ASP.NET пример приложения buggy Core, прослушивающего порт 5001.
  • Оба приложения ASP.NET Core должны работать в качестве служб, которые автоматически перезапускается при перезапуске сервера или приложение перестает отвечать.
  • Локальный брандмауэр Linux включен и настроен для разрешения трафика SSH и HTTP.

Примечание.

Если настройка не готова, перейдите в раздел "Часть 2 Создание и запуск приложений ASP.NET Core".

Чтобы продолжить эту лабораторию, необходимо иметь по крайней мере одно проблематичное веб-приложение ASP.NET Core, работающее за Nginx.

Цель этой лаборатории

Автоматически созданные файлы дампа ядра не полезны, так как они не содержат все сведения об управляемом состоянии. Рекомендуемое средство для записи файлов аварийного дампа .NET Core создается.

В этой части вы узнаете, как записать файл аварийного дампа с помощью createdump и открыть файл в lldb, чтобы диагностировать проблему сбоя.

Настройка createdump для запуска при завершении процесса

Createdump устанавливается автоматически вместе с каждой средой выполнения .NET Core.

Как описано в документации по политике конфигурации createdump, можно задать параметры конфигурации с переменными среды. Они передаются команде createdump в качестве параметров. Ниже приведены поддерживаемые переменные среды:

  • COMPlus_DbgEnableMiniDump: если задано значение 1, включает автоматическое создание дампа ядра при завершении. Значение по умолчанию — 0.
  • COMPlus_DbgMiniDumpType: это тип файла мини-дампа, который будет создан. Значение по умолчанию для этого равно 2 (или тип перечисления MiniDumpWithPrivateReadWriteMemory). Это означает, что созданный файл дампа будет включать кучи GC и необходимые сведения для отслеживания трассировки стека для всех существующих потоков в процессе.
  • COMPlus_DbgMiniDumpName: если задано, используйте шаблон для создания пути к файлу дампа и имени файла. PiD можно поместить в имя с помощью %d параметра. Шаблон по умолчанию ./tmp/coredump.%d С помощью этой переменной среды можно настроить выходной каталог.
  • COMPlus_CreateDumpDiagnostics: если задано значение 1, включает диагностические сообщения средства createdump (макрос TRACE). Этот параметр может быть полезным, если createump не работает должным образом и не создает файл дампа памяти.

Сведения об этих переменных можно найти в политике конфигурации createdump.

Важная переменная здесь COMPlus_DbgEnableMiniDump. Необходимо задать для этой переменной среды значение 1. Существует несколько методов установки этой среды:

  • Задайте его в файле конфигурации приложения.
  • export COMPlus_DbgEnableMiniDump=1 Используйте команду, чтобы задать ее. Этот параметр не будет сохраняться после перезагрузки операционной системы. Поэтому необходимо задать его как постоянный, если вы хотите сохранить параметр включено после перезапуска.
  • Задайте его в файле единицы обслуживания ASP.NET Core.

Установка этой переменной в файле единицы обслуживания core ASP.NET является самым простым методом. Недостаток заключается в том, что служба должна быть перезапущена. В этом разделе по устранению неполадок будет показан параметр.

Откройте файл службы приложения buggy и добавьте COMPlus_DbgEnableMiniDump=1 переменную среды. Это то же самое, что вы сделали несколько раз в предыдущих главах этого обучения.

Снимок экрана: команда buggy.

Необходимо перезагрузить конфигурацию службы, так как конфигурация была изменена. Затем перезапустите службу BuggyAmb.

Снимок экрана: команда sudo.

После внесения этих изменений воспроизвести проблему сбоя. Если созданная функция работает, файл дампа должен быть записан в каталоге /tmp/ в качестве coredump.<PiD>. Выполните те же действия, чтобы воспроизвести проблему:

  1. Выберите "Сбой 3". Страница загружается правильно, но возвращает неправильное сообщение, которое предполагает, что процесс должен завершиться сбоем.
  2. Нажмите кнопку "Медленно". Это приведет к созданию кода отклика HTTP 502 (ошибка с неправильным шлюзом) вместо таблицы продуктов.
  3. После возникновения проблемы ни одна из страниц не будет отображаться, и вы получите то же сообщение об ошибке в течение 10–15 секунд.
  4. Через 10–15 секунд приложение начинает работать правильно.

Теперь в каталоге /tmp должен быть файл дампа ядра.

Снимок экрана: команда ll.

Если у вас нет файла дампа ядра, убедитесь, что файл настроен buggyamb.service правильно. Кроме того, необходимо перезагрузить конфигурацию службы и перезапустить службу.

Открытие файла основного дампа в lldb

Рекомендуется переместить файл дампа в ~/dumps/ папку, чтобы следовать примеру анализа. Чтобы открыть файл дампа, выполните команду lldb --core ~/dumps/coredump.<10354>. В этой команде замените заполнитель 10354 идентификатором идентификатора процесса.

Примечание.

Если вы ранее открыли файл дампа и работали с lldb, вы уже настроили символы и установили SOS. Вы можете открыть тот же файл дампа версии .NET Core, не скачивая символы еще раз. Однако если открыть другой файл дампа версии .NET Core, для которого символы еще не скачиваются, необходимо скачать символы для этой версии, прежде чем начать анализ.

Выполните команду SOS clrstack , чтобы отобразить стек управляемых вызовов. Помните, что при выполнении той же команды при выполнении той же команды с помощью основного файла дампа, созданного системой. На этот раз вы увидите правильный стек управляемых вызовов.

Снимок экрана: команда lldb.

Это хороший старт. Однако стек вызовов, отображаемый, относится к основному потоку отлаживаемого процесса. Это не поток, в котором создается исключение.

Примечание.

Если открыть файл аварийного дампа в WinDbg в Windows, WinDbg будет напрямую выбрать поток, который вызвал сбой. Однако это не так в lldb. В lldb WinDbg не выбирает автоматически поток, который активировал отладчик для создания дампа памяти.

Хотя это поведение WinDbg полезно при отладке, отсутствие этой функции в lldb не является конец мира. Вместо этого можно изучить все потоки, чтобы попытаться определить, где может быть вызвано исключение. Начните с изучения собственных потоков с помощью thread list команды.

Всегда рекомендуется начать с быстрой проверки всех стеков вызовов потоков, чтобы понять, что выполнялось во время создания файла дампа. Сначала просмотрите собственный список потоков, имеющий thread list команду.

Примечание.

Звездочка (*) рядом с первым потоком в списке (thread #1) указывает, что это активный поток.

Снимок экрана: команда списка.

Проверка собственного потока не показывает много. Так как это приложение .NET Core, изучите список потоков СРЕДЫ CLR, выполнив команду SOS clrthreads . Эта команда перечисляет управляемые потоки, работающие в приложении.

Снимок экрана: команда clrthreads.

На этом снимке экрана не отображаются все управляемые потоки. Однако на снимке экрана приведены подробные сведения, на которые вы должны сосредоточиться. Thread #15 имеет исключение, которое мы видели в наших системных журналах.

Снимок экрана: сведения о потоке15.

Проверьте стек вызовов этого потока. Для этого необходимо сначала выбрать поток в вопросе. В анализе дампа памяти, который будет выполняться, число потока, скорее всего, будет отличаться. Чтобы выбрать другой поток в качестве активного потока, используйте thread select команду и передайте идентификатор потока dbg lldb. Например, запустите, thread select 15 чтобы переключиться на поток 15. Затем каждая последовательная команда, которую вы выполняете, будет находиться в контексте этого потока. Чтобы просмотреть собственный стек вызовов, выполните bt команду (обратная трассировка).

Снимок экрана: команда select.

Как видно на этом снимке экрана, этот поток, безусловно, является потоком, который вызвал сбой.

  • PROCEndProcess и PROCAbort() вызываются после необработанного исключения.
  • POCCreateCrashDump сообщает нам, что аварийный дамп написан .NET Core.

Вы можете проверить стек управляемых вызовов, выполнив clrstack команду. Тем не менее, это не покажет много. pe Выполните команду, чтобы получить сведения об исключении.

Снимок экрана: команда pe.

Эта информация указывает: активируется System.Net.HttpWebRequest на странице Crash3 в методе LogTheRequest() . Это важный фрагмент информации, помогающий найти проблему. Но что делать, если вы хотите найти URL-адрес HTTP-запроса? Чтобы продолжить, попробуйте проверить объекты, на которые ссылается стек, чтобы узнать, можно ли собирать дополнительные сведения из этого списка. Чтобы отобразить все управляемые объекты, найденные в пределах текущего стека, выполните команду dso.

Снимок экрана: команда dso.

Это не полезно. Экземпляры не должны отображаться System.Net.HttpWebRequest . Есть экземпляры исключения, и вы уже проверили его. Поэтому эта команда не дала новых сведений, связанных с причиной.

Все управляемые объекты хранятся в управляемой куче, и мы можем посмотреть на управляемую кучу, выполнив команду dumpheap. Не выполняйтесь dumpheap без каких-либо параметров, так как команда будет перечислять все объекты в управляемой куче (большой список). Вместо этого можно получить статистику кучи с помощью dumpheap -stat команды.

Вы можете использовать еще одну тактику для сузки статистики, выполнив команду в следующем формате:

dumpheap -stat -type System.Net.HttpWebRequest

На следующем снимке экрана показана статистика для управляемых объектов, содержащих строку System.Net.HttpWebRequest в их имени.

Снимок экрана: сведения о запросе.

В примере приложения существует только один System.Net.HttpWebRequest объект в управляемой куче. В предыдущем списке адрес, который отображается рядом с HttpWebRequest записью, не является адресом этого объекта в памяти. Скорее, это адрес, соответствующий "таблице методов" объектов типа System.Net.HttpWebRequest. Чтобы получить фактический список объектов, можно передать этот адрес таблицы методов (MT) в dumpheap команду следующим образом:

dumpheap -mt <address>

Например, выполните команду dumpheap -mt 00007f53623cb640 , чтобы найти адрес объекта.

Снимок экрана: команда dumpheap.

Теперь вы можете определить адрес проблемного объекта. В нашем примере это значение выглядит следующим образом: 00007f51300c0868. Свойства объекта можно исследовать, передав этот адрес команде dumpobj . В этом списке перечислены свойства этого объекта. В этом примере выполните проверку dumpobj 00007f51300c0868 свойств объекта.

Снимок экрана: команда dumpobj.

Примечание.

Вы изучаете System.Net.HttpWebRequest объект, и что один из его свойств ._requestUri Это объект System.Uri типа. Вы хотите определить универсальный код ресурса (URI). Поэтому передайте адрес _requestUri свойства команде dumpobj .

Скопируйте адрес System.Uri объекта и изучите его еще dumpobj раз. Запустите dumpobj 00007f51300bfbb8. Адрес объекта в созданном файле дампа памяти, безусловно, будет отличаться. В списке _string будет отображаться свойство System.Uri.

Снимок экрана: команда dumpobj2.

Скопируйте адрес _stringи снова выполните dumpobj команду. Запустите dumpobj 00007f51300bfb40. Результат отображается на следующем снимке экрана.

Снимок экрана: команда dumpobj3.

Наконец, вы можете найти URL-адрес httpWebRequest: http://buggyamb/Problem/Api/NotExistingLoggingApi Как предполагает имя, это, вероятно, не существующая страница в приложении.

Чтобы завершить, теория о том, как произошла авария, выглядит следующим образом:

  • HttpWebRequest создается в не существующий URL-адрес в методе LogTheRequest() на веб-странице Crash3 .
  • В реальном приложении решение для устранения этой проблемы будет обрабатывать ошибки при HttpWebRequest создании. Однако в этом случае решение гораздо проще: не выполняйте HttpWebRequest запрос на несуществующую страницу.

На этом этапе вы, вероятно, должны иметь больше вопросов о том, что вызвало аварию. Например, почему произошел сбой после выбора медленной ссылки?

Вы можете продолжать расследование самостоятельно. Следующий рекомендуемый шаг — выполнить gcroot команду с помощью HttpWebRequest адреса объекта, чтобы узнать, где он корень. Это может помочь вам разработать картину того, как произошел сбой.

Это завершает лабораторию. Нажмите клавиши CTRL+C или используйте q команду, чтобы выйти из отладчика lldb.

Следующие шаги

Устранение проблем с производительностью лаборатории 2.1 с помощью createdump в Linux