Перейти к содержанию

Использование трассировок, DQL и логов для выявления закономерностей

Выявляйте аномальные закономерности в трассировках и логах с помощью Distributed Tracing Distributed Tracing и Dynatrace Query Language (DQL).

Введение

В этом руководстве вы узнаете, как использовать трассировки, DQL и логи для:

  • Выявления неэффективных запросов к базе данных.
  • Понимания закономерностей рабочей нагрузки.
  • Обнаружения аномалий в использовании базы данных.
  • Анализа производительности.
  • Понимания влияния отдельных запросов к базе данных (например, сколько данных они изменяют).

Для удобства разделы, в которых используется Distributed Tracing Distributed Tracing, отмечены значком Distributed Tracing, а разделы, в которых используется DQL, отмечены значком . Кроме того, для подробного объяснения каждого DQL-запроса выберите Пояснение к DQL-запросу над блоком кода DQL-запроса.

Целевая аудитория

Любой пользователь последней версии Dynatrace, который хочет больше узнать о трассировках, логах и DQL, а также понять, как эффективно их использовать.

Результат обучения

После прохождения этого руководства вы научитесь составлять и эффективно использовать различные DQL-запросы, которые помогут вам оптимизировать устранение неполадок, настроить оповещения и автоматизировать рабочие процессы.

Прежде чем начать

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

Для прохождения этого руководства вам нужен только доступ к последней версии Dynatrace в вашей среде.

Также вы можете использовать нашу среду Dynatrace Playground для выполнения шагов этого руководства.

Необходимые знания

  • Знакомство с последней версией Dynatrace
  • Хотя бы базовые знания DQL
  • Понимание того, что такое Distributed Tracing

Для обзора посмотрите видео Unleash the Power of Distributed Tracing на YouTube.

Выявление неэффективных паттернов запросов к базе данных

Независимо от того, выполняется ли определённый SQL-оператор повторно, вызываются ли несколько различных SQL-операторов в рамках трассировки или задействован один длительный запрос — каждый из этих сценариев представляет собой потенциальную проблему производительности, которую мы стремимся обнаружить.

Distributed Tracing Обнаружение паттернов запросов с помощью Distributed Tracing

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

  1. Перейдите в Distributed Tracing Distributed Tracing.
  2. В верхней левой части страницы, под заголовком приложения, выберите Spans, чтобы просмотреть анализ на основе спанов запросов.
  3. В текстовом поле Search facets введите Databases и выберите фасет Databases, чтобы отобразить все связанные метаданные.
  4. Рядом с Db query text выберите (More) > Group by, чтобы мгновенно проанализировать все запросы к базе данных по спанам.

В этом представлении вы можете:

  • Сортировать данные по различным параметрам в порядке возрастания или убывания.
  • Группировать данные по нескольким атрибутам.
  • Сужать выборку данных с помощью различных фильтров.

Вы можете применять описанные ниже техники к исключениям, хостам, процессам, удалённым вызовам процедур и многому другому.

В Distributed Tracing переключитесь на "Spans" и сгруппируйте данные по "Db query text" и "Service", чтобы выявить некоторые паттерны запросов к базе данных

Сортировка данных

Выберите заголовки столбцов таблицы, чтобы отсортировать данные по различным параметрам и выявить определённые паттерны запросов к базе данных.

  • Count: Найти наиболее частые запросы.
  • Average duration: Обнаружить самые длительные запросы.
  • Failure rate: Просмотреть запросы к базе данных с наибольшей частотой ошибок.

Группировка данных по нескольким атрибутам

Разделяйте данные по нескольким атрибутам для уточнения представления.

  1. Прямо над таблицей раскройте выпадающий список Group by и выберите Services. У вас должна получиться следующая группировка: Group by: Db query text | Service.

Таким образом, вы сможете увидеть, какие запросы к базе данных являются общими для разных сервисов. 2. Измените порядок атрибутов группировки. В выпадающем списке Group by снимите выбор с Db query text, а затем выберите этот атрибут снова. У вас должна получиться следующая группировка: Group by: Service | Db query text.

В этом случае вы можете увидеть, какие запросы к базе данных выполняет каждый сервис. 3. Выберите слева от текущего активного первичного атрибута, чтобы развернуть атрибут и просмотреть запрошенный анализ.

Порядок, в котором вы размещаете атрибуты группировки, напрямую влияет на получаемые результаты.

Сужение данных с помощью фильтров

Применяйте фильтры для сужения выборки данных.

В текстовом поле Type to filter введите запрос. Например, введите "Db query text" = *, чтобы исключить спаны с пустыми запросами к базе данных.

Обнаружение необычных паттернов с помощью DQL

После использования Distributed Tracing Distributed Tracing давайте узнаем, как использовать DQL для выявления нетипичных паттернов в трассировках и логах. Мы рекомендуем использовать Notebooks Notebooks для выполнения всех примеров DQL-запросов в этом руководстве.

  1. Перейдите в Notebooks Notebooks.
  2. Выберите Notebook в заголовке приложения, чтобы создать новый ноутбук.
  3. Откройте меню Add и выберите DQL.

Вы можете добавить несколько DQL-секций для всех DQL-запросов, представленных в руководстве. 4. В секции запроса введите DQL-запрос. 5. Выберите Run, чтобы выполнить DQL-запрос.

Используйте Notebooks для ввода и выполнения DQL-запросов, представленных в этом руководстве

Обнаружение наиболее частых типов запросов

Давайте проверим, как часто определённый тип запроса (например, INSERT, SELECT или UPDATE) встречается в ваших спанах с течением времени. Скопируйте следующий запрос в секцию запроса ноутбука, а затем выберите Run, чтобы выполнить DQL-запрос.

Пояснение к DQL-запросу

  • fetch spans: Извлечение данных из таблицы spans, содержащей информацию об отдельных спанах.
  • filter isNotNull(db.query.text): Включение только тех спанов, в которых присутствует запрос к базе данных.
  • parse db.query.text, "string:type": Разбор поля db.query.text и извлечение значения type для определения типа запроса. Это значение сохраняется в новом поле type.
  • makeTimeseries count(), by:{upper(type)}: Подсчёт количества появлений каждого типа запроса в спанах и создание временного ряда для визуализации.
fetch spans


| filter isNotNull(db.query.text)


| parse db.query.text, "string:type"


| makeTimeseries count(), by:{upper(type)}

Запустить в Playground

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

Используйте этот запрос для понимания закономерностей рабочей нагрузки или обнаружения аномалий.

Обнаружение ресурсоёмких запросов

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

Пояснение к DQL-запросу

  • fetch spans: Извлечение данных из таблицы spans, содержащей информацию об отдельных спанах.
  • filter isNotNull(db.query.text): Включение только тех спанов, в которых присутствует запрос к базе данных.
  • makeTimeseries sum(duration), by:{db.query.text}: Создание временного ряда, показывающего сумму длительности каждого запроса, отсортированную по тексту запроса.
fetch spans


| filter isNotNull(db.query.text)


| makeTimeseries sum(duration), by:{db.query.text}

Запустить в Playground

Временной ряд, созданный с помощью DQL, показывающий общую длительность спанов, сгруппированных по тексту запроса к базе данных

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

Выявление запросов с высоким воздействием

С помощью этого запроса мы можем проверить, сколько строк данных затронуто — например, SELECT, INSERT или DELETE — каждым запросом к базе данных.

Пояснение к DQL-запросу

  • fetch spans: Извлечение данных из таблицы spans, содержащей информацию об отдельных спанах.
  • filter isNotNull(db.query.text): Включение только тех спанов, в которых присутствует запрос к базе данных.
  • makeTimeseries sum(db.affected_item_count), by:{db.query.text}: Создание временного ряда с суммированием количества затронутых строк данных, отсортированного по тексту запроса.
fetch spans


| filter isNotNull(db.query.text)


| makeTimeseries sum(db.affected_item_count), by:{db.query.text}

Запустить в Playground

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

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

Обнаружение паттернов исключений

В этом разделе мы будем использовать DQL для выявления определённых паттернов исключений. Мы определим, какие типы исключений наиболее распространены, и найдём сервисы с наибольшим количеством исключений.

Подсчёт исключений по типу исключения

Мы сосредоточимся на количестве поступающих исключений и узнаем, как часто возникает каждый тип исключения.

Пояснение к DQL-запросу

  • fetch spans: Извлечение данных из таблицы spans, содержащей информацию об отдельных спанах.
  • filter iAny(span.events[][span_event.name] == "exception"): Включение только тех спанов, которые содержат исключение.
  • expand span.events: Развёртывание массива span.events для работы с отдельными событиями спана вместо всего массива.
  • fieldsFlatten span.events, fields: {exception.type}: Извлечение поля exception.type из каждого события спана и его развёртывание в отдельный столбец, по которому можно группировать и считать.
  • makeTimeseries count(), by: {exception.type}, time:start_time: Создание временного ряда, показывающего количество исключений, сгруппированных по типу с течением времени. Этот временной ряд показывает, как часто возникает каждый тип исключения на основе времени начала спана.
fetch spans


| filter iAny(span.events[][span_event.name] == "exception")


| expand span.events


| fieldsFlatten span.events, fields: {exception.type}


| makeTimeseries count(), by: {exception.type}, time:start_time

Запустить в Playground

Временной ряд, созданный с помощью DQL, показывающий количество исключений с течением времени, сгруппированных по типу

Проверка количества исключений по типу может быть полезна для мониторинга ошибок и отладки. С помощью этого запроса вы можете:

  • Определить, какие типы исключений наиболее распространены.
  • Обнаружить тренды или всплески определённых типов исключений.
  • Соотнести частоту исключений с развёртываниями, изменениями трафика или другими системными событиями.

Обнаружение сервисов с наибольшим количеством исключений

С помощью следующего запроса мы получаем список сервисов с наибольшим количеством исключений.

Пояснение к DQL-запросу

  • fetch spans: Извлечение данных из таблицы spans, содержащей информацию об отдельных спанах.
  • filter iAny(span.events[][span_event.name] == "exception"): Включение только тех спанов, которые содержат исключение.
  • expand span.events: Развёртывание массива span.events для работы с отдельными событиями спана вместо всего массива.
  • fieldsFlatten span.events, fields: {exception.type, exception.message}: Развёртывание полей exception.type и exception.message.
  • summarize count(), by: {service.name, exception.message}: Суммирование этих полей по количеству и группировка по имени сервиса и сообщению исключения.
fetch spans


| filter iAny(span.events[][span_event.name] == "exception")


| expand span.events


| fieldsFlatten span.events, fields: {exception.type, exception.message}


| summarize count(), by: {service.name, exception.message}

Запустить в Playground

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

Обнаружение «горячих» внутренних методов

Когда речь идёт об оптимизации кода, вы, возможно, захотите сначала увидеть, какие методы являются «горячими точками». В этом случае мы можем проанализировать все спаны, представляющие вызовы внутренних методов, и затем сгруппировать их по сервису и имени спана.

Distributed Tracing Поиск длительных спанов с помощью Distributed Tracing

Вот как мы достигаем этого в Distributed Tracing Distributed Tracing.

  1. Перейдите в Distributed Tracing Distributed Tracing.
  2. В верхней левой части страницы, под заголовком приложения, выберите Spans, чтобы просмотреть анализ на основе спанов запросов.
  3. В текстовом поле Search facets введите Span, а затем выберите internal в фасете Span kind.
  4. Прямо над таблицей раскройте выпадающий список Group by и выберите Services и Span name. У вас должна получиться следующая группировка: Group by: Service | Span name.
  5. Выберите заголовок таблицы Average duration.
  6. Выберите слева от текущего активного первичного атрибута, чтобы развернуть атрибут и просмотреть запрошенный анализ.

В Distributed Tracing переключитесь на "Spans", отфильтруйте внутренние спаны и сгруппируйте данные по "Service" и "Span name" для выявления длительных спанов

Вы можете мгновенно увидеть, какие спаны потребляют больше всего времени.

Определение топ-10 самых медленных внутренних спанов

Используя следующий запрос, вы получите список самых медленных внутренних узлов спанов по средней длительности.

Пояснение к DQL-запросу

  • fetch spans: Извлечение данных из таблицы spans, содержащей информацию об отдельных спанах.
  • filter matchesValue(`span.kind`, "internal"): Фокус на внутренних спанах, исключая такие типы спанов, как HTTP-запросы или спаны обмена сообщениями.
  • summarize {durationSum = sum(duration), callCount = count(), avgDuration = avg(duration)}, by: {service.name, span.name}: Агрегирование данных спанов по трём направлениям (общая длительность, количество вызовов и средняя длительность) и группировка данных по сервису и имени спана для получения метрик для каждого метода или операции в рамках каждого сервиса.
  • sort avgDuration desc: Сортировка по средней длительности, начиная с наибольшей (то есть самых медленных внутренних операций).
  • limit 10: Ограничение вывода 10 первыми результатами.
fetch spans


| filter matchesValue(`span.kind`, "internal")


| summarize {durationSum = sum(duration), callCount = count(), avgDuration = avg(duration)}, by: {service.name, span.name}


| sort avgDuration desc


| limit 10

Запустить в Playground

Выявление функции в вашем коде, которая потребляет значительное количество времени выполнения или ресурсов, помогает обнаруживать узкие места, понимать поведение во время выполнения и оптимизировать усилия (такие как снижение использования CPU, потребления памяти или времени отклика).

Выявление паттернов логов: сервисы с наибольшим количеством логов

Теперь давайте обнаружим сервисы, которые генерируют наибольшее количество логов. Запрос ниже предлагает нам простой способ определить наших основных генераторов логов в контексте трассировки.

Пояснение к DQL-запросу

  • fetch logs: Загрузка всех доступных данных логов из таблицы logs.
  • filter isNotNull(trace_id): Включение только тех логов, которые являются частью трассировки.
  • summarize count = count(), by: {service.name}: Суммирование логов и группировка по имени сервиса, то есть мы считаем, сколько логов, связанных с трассировками, создал каждый сервис.
  • sort count desc: Сортировка по количеству логов, начиная с наибольшего, так что сервисы с наибольшим количеством логов отображаются первыми.
  • limit 20: Ограничение вывода 20 первыми результатами.
fetch logs


| filter isNotNull(trace_id)


| summarize count = count(), by: {service.name}


| sort count desc


| limit 20

Запустить в Playground

Такой DQL-запрос полезен, когда вам нужно понять, какие сервисы генерируют наибольшее количество логов. Зная это, вы можете выявить сервисы с чрезмерным логированием и оптимизировать затраты на приём логов.

Объединение логов и трассировок: подсчёт логов на конечную точку сервиса

Наконец, давайте узнаем, сколько логов создаётся для каждой конечной точки сервиса.

По умолчанию логи не содержат информации о конечной точке. Однако, обогащая логи идентификатором трассировки, мы можем выполнить join логов и трассировок на основе их общего поля.

Пояснение к DQL-запросу

  • fetch spans: Извлечение данных из таблицы spans, содержащей информацию об отдельных спанах.
  • join [: Выполнение операции объединения с другим набором данных:

  • fetch logs: Загрузка всех доступных данных логов из таблицы logs.

  • fieldsAdd trace.id = toUid(trace_id): Добавление поля trace.id путём преобразования поля trace_id в уникальный идентификатор (UID) с помощью функции toUid.
  • summarize logCount = count(), by: {trace.id}: Суммирование данных логов по trace.id, вычисление общего количества логов для каждой трассировки.
  • ], on: {trace.id}: Объединение суммированных данных логов с данными спанов по полю trace.id, совмещая два набора данных.
  • filter isNotNull(http.url): Включение только тех спанов, которые содержат HTTP URL.
  • summarize {requestCount = count(), logCount = sum(right.logCount)}, by: {http.url}: Суммирование количества запросов и количества логов для каждой запрошенной конечной точки (поле http.url).
  • fieldsAdd logPerRequest = logCount / requestCount: Добавление поля, в котором вычисляется соотношение логов на запрос.
  • sort logPerRequest desc: Сортировка по убыванию.
fetch spans


| join [


fetch logs


| fieldsAdd trace.id = toUid(trace_id)


| summarize logCount = count(), by: {trace.id}


], on: {trace.id}


| filter isNotNull(http.url)


| summarize {requestCount = count(), logCount = sum(right.logCount)}, by: {http.url}


| fieldsAdd logPerRequest = logCount / requestCount


| sort logPerRequest desc

Запустить в Playground

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

Призыв к действию

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

Вы узнали, как использовать Distributed Tracing Distributed Tracing для обнаружения паттернов запросов к базе данных. Кроме того, вы освоили множество примеров использования DQL для поиска сервисов с наибольшим количеством исключений, выявления «горячих» методов и даже объединения логов и трассировок для подсчёта количества логов, созданных для каждой конечной точки сервиса.

Если вы считаете, что вам необходимо иметь определённую информацию под рукой, добавьте результат DQL-запроса на дашборд. Вы также можете рассмотреть возможность создания метрики, которую можно извлекать из логов по мере их поступления в Dynatrace.

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

  • Ознакомьтесь с этим специальным ноутбуком, созданным в нашей среде Dynatrace Playground, где мы делимся некоторыми советами и приёмами использования трассировок, логов и DQL для выявления необычных паттернов в вашей среде.
  • Погрузитесь глубже в мир DQL: посетите Dynatrace Query Language и лучшие практики DQL.
  • Изучите следующие приложения Dynatrace:

  • Distributed Tracing Distributed Tracing

  • Logs Logs
  • Notebooks Notebooks
  • Dashboards Dashboards