Share via


Monitorare ed eseguire il debug di un'applicazione .NET di Azure Batch con Application Insights

Application Insights offre agli sviluppatori un modo elegante e potente per monitorare ed eseguire il debug delle applicazioni distribuite nei servizi di Azure. Usare Application Insights per monitorare i contatori delle prestazioni e le eccezioni, nonché per instrumentare il codice con metriche e funzionalità di traccia personalizzate. L'integrazione di Application Insights con l'applicazione Azure Batch consente di ottenere informazioni dettagliate sui comportamenti e di analizzare i problemi in tempo quasi reale.

Questo articolo illustra come aggiungere e configurare la libreria di Application Insights nella soluzione .NET di Azure Batch e instrumentare il codice dell'applicazione. Vengono inoltre presentati i modi per monitorare l'applicazione tramite il portale di Azure e creare dashboard personalizzati. Per il supporto di Application Insights in altri linguaggi, vedere la documentazione relativa a lingue, piattaforme e integrazioni.

In GitHub è disponibile una soluzione C# di esempio con codice per seguire questo articolo. Questo esempio aggiunge codice di strumentazione di Application Insights all'esempio TopNWords. Se non si ha familiarità con tale esempio, provare prima di tutto a compilare ed eseguire TopNWords. In questo modo sarà possibile comprendere un flusso di lavoro semplice di Batch per l'elaborazione di un set di BLOB di input in parallelo su più nodi di calcolo.

Suggerimento

In alternativa, configurare la soluzione Batch per visualizzare i dati di Application Insights, ad esempio i contatori delle prestazioni delle macchine virtuali in Batch Explorer. Batch Explorer è uno strumento client autonomo, gratuito e ricco di funzionalità che consente di creare, eseguire il debug e monitorare le applicazioni di Azure Batch. È possibile scaricare un pacchetto di installazione per Mac, Linux o Windows. Vedere il repository di informazioni dettagliate su Batch per azioni rapide per abilitare i dati di Application Insights in Batch Explorer.

Prerequisiti

Aggiunta di Application Insights al progetto

Per il progetto sono necessari il pacchetto NuGet Microsoft.ApplicationInsights.WindowsServer e le relative dipendenze. Aggiungerli o ripristinarli nel progetto dell'applicazione. Per installare il pacchetto, usare il comando Install-Package o Gestione pacchetti NuGet.

Install-Package Microsoft.ApplicationInsights.WindowsServer

Aggiungere un riferimento ad Application Insights nell'applicazione .NET tramite lo spazio dei nomi Microsoft.ApplicationInsights.

Instrumentare il codice

Per instrumentare il codice, la soluzione deve creare un TelemetryClient di Application Insights. Nell'esempio, il TelemetryClient carica la relativa configurazione dal file ApplicationInsights.config. Assicurarsi di aggiornare il file ApplicationInsights.config nei progetti seguenti con la chiave di strumentazione di Application Insights: Microsoft.Azure.Batch.Samples.TelemetryStartTask e TopNWordsSample.

<InstrumentationKey>YOUR-IKEY-GOES-HERE</InstrumentationKey>

Aggiungere la chiave di strumentazione anche al file TopNWords.cs.

L'esempio in TopNWords.cs usa le chiamate di strumentazione seguenti dall'API Application Insights:

  • TrackMetric() - Tiene traccia del tempo medio richiesto per il download del file di testo richiesto dal nodo di calcolo.
  • TrackTrace() - Aggiunge le chiamate di debug al codice.
  • TrackEvent() - Tiene traccia degli eventi interessanti da acquisire.

Questo esempio esclude intenzionalmente la gestione delle eccezioni. Application Insights segnala invece automaticamente le eccezioni non gestite, con un miglioramento notevole dell'esperienza di debug.

Il frammento di codice seguente illustra come usare questi metodi.

public void CountWords(string blobName, int numTopN, string storageAccountName, string storageAccountKey)
{
    // simulate exception for some set of tasks
    Random rand = new Random();
    if (rand.Next(0, 10) % 10 == 0)
    {
        blobName += ".badUrl";
    }

    // log the url we are downloading the file from
    insightsClient.TrackTrace(new TraceTelemetry(string.Format("Task {0}: Download file from: {1}", this.taskId, blobName), SeverityLevel.Verbose));

    // open the cloud blob that contains the book
    var storageCred = new StorageCredentials(storageAccountName, storageAccountKey);
    CloudBlockBlob blob = new CloudBlockBlob(new Uri(blobName), storageCred);
    using (Stream memoryStream = new MemoryStream())
    {
        // calculate blob download time
        DateTime start = DateTime.Now;
        blob.DownloadToStream(memoryStream);
        TimeSpan downloadTime = DateTime.Now.Subtract(start);

        // track how long the blob takes to download on this node
        // this will help debug timing issues or identify poorly performing nodes
        insightsClient.TrackMetric("Blob download in seconds", downloadTime.TotalSeconds, this.CommonProperties);

        memoryStream.Position = 0; //Reset the stream
        var sr = new StreamReader(memoryStream);
        var myStr = sr.ReadToEnd();
        string[] words = myStr.Split(' ');

        // log how many words were found in the text file
        insightsClient.TrackTrace(new TraceTelemetry(string.Format("Task {0}: Found {1} words", this.taskId, words.Length), SeverityLevel.Verbose));
        var topNWords =
            words.
                Where(word => word.Length > 0).
                GroupBy(word => word, (key, group) => new KeyValuePair<String, long>(key, group.LongCount())).
                OrderByDescending(x => x.Value).
                Take(numTopN).
                ToList();
        foreach (var pair in topNWords)
        {
            Console.WriteLine("{0} {1}", pair.Key, pair.Value);
        }

        // emit an event to track the completion of the task
        insightsClient.TrackEvent("Done counting words");
    }
}

Helper dell'inizializzatore di telemetria di Azure Batch

Quando si segnalano i dati di telemetria per un determinato server e un'istanza, Application Insights usa il ruolo di macchina virtuale di Azure e il nome della macchina virtuale per i valori predefiniti. Nel contesto di Azure Batch, l'esempio mostra come usare invece il nome del pool e il nome del nodo di calcolo. Usare un inizializzatore di telemetria per sostituire i valori predefiniti.

using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using System;
using System.Threading;

namespace Microsoft.Azure.Batch.Samples.TelemetryInitializer
{
    public class AzureBatchNodeTelemetryInitializer : ITelemetryInitializer
    {
        // Azure Batch environment variables
        private const string PoolIdEnvironmentVariable = "AZ_BATCH_POOL_ID";
        private const string NodeIdEnvironmentVariable = "AZ_BATCH_NODE_ID";

        private string roleInstanceName;
        private string roleName;

        public void Initialize(ITelemetry telemetry)
        {
            if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName))
            {
                // override the role name with the Azure Batch Pool name
                string name = LazyInitializer.EnsureInitialized(ref this.roleName, this.GetPoolName);
                telemetry.Context.Cloud.RoleName = name;
            }

            if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleInstance))
            {
                // override the role instance with the Azure Batch Compute Node name
                string name = LazyInitializer.EnsureInitialized(ref this.roleInstanceName, this.GetNodeName);
                telemetry.Context.Cloud.RoleInstance = name;
            }
        }

        private string GetPoolName()
        {
            return Environment.GetEnvironmentVariable(PoolIdEnvironmentVariable) ?? string.Empty;
        }

        private string GetNodeName()
        {
            return Environment.GetEnvironmentVariable(NodeIdEnvironmentVariable) ?? string.Empty;
        }
    }
}

Per abilitare l'inizializzatore di telemetria, il file Applicationinsights.config nel progetto TopNWordsSample include quanto segue:

<TelemetryInitializers>
    <Add Type="Microsoft.Azure.Batch.Samples.TelemetryInitializer.AzureBatchNodeTelemetryInitializer, Microsoft.Azure.Batch.Samples.TelemetryInitializer"/>
</TelemetryInitializers>

Aggiornare il processo e le attività per includere i file binari di Application Insights

Per la corretta esecuzione di Application Insights sui nodi di calcolo, assicurarsi che i file binari siano posizionati correttamente. Aggiungere i file binari necessari alla raccolta di file di risorse dell'attività, in modo che vengano scaricati in fase di esecuzione dell'attività. I frammenti di codice seguenti sono simili al codice in Job.cs.

Prima di tutto, creare un elenco statico di file di Application Insights da caricare.

private static readonly List<string> AIFilesToUpload = new List<string>()
{
    // Application Insights config and assemblies
    "ApplicationInsights.config",
    "Microsoft.ApplicationInsights.dll",
    "Microsoft.AI.Agent.Intercept.dll",
    "Microsoft.AI.DependencyCollector.dll",
    "Microsoft.AI.PerfCounterCollector.dll",
    "Microsoft.AI.ServerTelemetryChannel.dll",
    "Microsoft.AI.WindowsServer.dll",
    
    // custom telemetry initializer assemblies
    "Microsoft.Azure.Batch.Samples.TelemetryInitializer.dll",
 };
...

Successivamente, creare i file di gestione temporanea usati dall'attività.

...
// create file staging objects that represent the executable and its dependent assembly to run as the task.
// These files are copied to every node before the corresponding task is scheduled to run on that node.
FileToStage topNWordExe = new FileToStage(TopNWordsExeName, stagingStorageAccount);
FileToStage storageDll = new FileToStage(StorageClientDllName, stagingStorageAccount);

// Upload Application Insights assemblies
List<FileToStage> aiStagedFiles = new List<FileToStage>();
foreach (string aiFile in AIFilesToUpload)
{
    aiStagedFiles.Add(new FileToStage(aiFile, stagingStorageAccount));
}
...

Il metodo FileToStage è una funzione helper nell'esempio di codice che consente di caricare facilmente un file dal disco locale in un BLOB di Archiviazione di Azure. Ogni file viene in seguito scaricato in un nodo di calcolo e un'attività vi fa riferimento.

Infine, aggiungere le attività al processo e includere i file binari di Application Insights necessari.

...
// initialize a collection to hold the tasks that will be submitted in their entirety
List<CloudTask> tasksToRun = new List<CloudTask>(topNWordsConfiguration.NumberOfTasks);
for (int i = 1; i <= topNWordsConfiguration.NumberOfTasks; i++)
{
    CloudTask task = new CloudTask("task_no_" + i, String.Format("{0} --Task {1} {2} {3} {4}",
        TopNWordsExeName,
        string.Format("https://{0}.blob.core.windows.net/{1}",
            accountSettings.StorageAccountName,
            documents[i]),
        topNWordsConfiguration.TopWordCount,
        accountSettings.StorageAccountName,
        accountSettings.StorageAccountKey));

    //This is the list of files to stage to a container -- for each job, one container is created and 
    //files all resolve to Azure Blobs by their name (so two tasks with the same named file will create just 1 blob in
    //the container).
    task.FilesToStage = new List<IFileStagingProvider>
                        {
                            // required application binaries
                            topNWordExe,
                            storageDll,
                        };
    foreach (FileToStage stagedFile in aiStagedFiles)
   {
        task.FilesToStage.Add(stagedFile);
   }    
    task.RunElevated = false;
    tasksToRun.Add(task);
}

Visualizzare i dati nel portale di Azure

Dopo aver configurato il processo e le attività per usare Application Insights, eseguire il processo di esempio nel pool. Passare al portale di Azure e aprire la risorsa di Application Insights di cui è stato eseguito il provisioning. Dopo il provisioning del pool dovrebbero iniziare il flusso dei dati e la relativa registrazione. Il resto di questo articolo descrive brevemente solo alcune funzionalità di Application Insights, ma può essere utile esplorare il set completo di funzionalità.

Visualizzare i dati di Live Stream

Per visualizzare i log di traccia nella risorsa di Application Insights, fare clic su Live Stream. Lo screenshot seguente mostra come visualizzare i dati in tempo reale provenienti dai nodi di calcolo nel pool, ad esempio l'utilizzo della CPU per ogni nodo di calcolo.

Screenshot dei dati dei nodi di calcolo del flusso live.

Visualizzare i log di traccia

Per visualizzare i log di traccia nella risorsa di Application Insights, fare clic su Cerca. Questa visualizzazione mostra un elenco dei dati di diagnostica acquisiti da Application Insights, inclusi eventi, tracce ed eccezioni.

Lo screenshot seguente mostra come registrare una singola traccia per un'attività e poi sottoporla a query per scopi di debug.

Screenshot che mostra i log per una singola traccia.

Visualizzare le eccezioni non gestite

Application Insights registra le eccezioni generate dall'applicazione. In questo caso, entro pochi secondi da quando l'applicazione genera l'eccezione, è possibile analizzare un'eccezione specifica e diagnosticare il problema.

Screenshot che mostra le eccezioni non gestite.

Misurare i tempi di download dei BLOB

Anche le metriche personalizzate sono uno strumento prezioso nel portale. Ad esempio, è possibile visualizzare il tempo medio impiegato per scaricare il file di testo richiesto per l'elaborazione da ogni nodo di calcolo.

Per creare un grafico di esempio:

  1. Nella risorsa di Application Insights fare clic su Esplora metriche>Aggiungi grafico.
  2. Fare clic su Modifica nel grafico aggiunto.
  3. Aggiornare i dettagli del grafico come segue:
    • Impostare Tipo di grafico su Griglia.
    • Impostare Aggregazione su Media.
    • Impostare Raggruppa per su NodeId.
    • In Metriche selezionare Personalizzato>Blob download in seconds (Download BLOB in secondi).
    • Modificare la visualizzazione della Tavolozza dei colori in base alle preferenze.

Screenshot di un grafico che mostra l'ora di download del BLOB per ogni nodo.

Monitoraggio continuo dei nodi di calcolo

Probabilmente si è notato che tutte le metriche, inclusi i contatori delle prestazioni, vengono registrate solo durante l'esecuzione delle attività. Questo comportamento è utile perché limita la quantità di dati registrata da Application Insights. In alcuni casi, tuttavia, può essere necessario monitorare sempre i nodi di calcolo, ad esempio perché eseguono attività in background che non sono pianificate tramite il servizio Batch. In questo caso, configurare un processo di monitoraggio per l'esecuzione per la durata del nodo di calcolo.

Un modo per ottenere questo comportamento consiste nel generare un processo che carica la libreria di Application Insights e viene eseguito in background. Nell'esempio, l'attività di avvio carica i file binari nel computer e mantiene un processo in esecuzione per un periodo illimitato. Configurare il file di configurazione di Application Insights in modo che questo processo produca i dati aggiuntivi di interesse, ad esempio contatori delle prestazioni.

...
 // Batch start task telemetry runner
private const string BatchStartTaskFolderName = "StartTask";
private const string BatchStartTaskTelemetryRunnerName = "Microsoft.Azure.Batch.Samples.TelemetryStartTask.exe";
private const string BatchStartTaskTelemetryRunnerAIConfig = "ApplicationInsights.config";
...
CloudPool pool = client.PoolOperations.CreatePool(
    topNWordsConfiguration.PoolId,
    targetDedicated: topNWordsConfiguration.PoolNodeCount,
    virtualMachineSize: "standard_d1_v2",
    VirtualMachineConfiguration: new VirtualMachineConfiguration(
    imageReference: new ImageReference(
                        publisher: "MicrosoftWindowsServer",
                        offer: "WindowsServer",
                        sku: "2019-datacenter-core",
                        version: "latest"),
    nodeAgentSkuId: "batch.node.windows amd64");
...

// Create a start task which will run a dummy exe in background that simply emits performance
// counter data as defined in the relevant ApplicationInsights.config.
// Note that the waitForSuccess on the start task was not set so the Compute Node will be
// available immediately after this command is run.
pool.StartTask = new StartTask()
{
    CommandLine = string.Format("cmd /c {0}", BatchStartTaskTelemetryRunnerName),
    ResourceFiles = resourceFiles
};
...

Suggerimento

Per aumentare la gestibilità della soluzione, è possibile aggregare l'assembly in un pacchetto di applicazione. Quindi, per distribuire automaticamente il pacchetto dell'applicazione nei pool, aggiungere un riferimento al pacchetto dell'applicazione nella configurazione del pool.

Limitazione e dati di esempio

Tenendo conto del fatto che le applicazioni di Azure Batch in esecuzione in ambiente di produzione sono per natura su larga scala, potrebbe essere utile limitare la quantità di dati raccolti da Application Insights per gestire i costi. Vedere Campionamento in Application Insights per informazioni su alcuni meccanismi per ottenere questo risultato.

Passaggi successivi