Condividi tramite


Esercitazione: Rilevare e analizzare le anomalie usando le funzionalità di Machine Learning KQL in Monitoraggio di Azure

Il Linguaggio di query Kusto (KQL) include operatori di Machine Learning, funzioni e plug-in per l'analisi delle serie temporali, il rilevamento anomalie, la previsione e l'analisi della causa radice. Usare queste funzionalità KQL per eseguire analisi avanzate dei dati in Monitoraggio di Azure senza il sovraccarico dell'esportazione dei dati in strumenti di Machine Learning esterni.

In questa esercitazione apprenderai a:

  • Creare una serie temporale
  • Identificare le anomalie in una serie temporale
  • Modificare le impostazioni di rilevamento anomalie per perfezionare i risultati
  • Analizzare la causa radice delle anomalie

Nota

Questa esercitazione fornisce collegamenti a un ambiente demo di Log Analytics in cui è possibile eseguire gli esempi di query KQL. I dati nell'ambiente demo sono dinamici, quindi i risultati della query non corrispondono ai risultati della query mostrati in questo articolo. Tuttavia, è possibile implementare le stesse query e entità KQL nel proprio ambiente e tutti gli strumenti di Monitoraggio di Azure che usano KQL.

Prerequisiti

Autorizzazioni obbligatorie

Occorrono autorizzazioni Microsoft.OperationalInsights/workspaces/query/*/read per le aree di lavoro Log Analytics su cui si esegue la query, ad esempio le autorizzazioni fornite dal ruolo predefinito Lettore di Log Analytics.

Creare una serie temporale

Usare l'operatore make-series KQL per creare una serie temporale.

Si creerà una serie temporale basata sui log nella tabella Utilizzo, che contiene informazioni sulla quantità di dati inseriti ogni ora in un'area di lavoro, inclusi i dati fatturabili e non fatturabili.

Questa query usa make-series per creare un grafico della quantità totale di dati fatturabili inseriti da ogni tabella nell'area di lavoro ogni giorno, negli ultimi 21 giorni:

Fare clic per eseguire la query

let starttime = 21d; // The start date of the time series, counting back from the current date
let endtime = 0d; // The end date of the time series, counting back from the current date
let timeframe = 1d; // How often to sample data
Usage // The table we’re analyzing
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime))) // Time range for the query, beginning at 12:00 AM of the first day and ending at 12:00 AM of the last day in the time range
| where IsBillable == "true" // Include only billable data in the result set
| make-series ActualUsage=sum(Quantity) default = 0 on TimeGenerated from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe by DataType // Creates the time series, listed by data type 
| render timechart // Renders results in a timechart

Nel grafico risultante è possibile visualizzare chiaramente alcune anomalie, ad esempio nei tipi di dati AzureDiagnostics e SecurityEvent:

GIF animata che mostra un grafico dei dati totali inseriti da ogni tabella nell'area di lavoro ogni giorno, in oltre 21 giorni. Il cursore si sposta per evidenziare tre anomalie di utilizzo nel grafico.

Si userà quindi una funzione KQL per elencare tutte le anomalie in una serie temporale.

Nota

Per altre informazioni sulla sintassi e sull'utilizzo make-series, vedere operatore make-series.

Trovare anomalie in una serie temporale

La funzione series_decompose_anomalies() accetta una serie di valori come input ed estrae anomalie.

Assegnare ora il set di risultati della query serie temporale come input alla funzione series_decompose_anomalies():

Fare clic per eseguire la query

let starttime = 21d; // Start date for the time series, counting back from the current date
let endtime = 0d; // End date for the time series, counting back from the current date
let timeframe = 1d; // How often to sample data
Usage // The table we’re analyzing
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime))) // Time range for the query, beginning at 12:00 AM of the first day and ending at 12:00 AM of the last day in the time range
| where IsBillable == "true" // Includes only billable data in the result set
| make-series ActualUsage=sum(Quantity) default = 0 on TimeGenerated from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe by DataType // Creates the time series, listed by data type
| extend(Anomalies, AnomalyScore, ExpectedUsage) = series_decompose_anomalies(ActualUsage) // Scores and extracts anomalies based on the output of make-series 
| mv-expand ActualUsage to typeof(double), TimeGenerated to typeof(datetime), Anomalies to typeof(double),AnomalyScore to typeof(double), ExpectedUsage to typeof(long) // Expands the array created by series_decompose_anomalies()
| where Anomalies != 0  // Returns all positive and negative deviations from expected usage
| project TimeGenerated,ActualUsage,ExpectedUsage,AnomalyScore,Anomalies,DataType // Defines which columns to return 
| sort by abs(AnomalyScore) desc // Sorts results by anomaly score in descending ordering

Questa query restituisce tutte le anomalie di utilizzo per tutte le tabelle nelle ultime tre settimane:

Screenshot di una tabella che mostra un elenco di anomalie in uso per tutte le tabelle nell'area di lavoro.

Esaminando i risultati della query, è possibile osservare che la funzione :

  • Calcola un utilizzo giornaliero previsto per ogni tabella.
  • Confronta l'utilizzo giornaliero effettivo con l'utilizzo previsto.
  • Assegna un punteggio di anomalia a ogni punto dati, che indica l'estensione della deviazione dell'utilizzo effettivo rispetto all'utilizzo previsto.
  • Identifica anomalie positive (1) e negative (-1) in ogni tabella.

Nota

Per altre informazioni sulla sintassi e sull'utilizzo series_decompose_anomalies(), vedere series_decompose_anomalies().

Modificare le impostazioni di rilevamento anomalie per perfezionare i risultati

È consigliabile esaminare i risultati iniziali delle query e apportare modifiche alla query, se necessario. Gli outlier nei dati di input possono influire sull'apprendimento della funzione e potrebbe essere necessario modificare le impostazioni di rilevamento anomalie della funzione per ottenere risultati più accurati.

Filtrare i risultati della query series_decompose_anomalies() per individuare le anomalie nel tipo di dati AzureDiagnostics:

Tabella che mostra i risultati della query di rilevamento anomalie, filtrata per i risultati del tipo di dati Diagnostica di Azure.

I risultati mostrano due anomalie il 14 giugno e il 15 giugno. Confrontare questi risultati con il grafico della prima query make-series, in cui è possibile visualizzare altre anomalie il 27 maggio e il 28:

Screenshot che mostra un grafico dei dati totali inseriti dalla tabella Diagnostica di Azure con anomalie evidenziate.

La differenza nei risultati si verifica perché la funzione series_decompose_anomalies() assegna punteggi di anomalie rispetto al valore di utilizzo previsto, che la funzione calcola in base all'intervallo completo di valori nella serie di input.

Per ottenere risultati più raffinati dalla funzione, escludere l'utilizzo il 15 giugno, ovvero un outlier rispetto agli altri valori della serie, dal processo di apprendimento della funzione.

La sintassi della funzione series_decompose_anomalies() è:

series_decompose_anomalies (Series[Threshold,Seasonality,Trend,Test_points,AD_method,Seasonality_threshold])

Test_points specifica il numero di punti alla fine della serie da escludere dal processo di apprendimento (regressione).

Per escludere l'ultimo punto dati, impostare Test_points su 1:

Fare clic per eseguire la query

let starttime = 21d; // Start date for the time series, counting back from the current date
let endtime = 0d; // End date for the time series, counting back from the current date
let timeframe = 1d; // How often to sample data
Usage // The table we’re analyzing
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime))) // Time range for the query, beginning at 12:00 AM of the first day and ending at 12:00 AM of the last day in the time range
| where IsBillable == "true" // Includes only billable data in the result set
| make-series ActualUsage=sum(Quantity) default = 0 on TimeGenerated from startofday(ago(starttime)) to startofday(ago(endtime)) step timeframe by DataType // Creates the time series, listed by data type
| extend(Anomalies, AnomalyScore, ExpectedUsage) = series_decompose_anomalies(ActualUsage,1.5,-1,'avg',1) // Scores and extracts anomalies based on the output of make-series, excluding the last value in the series - the Threshold, Seasonality, and Trend input values are the default values for the function 
| mv-expand ActualUsage to typeof(double), TimeGenerated to typeof(datetime), Anomalies to typeof(double),AnomalyScore to typeof(double), ExpectedUsage to typeof(long) // Expands the array created by series_decompose_anomalies()
| where Anomalies != 0  // Returns all positive and negative deviations from expected usage
| project TimeGenerated,ActualUsage,ExpectedUsage,AnomalyScore,Anomalies,DataType // Defines which columns to return 
| sort by abs(AnomalyScore) desc // Sorts results by anomaly score in descending ordering

Filtrare i risultati per il tipo di dati AzureDiagnostics:

Tabella che mostra i risultati della query di rilevamento anomalie modificata, filtrata per i risultati del tipo di dati Diagnostica di Azure. I risultati mostrano ora le stesse anomalie del grafico creato all'inizio dell'esercitazione.

Tutte le anomalie nel grafico della prima query make-series vengono ora visualizzate nel set di risultati.

Analizzare la causa radice delle anomalie

Il confronto dei valori previsti con valori anomali consente di comprendere la causa delle differenze tra i due set.

Il plug-in diffpatterns() KQL confronta due set di dati della stessa struttura e trova modelli che caratterizzano le differenze tra i due set di dati.

Questa query confronta l'utilizzo di AzureDiagnostics il 15 giugno, l'outlier estremo nell'esempio, con l'utilizzo della tabella in altri giorni:

Fare clic per eseguire la query

let starttime = 21d; // Start date for the time series, counting back from the current date
let endtime = 0d; // End date for the time series, counting back from the current date
let anomalyDate = datetime_add('day',-1, make_datetime(startofday(ago(endtime)))); // Start of day of the anomaly date, which is the last full day in the time range in our example (you can replace this with a specific hard-coded anomaly date)
AzureDiagnostics	
| extend AnomalyDate = iff(startofday(TimeGenerated) == anomalyDate, "AnomalyDate", "OtherDates") // Adds calculated column called AnomalyDate, which splits the result set into two data sets – AnomalyDate and OtherDates
| where TimeGenerated between (startofday(ago(starttime))..startofday(ago(endtime))) // Defines the time range for the query
| project AnomalyDate, Resource // Defines which columns to return
| evaluate diffpatterns(AnomalyDate, "OtherDates", "AnomalyDate") // Compares usage on the anomaly date with the regular usage pattern

La query identifica ogni voce della tabella come si verifica in AnomalyDate (15 giugno) o OtherDates. Il plug-in diffpatterns() suddivide quindi questi set di dati, denominati A (OtherDates nell'esempio) e B (AnomalyDate nell'esempio) e restituisce alcuni modelli che contribuiscono alle differenze nei due set:

Screenshot che mostra una tabella con tre righe. Ogni riga mostra una differenza tra l'utilizzo dell'uso anomalo e l'utilizzo della baseline.

Esaminando i risultati della query, è possibile visualizzare le differenze seguenti:

  • Sono presenti 24.892.147 istanze di inserimento dalla risorsa CH1-GEARAMAAKS in tutti gli altri giorni nell'intervallo di tempo della query e nessun inserimento di dati da questa risorsa il 15 giugno. I dati della risorsa CH1-GEARAMAAKS sono pari al 73,36% dell'inserimento totale in altri giorni nell'intervallo di tempo della query e al 0% dell'inserimento totale il 15 giugno.
  • Sono presenti 2.168.448 istanze di inserimento dalla risorsa NSG-TESTSQLMI519 in tutti gli altri giorni nell'intervallo di tempo della query e 110.544 istanze di inserimento da questa risorsa il 15 giugno. I dati della risorsa NSG-TESTSQLMI519 sono pari al 6,39% dell'inserimento totale in altri giorni nell'intervallo di tempo della query e al 25,61% dell'inserimento il 15 giugno.

Si noti che, in media, sono presenti 108.422 istanze di inserimento dalla risorsa NSG-TESTSQLMI519 durante i 20 giorni che costituiscono il periodo altri giorni (dividere 2.168.448 per 20). Di conseguenza, l'inserimento dalla risorsa NSG-TESTSQLMI519 il 15 giugno non è significativamente diverso dall'inserimento da questa risorsa in altri giorni. Tuttavia, poiché non è presente alcun inserimento da CH1-GEARAMAAKS il 15 giugno, l'inserimento da NSG-TESTSQLMI519 costituisce una percentuale significativamente maggiore dell'inserimento totale sulla data di anomalia rispetto agli altri giorni.

La colonna PercentDiffAB mostra la differenza del punto percentuale assoluto tra A e B (|PercentA - PercentB|), ovvero la misura principale della differenza tra i due set. Per impostazione predefinita, il plug-in diffpatterns() restituisce la differenza di oltre il 5% tra i due set di dati, ma è possibile modificare questa soglia. Ad esempio, per restituire solo le differenze del 20% o più tra i due set di dati, è possibile impostare | evaluate diffpatterns(AnomalyDate, "OtherDates", "AnomalyDate", "~", 0.20) nella query precedente. La query restituisce ora un solo risultato:

Screenshot che mostra una tabella con una riga che presenta una differenza tra l'utilizzo nell'uso anomalo e l'utilizzo di base. Questa volta, la query non ha restituito differenze inferiori al 20% tra i due set di dati.

Nota

Per altre informazioni sulla sintassi e sull'utilizzo diffpatterns(), vedere plug-in modelli diff.

Passaggi successivi

Altre informazioni su: