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


Анализ журналов телеметрии Application Insights с помощью Apache Spark в HDInsight

Сведения об анализе данных телеметрии Application Insight с помощью Apache Spark в HDInsight.

Visual Studio Application Insights — это служба аналитики, которая отслеживает ваши веб-приложения. Данные телеметрии, созданные службой Application Insights, можно экспортировать в службу хранилища Azure. Затем вы можете использовать HDInsight, чтобы проанализировать их.

Необходимые компоненты

  • Приложение, настроенное для использования службы Application Insights.

  • Умение создавать кластеры HDInsight под управлением Linux. Дополнительные сведения см. в статье о создании кластера Apache Spark в HDInsight.

  • Веб-браузер.

При разработке и тестировании этого документа использовались следующие ресурсы:

Архитектура и планирование

На следующей схеме показана архитектура служб данного примера:

Data flowing from Application Insights to blob storage, then Spark.

Хранилище Azure

В службе Application Insights можно настроить непрерывный экспорт данных телеметрии в большие двоичные объекты. Затем HDInsight сможет считывать данные, хранимые в больших двоичных объектах. Однако существует ряд требований, которые необходимо выполнить. Они описаны ниже.

  • Расположение. Если учетная запись хранения и HDInsight находятся в разных местах, это может увеличить задержку. Это также увеличивает затраты, так как передача данных между регионами оплачивается как исходящий трафик.

    Предупреждение

    Использование учетной записи хранения, расположение которой отличается от расположения кластера HDInsight, не поддерживается.

  • Тип большого двоичного объекта. HDInsight поддерживает только блочные BLOB-объекты. Служба Application Insights по умолчанию использует блочные BLOB-объекты, поэтому должна работать с HDInsight.

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

Схема данных

Application Insights предоставляет сведения об экспорте модели данных для формата данных телеметрии, экспортируемых в большие двоичные объекты. В этом документе для работы с данными используется Spark SQL. Spark SQL может автоматически создавать схему для структуры данных JSON, регистрируемой службой Application Insights.

Экспорт данных телеметрии

Чтобы настроить непрерывный экспорт данных телеметрии из Application Insights в хранилище BLOB-объектов Azure, выполните действия, описанные в статье Экспорт данных телеметрии из Application Insights.

Настройка доступа к данным из HDInsight

Если вы создаете кластер HDInsight, в процессе добавьте учетную запись хранения.

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

Анализ данных. PySpark

  1. В веб-браузере перейдите на страницу https://CLUSTERNAME.azurehdinsight.net/jupyter, заменив CLUSTERNAME именем своего кластера.

  2. В правом верхнем углу страницы Jupyter щелкните Создать, а затем выберите PySpark. При этом откроется новая вкладка браузера, содержащая записную книжку Jupyter на основе Python.

  3. На этой странице в первом поле (которое называется ячейка) введите следующий текст:

    sc._jsc.hadoopConfiguration().set('mapreduce.input.fileinputformat.input.dir.recursive', 'true')
    

    Этот код настраивает Spark рекурсивно обращаться к структуре каталогов для получения входных данных. Телеметрия Application Insights записывается в структуру каталогов, аналогичную этой: /{telemetry type}/YYYY-MM-DD/{##}/.

  4. Для выполнения кода используйте сочетание клавиш SHIFT+ВВОД. Слева от ячейки в скобках отобразится звездочка (*), показывая тем самым, что код в этой ячейке выполняется. После завершения выполнения звездочку (*) заменит число, а под ячейкой отобразятся данные, аналогичные следующим:

    Creating SparkContext as 'sc'
    
    ID    YARN Application ID    Kind    State    Spark UI    Driver log    Current session?
    3    application_1468969497124_0001    pyspark    idle    Link    Link    ✔
    
    Creating HiveContext as 'sqlContext'
    SparkContext and HiveContext created. Executing user code ...
    
  5. Под первой ячейкой будет создана ячейка. Введите в новую ячейку следующие данные. Замените CONTAINER и STORAGEACCOUNT именем учетной записи хранения Azure и именем контейнера больших двоичных объектов, который содержит данные службы Application Insights.

    %%bash
    hdfs dfs -ls wasbs://CONTAINER@STORAGEACCOUNT.blob.core.windows.net/
    

    Для выполнения этой ячейки используйте сочетание клавиш SHIFT+ВВОД. Отобразится результат, аналогичный следующему:

    Found 1 items
    drwxrwxrwx   -          0 1970-01-01 00:00 wasbs://appinsights@contosostore.blob.core.windows.net/contosoappinsights_2bededa61bc741fbdee6b556571a4831
    

    Полученный путь WASBS является расположением данных телеметрии Application Insights. Замените строку hdfs dfs -ls в ячейке на полученный путь WASBS, а затем используйте клавиши SHIFT+ВВОД для повторного выполнения ячейки. На этот раз в результате выполнения должны отобразиться каталоги, содержащие данные телеметрии.

    Примечание.

    Для остальных действий, описанных в этом разделе, использовался каталог wasbs://appinsights@contosostore.blob.core.windows.net/contosoappinsights_{ID}/Requests. Структура каталога может отличаться.

  6. В следующей ячейке введите код ниже: замените WASB_PATH на путь, который вы использовали на предыдущем шаге.

    jsonFiles = sc.textFile('WASB_PATH')
    jsonData = sqlContext.read.json(jsonFiles)
    

    Этот код создает кадр данных на основе файлов JSON, экспортируемых в процессе непрерывного экспорта. Для выполнения ячейки используйте сочетание клавиш SHIFT+ВВОД.

  7. В следующей ячейке введите и выполните такую команду, чтобы просмотреть схему, созданную Spark для JSON-файлов:

    jsonData.printSchema()
    

    Схемы для разных типов телеметрии будут отличаться. Ниже приведен пример схемы, созданной для веб-запросов (для данных, хранящихся в подкаталоге Requests):

    root
    |-- context: struct (nullable = true)
    |    |-- application: struct (nullable = true)
    |    |    |-- version: string (nullable = true)
    |    |-- custom: struct (nullable = true)
    |    |    |-- dimensions: array (nullable = true)
    |    |    |    |-- element: string (containsNull = true)
    |    |    |-- metrics: array (nullable = true)
    |    |    |    |-- element: string (containsNull = true)
    |    |-- data: struct (nullable = true)
    |    |    |-- eventTime: string (nullable = true)
    |    |    |-- isSynthetic: boolean (nullable = true)
    |    |    |-- samplingRate: double (nullable = true)
    |    |    |-- syntheticSource: string (nullable = true)
    |    |-- device: struct (nullable = true)
    |    |    |-- browser: string (nullable = true)
    |    |    |-- browserVersion: string (nullable = true)
    |    |    |-- deviceModel: string (nullable = true)
    |    |    |-- deviceName: string (nullable = true)
    |    |    |-- id: string (nullable = true)
    |    |    |-- osVersion: string (nullable = true)
    |    |    |-- type: string (nullable = true)
    |    |-- location: struct (nullable = true)
    |    |    |-- city: string (nullable = true)
    |    |    |-- clientip: string (nullable = true)
    |    |    |-- continent: string (nullable = true)
    |    |    |-- country: string (nullable = true)
    |    |    |-- province: string (nullable = true)
    |    |-- operation: struct (nullable = true)
    |    |    |-- name: string (nullable = true)
    |    |-- session: struct (nullable = true)
    |    |    |-- id: string (nullable = true)
    |    |    |-- isFirst: boolean (nullable = true)
    |    |-- user: struct (nullable = true)
    |    |    |-- anonId: string (nullable = true)
    |    |    |-- isAuthenticated: boolean (nullable = true)
    |-- internal: struct (nullable = true)
    |    |-- data: struct (nullable = true)
    |    |    |-- documentVersion: string (nullable = true)
    |    |    |-- id: string (nullable = true)
    |-- request: array (nullable = true)
    |    |-- element: struct (containsNull = true)
    |    |    |-- count: long (nullable = true)
    |    |    |-- durationMetric: struct (nullable = true)
    |    |    |    |-- count: double (nullable = true)
    |    |    |    |-- max: double (nullable = true)
    |    |    |    |-- min: double (nullable = true)
    |    |    |    |-- sampledValue: double (nullable = true)
    |    |    |    |-- stdDev: double (nullable = true)
    |    |    |    |-- value: double (nullable = true)
    |    |    |-- id: string (nullable = true)
    |    |    |-- name: string (nullable = true)
    |    |    |-- responseCode: long (nullable = true)
    |    |    |-- success: boolean (nullable = true)
    |    |    |-- url: string (nullable = true)
    |    |    |-- urlData: struct (nullable = true)
    |    |    |    |-- base: string (nullable = true)
    |    |    |    |-- hashTag: string (nullable = true)
    |    |    |    |-- host: string (nullable = true)
    |    |    |    |-- protocol: string (nullable = true)
    
  8. Чтобы зарегистрировать таблицу данных в качестве временной таблицы и выполнить запрос на основе этих данных, используйте следующую команду:

    jsonData.registerTempTable("requests")
    df = sqlContext.sql("select context.location.city from requests where context.location.city is not null")
    df.show()
    

    Этот запрос вернет сведения о городе для первых 20 записей, где параметр context.location.city не имеет значение NULL.

    Примечание.

    Структура контекста присутствует во всех данных телеметрии, записываемых Application Insights. Однако элемент city (город) в журналах может не заполняться. Используйте эту схему для определения других элементов, которые можно запросить и которые могут содержать данные для журналов.

    Этот запрос возвращает следующие сведения:

    +---------+
    |     city|
    +---------+
    | Bellevue|
    |  Redmond|
    |  Seattle|
    |Charlotte|
    ...
    +---------+
    

Анализ данных. Scala

  1. В веб-браузере перейдите на страницу https://CLUSTERNAME.azurehdinsight.net/jupyter, заменив CLUSTERNAME именем своего кластера.

  2. В правом верхнем углу страницы Jupyter щелкните Создать, а затем выберите Scala. При этом откроется новая вкладка браузера, содержащая записную книжку Jupyter на основе Scala.

  3. На этой странице в первом поле (которое называется ячейка) введите следующий текст:

    sc.hadoopConfiguration.set("mapreduce.input.fileinputformat.input.dir.recursive", "true")
    

    Этот код настраивает Spark рекурсивно обращаться к структуре каталогов для получения входных данных. Телеметрия Application Insights записывается в структуру каталогов, аналогичную этой: /{telemetry type}/YYYY-MM-DD/{##}/.

  4. Для выполнения кода используйте сочетание клавиш SHIFT+ВВОД. Слева от ячейки в скобках отобразится звездочка (*), показывая тем самым, что код в этой ячейке выполняется. После завершения выполнения звездочку (*) заменит число, а под ячейкой отобразятся данные, аналогичные следующим:

    Creating SparkContext as 'sc'
    
    ID    YARN Application ID    Kind    State    Spark UI    Driver log    Current session?
    3    application_1468969497124_0001    spark    idle    Link    Link    ✔
    
    Creating HiveContext as 'sqlContext'
    SparkContext and HiveContext created. Executing user code ...
    
  5. Под первой ячейкой будет создана ячейка. Введите в новую ячейку следующие данные. Замените CONTAINER и STORAGEACCOUNT именем учетной записи хранения Azure и именем контейнера больших двоичных объектов, который содержит журналы службы Application Insights.

    %%bash
    hdfs dfs -ls wasbs://CONTAINER@STORAGEACCOUNT.blob.core.windows.net/
    

    Для выполнения этой ячейки используйте сочетание клавиш SHIFT+ВВОД. Отобразится результат, аналогичный следующему:

    Found 1 items
    drwxrwxrwx   -          0 1970-01-01 00:00 wasbs://appinsights@contosostore.blob.core.windows.net/contosoappinsights_2bededa61bc741fbdee6b556571a4831
    

    Полученный путь WASBS является расположением данных телеметрии Application Insights. Замените строку hdfs dfs -ls в ячейке на полученный путь WASBS, а затем используйте клавиши SHIFT+ВВОД для повторного выполнения ячейки. На этот раз в результате выполнения должны отобразиться каталоги, содержащие данные телеметрии.

    Примечание.

    Для остальных действий, описанных в этом разделе, использовался каталог wasbs://appinsights@contosostore.blob.core.windows.net/contosoappinsights_{ID}/Requests. Этот каталог может отсутствовать, если ваши данные телеметрии не предназначены для веб-приложения.

  6. В следующей ячейке введите код ниже: замените WASB\_PATH на путь, который вы использовали на предыдущем шаге.

    var jsonFiles = sc.textFile('WASB_PATH')
    val sqlContext = new org.apache.spark.sql.SQLContext(sc)
    var jsonData = sqlContext.read.json(jsonFiles)
    

    Этот код создает кадр данных на основе файлов JSON, экспортируемых в процессе непрерывного экспорта. Для выполнения ячейки используйте сочетание клавиш SHIFT+ВВОД.

  7. В следующей ячейке введите и выполните такую команду, чтобы просмотреть схему, созданную Spark для JSON-файлов:

    jsonData.printSchema
    

    Схемы для разных типов телеметрии будут отличаться. Ниже приведен пример схемы, созданной для веб-запросов (для данных, хранящихся в подкаталоге Requests):

    root
    |-- context: struct (nullable = true)
    |    |-- application: struct (nullable = true)
    |    |    |-- version: string (nullable = true)
    |    |-- custom: struct (nullable = true)
    |    |    |-- dimensions: array (nullable = true)
    |    |    |    |-- element: string (containsNull = true)
    |    |    |-- metrics: array (nullable = true)
    |    |    |    |-- element: string (containsNull = true)
    |    |-- data: struct (nullable = true)
    |    |    |-- eventTime: string (nullable = true)
    |    |    |-- isSynthetic: boolean (nullable = true)
    |    |    |-- samplingRate: double (nullable = true)
    |    |    |-- syntheticSource: string (nullable = true)
    |    |-- device: struct (nullable = true)
    |    |    |-- browser: string (nullable = true)
    |    |    |-- browserVersion: string (nullable = true)
    |    |    |-- deviceModel: string (nullable = true)
    |    |    |-- deviceName: string (nullable = true)
    |    |    |-- id: string (nullable = true)
    |    |    |-- osVersion: string (nullable = true)
    |    |    |-- type: string (nullable = true)
    |    |-- location: struct (nullable = true)
    |    |    |-- city: string (nullable = true)
    |    |    |-- clientip: string (nullable = true)
    |    |    |-- continent: string (nullable = true)
    |    |    |-- country: string (nullable = true)
    |    |    |-- province: string (nullable = true)
    |    |-- operation: struct (nullable = true)
    |    |    |-- name: string (nullable = true)
    |    |-- session: struct (nullable = true)
    |    |    |-- id: string (nullable = true)
    |    |    |-- isFirst: boolean (nullable = true)
    |    |-- user: struct (nullable = true)
    |    |    |-- anonId: string (nullable = true)
    |    |    |-- isAuthenticated: boolean (nullable = true)
    |-- internal: struct (nullable = true)
    |    |-- data: struct (nullable = true)
    |    |    |-- documentVersion: string (nullable = true)
    |    |    |-- id: string (nullable = true)
    |-- request: array (nullable = true)
    |    |-- element: struct (containsNull = true)
    |    |    |-- count: long (nullable = true)
    |    |    |-- durationMetric: struct (nullable = true)
    |    |    |    |-- count: double (nullable = true)
    |    |    |    |-- max: double (nullable = true)
    |    |    |    |-- min: double (nullable = true)
    |    |    |    |-- sampledValue: double (nullable = true)
    |    |    |    |-- stdDev: double (nullable = true)
    |    |    |    |-- value: double (nullable = true)
    |    |    |-- id: string (nullable = true)
    |    |    |-- name: string (nullable = true)
    |    |    |-- responseCode: long (nullable = true)
    |    |    |-- success: boolean (nullable = true)
    |    |    |-- url: string (nullable = true)
    |    |    |-- urlData: struct (nullable = true)
    |    |    |    |-- base: string (nullable = true)
    |    |    |    |-- hashTag: string (nullable = true)
    |    |    |    |-- host: string (nullable = true)
    |    |    |    |-- protocol: string (nullable = true)
    
  8. Чтобы зарегистрировать таблицу данных в качестве временной таблицы и выполнить запрос на основе этих данных, используйте следующую команду:

    jsonData.registerTempTable("requests")
    var city = sqlContext.sql("select context.location.city from requests where context.location.city isn't null limit 10").show()
    

    Этот запрос вернет сведения о городе для первых 20 записей, где параметр context.location.city не имеет значение NULL.

    Примечание.

    Структура контекста присутствует во всех данных телеметрии, записываемых Application Insights. Однако элемент city (город) в журналах может не заполняться. Используйте эту схему для определения других элементов, которые можно запросить и которые могут содержать данные для журналов.

    Этот запрос возвращает следующие сведения:

    +---------+
    |     city|
    +---------+
    | Bellevue|
    |  Redmond|
    |  Seattle|
    |Charlotte|
    ...
    +---------+
    

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

Дополнительные примеры применения Apache Spark при работе с данными и службами в Azure см. в следующих документах:

Дополнительные сведения о создании и запуске приложений Spark см. в следующих документах: