Kurz: Detekce a analýza anomálií pomocí funkcí strojového učení KQL ve službě Azure Monitor

Dotazovací jazyk Kusto (KQL) zahrnuje operátory strojového učení, funkce a moduly plug-in pro analýzu časových řad, detekci anomálií, prognózování a analýzu původní příčiny. Pomocí těchto funkcí KQL můžete provádět pokročilou analýzu dat ve službě Azure Monitor bez režie při exportu dat do externích nástrojů strojového učení.

V tomto kurzu se naučíte:

  • Vytvoření časové řady
  • Identifikace anomálií v časové řadě
  • Vylepšení nastavení detekce anomálií za účelem upřesnění výsledků
  • Analýza původní příčiny anomálií

Poznámka:

Tento kurz obsahuje odkazy na ukázkové prostředí Log Analytics, ve kterém můžete spustit příklady dotazů KQL. Data v ukázkovém prostředí jsou dynamická, takže výsledky dotazu nejsou stejné jako výsledky dotazu uvedené v tomto článku. Ve svém vlastním prostředí však můžete implementovat stejné dotazy KQL a principy, a všechny nástroje Azure Monitoru, které používají KQL.

Požadavky

Požadována oprávnění

Musíte mít Microsoft.OperationalInsights/workspaces/query/*/read oprávnění k pracovním prostorům služby Log Analytics, na které provádíte dotazy, jak například poskytuje vestavěná role Čtenář Log Analytics.

Vytvoření časové řady

K vytvoření časové řady použijte operátor KQL make-series .

Pojďme vytvořit časovou řadu na základě protokolů v tabulce Využití, která obsahuje informace o tom, kolik dat každá tabulka v pracovním prostoru ingestuje každou hodinu, včetně fakturovatelných a nefakturovatelných dat.

Tento dotaz používá make-series k vytvoření grafu celkového množství fakturovatelných dat přijatých každou tabulkou v pracovním prostoru každý den za posledních 21 dnů:

Kliknutím spustíte dotaz.

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

Ve výsledném grafu můžete jasně vidět některé anomálie – například v AzureDiagnostics datových typech:SecurityEvent

Animovaný obrázek GIF zobrazující graf celkových dat přijatých každou tabulkou v pracovním prostoru každý den, více než 21 dnů. Kurzor se přesune a zvýrazní tři anomálie využití v grafu.

V dalším kroku použijeme funkci KQL k výpisu všech anomálií v časové řadě.

Poznámka:

Další informace o syntaxi a použití make-series viz operátor make-series.

Vyhledání anomálií v časové řadě

Funkce series_decompose_anomalies() přebírá jako vstup řadu hodnot a extrahuje anomálie.

Pojďme dát sadu výsledků dotazu na časovou řadu jako vstup funkci series_decompose_anomalies().

Kliknutím spustíte dotaz.

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

Tento dotaz vrátí všechny anomálie využití pro všechny tabulky za poslední tři týdny:

Snímek obrazovky tabulky, která zobrazuje seznam anomálií v použití všech tabulek v pracovním prostoru.

Když se podíváte na výsledky dotazu, uvidíte, že funkce:

  • Vypočítá očekávané denní využití pro každou tabulku.
  • Porovná skutečné denní využití s očekávaným využitím.
  • Přiřadí každému datovému bodu skóre anomálií, které označuje rozsah odchylky skutečného využití od očekávaného využití.
  • Identifikuje kladné () a záporné (1-1) anomálie v každé tabulce.

Poznámka:

Další informace o series_decompose_anomalies() syntaxi a použití najdete v tématu series_decompose_anomalies().

Vylepšení nastavení detekce anomálií za účelem upřesnění výsledků

Je vhodné zkontrolovat počáteční výsledky dotazu a v případě potřeby ho upravit. Odlehlé hodnoty ve vstupních datech můžou ovlivnit učení funkce a možná budete muset upravit nastavení detekce anomálií funkce, abyste získali přesnější výsledky.

Vyfiltrujte výsledky series_decompose_anomalies() dotazu na anomálie v datovém AzureDiagnostics typu:

Tabulka zobrazující výsledky dotazu detekce anomálií filtrovaná pro výsledky z datového typu Azure Diagnostics.

Výsledky zobrazují dvě anomálie 14. června a 15. června. Porovnejte tyto výsledky s grafem z našeho prvního make-series dotazu, kde můžete vidět další anomálie 27. května a 28:

Snímek obrazovky znázorňující graf celkových ingestovaných dat tabulkou Azure Diagnostics se zvýrazněnými anomáliemi

Rozdíl ve výsledcích nastane, protože series_decompose_anomalies() funkce vyhodnotí anomálie vzhledem k očekávané hodnotě využití, kterou funkce vypočítá na základě úplného rozsahu hodnot ve vstupní řadě.

Pokud chcete z funkce získat přesnější výsledky, vylučte z procesu učení funkce použití 15. června, což je odlehlá hodnota v porovnání s ostatními hodnotami v řadě.

Syntaxe funkce series_decompose_anomalies() je:

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

Test_points určuje počet bodů na konci řady, které se mají vyloučit z procesu učení (regrese).

Pokud chcete vyloučit poslední datový bod, nastavte Test_points hodnotu 1:

Kliknutím spustíte dotaz.

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

Vyfiltrujte výsledky pro AzureDiagnostics datový typ:

Tabulka zobrazující výsledky upraveného dotazu detekce anomálií filtrované pro výsledky z datového typu Azure Diagnostics. Výsledky teď zobrazují stejné anomálie jako graf vytvořený na začátku kurzu.

Všechny anomálie v grafu z prvního make-series dotazu se teď zobrazují v sadě výsledků.

Analýza původní příčiny anomálií

Porovnání očekávaných hodnot s neobvyklými hodnotami vám pomůže pochopit příčinu rozdílů mezi těmito dvěma sadami.

Modul plug-in KQL diffpatterns() porovnává dvě datové sady stejné struktury a najde vzory, které charakterizují rozdíly mezi těmito dvěma datovými sadami.

Tento dotaz porovnává AzureDiagnostics využití 15. června, nejextrémnější odlehlé hodnoty v našem příkladu, s využitím tabulky v jiné dny:

Kliknutím spustíte dotaz.

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

Dotaz identifikuje každou položku v tabulce jako výskyt k datumu anomálie (15. června) nebo k jiným datumům. Plug-in diffpatterns() pak tyto datové sady rozdělí – označované jako A (JinéTermíny v našem příkladu) a B (DatumAnomálie v našem příkladu) – a vrátí několik vzorců, které přispívají k rozdílům v těchto dvou sadách.

Snímek obrazovky zobrazující tabulku se třemi řádky Každý řádek zobrazuje rozdíl mezi použitím neobvyklých a standardních hodnot.

Když se podíváte na výsledky dotazu, uvidíte následující rozdíly:

  • Ve všech ostatních dnech v časovém rozsahu dotazů bylo zaznamenáno 24 892 147 instancí příjmu dat z prostředku CH1-GEARAMAAKS, zatímco k žádnému příjmu dat z tohoto prostředku nedošlo 15. června. Data z prostředků CH1-GEARAMAAKS představují 73,36 % celkového příjmu dat v jiných dnech v časovém rozsahu dotazů a 0 % celkového příjmu dat 15. června.
  • Ve všech ostatních dnech v časovém rozsahu dotazů existuje 2 168 448 instancí příjmu dat z prostředku NSG-TESTSQLMI519 a 110 544 instancí příjmu dat z tohoto prostředku dne 15. června. Data z NSG-TESTSQLMI519 prostředků představují 6,39 % celkového příjmu dat v jiných dnech v časovém rozsahu dotazů a 25,61 % příjmu dat 15. června.

Všimněte si, že v průměru dochází k 108 422 případům příjmu z prostředku NSG-TESTSQLMI519 během 20 dnů, které tvoří období ostatních dnů (dělíme 2 168 448 dvaceti). Příjem dat z prostředku NSG-TESTSQLMI519 15. června se proto výrazně neliší od příjmu dat z tohoto prostředku v jiných dnech. Vzhledem k tomu, že 15. června nedošlo k příjmu dat z CH1-GEARAMAAKS, příjem dat z NSG-TESTSQLMI519 tvoří výrazně větší procento celkového příjmu v den anomálie ve srovnání s jinými dny.

Sloupec PercentDiffAB zobrazuje absolutní procentuální rozdíl mezi A a B (|PercentA – PercentB|), což je hlavní míra rozdílu mezi těmito dvěma sadami. Ve výchozím nastavení vrátí plugin diffpatterns() rozdíl větší než 5 % mezi dvěma datovými sadami, ale můžete tuto prahovou hodnotu upravit. Pokud například chcete vrátit pouze rozdíly 20 % nebo více mezi těmito dvěma datovými sadami, můžete je nastavit | evaluate diffpatterns(AnomalyDate, "OtherDates", "AnomalyDate", "~", 0.20) v dotazu výše. Dotaz teď vrátí jenom jeden výsledek:

Snímek obrazovky zobrazující tabulku s jedním řádkem, který ukazuje rozdíl mezi anomálním použitím a základním použitím. Tentokrát dotaz nevrátil rozdíly menší než 20 procent mezi těmito dvěma sadami dat.

Poznámka:

Další informace o diffpatterns() syntaxi a použití najdete v tématu modul plug-in rozdílové vzory.

Další kroky

Přečtěte si další informace: