Bagikan melalui


Tutorial: Mendeteksi dan menganalisis anomali menggunakan kemampuan pembelajaran mesin KQL di Azure Monitor

Bahasa Kueri Kusto (KQL) mencakup operator pembelajaran mesin, fungsi, dan plugin untuk analisis rangkaian waktu, deteksi anomali, prakiraan, dan analisis akar penyebab. Gunakan kemampuan KQL ini untuk melakukan analisis data tingkat lanjut di Azure Monitor tanpa overhead mengekspor data ke alat pembelajaran mesin eksternal.

Dalam tutorial ini, Anda akan mempelajari cara:

  • Membuat rangkaian waktu
  • Mengidentifikasi anomali dalam rangkaian waktu
  • Mengubah pengaturan deteksi anomali untuk menyempurnakan hasil
  • Menganalisis akar penyebab anomali

Catatan

Tutorial ini menyediakan tautan ke lingkungan demo Analitik Log tempat Anda dapat menjalankan contoh kueri KQL. Data di lingkungan demo bersifat dinamis, sehingga hasil kueri tidak sama dengan hasil kueri yang diperlihatkan dalam artikel ini. Namun, Anda dapat menerapkan kueri dan prinsipal KQL yang sama di lingkungan Anda sendiri dan semua alat Azure Monitor yang menggunakan KQL.

Prasyarat

Izin yang diperlukan

Anda harus memiliki Microsoft.OperationalInsights/workspaces/query/*/read izin ke ruang kerja Analitik Log yang Anda kueri, seperti yang disediakan oleh peran bawaan Pembaca Analitik Log, misalnya.

Membuat rangkaian waktu

Gunakan operator KQL make-series untuk membuat rangkaian waktu.

Mari kita buat rangkaian waktu berdasarkan log dalam tabel Penggunaan, yang menyimpan informasi tentang berapa banyak data setiap tabel di ruang kerja yang diserap setiap jam, termasuk data yang dapat ditagih dan tidak dapat ditagih.

Kueri ini menggunakan make-series untuk membuat bagan jumlah total data yang dapat ditagih yang diserap oleh setiap tabel di ruang kerja setiap hari, selama 21 hari terakhir:

Klik untuk menjalankan kueri

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

Dalam bagan yang dihasilkan, Anda dapat dengan jelas melihat beberapa anomali - misalnya, dalam AzureDiagnostics jenis data dan SecurityEvent :

GIF animasi memperlihatkan bagan dari total data yang diserap oleh setiap tabel di ruang kerja setiap hari, selama 21 hari. Kursor bergerak untuk menyoroti tiga anomali penggunaan pada bagan.

Selanjutnya, kita akan menggunakan fungsi KQL untuk mencantumkan semua anomali dalam rangkaian waktu.

Catatan

Untuk informasi selengkapnya tentang make-series sintaksis dan penggunaan, lihat operator seri buatan.

Menemukan anomali dalam rangkaian waktu

Fungsi ini series_decompose_anomalies() mengambil serangkaian nilai sebagai input dan mengekstrak anomali.

Mari kita berikan kumpulan hasil kueri rangkaian waktu sebagai input ke series_decompose_anomalies() fungsi:

Klik untuk menjalankan kueri

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

Kueri ini mengembalikan semua anomali penggunaan untuk semua tabel dalam tiga minggu terakhir:

Cuplikan layar tabel memperlihatkan daftar anomali dalam penggunaan untuk semua tabel di ruang kerja.

Melihat hasil kueri, Anda bisa melihat bahwa fungsi:

  • Menghitung penggunaan harian yang diharapkan untuk setiap tabel.
  • Membandingkan penggunaan harian aktual dengan penggunaan yang diharapkan.
  • Menetapkan skor anomali ke setiap titik data, menunjukkan sejauh mana penyimpangan penggunaan aktual dari penggunaan yang diharapkan.
  • Mengidentifikasi anomali positif (1) dan negatif (-1) di setiap tabel.

Catatan

Untuk informasi selengkapnya tentang series_decompose_anomalies() sintaksis dan penggunaan, lihat series_decompose_anomalies().

Mengubah pengaturan deteksi anomali untuk menyempurnakan hasil

Adalah praktik yang baik untuk meninjau hasil kueri awal dan membuat perubahan pada kueri, jika perlu. Outlier dalam data input dapat memengaruhi pembelajaran fungsi, dan Anda mungkin perlu menyesuaikan pengaturan deteksi anomali fungsi untuk mendapatkan hasil yang lebih akurat.

Filter hasil series_decompose_anomalies() kueri untuk anomali dalam AzureDiagnostics jenis data:

Tabel yang memperlihatkan hasil kueri deteksi anomali, difilter untuk hasil dari jenis data Azure Diagnostics.

Hasilnya menunjukkan dua anomali pada 14 Juni dan 15 Juni. Bandingkan hasil ini dengan bagan dari kueri pertama make-series kami, di mana Anda dapat melihat anomali lain pada 27 dan 28 Mei:

Cuplikan layar memperlihatkan bagan dari total data yang diserap oleh tabel Diagnostik Azure dengan anomali disorot.

Perbedaan hasil terjadi karena series_decompose_anomalies() fungsi menilai anomali relatif terhadap nilai penggunaan yang diharapkan, yang dihitung fungsi berdasarkan rentang penuh nilai dalam seri input.

Untuk mendapatkan hasil yang lebih halus dari fungsi, kecualikan penggunaan pada 15 Juni - yang merupakan outlier dibandingkan dengan nilai lain dalam seri - dari proses pembelajaran fungsi.

Sintaks series_decompose_anomalies() fungsi adalah:

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

Test_points menentukan jumlah titik di akhir seri yang akan dikecualikan dari proses pembelajaran (regresi).

Untuk mengecualikan titik data terakhir, atur Test_points ke 1:

Klik untuk menjalankan kueri

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

Filter hasil untuk AzureDiagnostics jenis data:

Tabel yang memperlihatkan hasil kueri deteksi anomali yang dimodifikasi, difilter untuk hasil dari jenis data Azure Diagnostics. Hasilnya sekarang menunjukkan anomali yang sama dengan bagan yang dibuat di awal tutorial.

Semua anomali dalam bagan dari kueri pertama make-series kami sekarang muncul dalam tataan hasil.

Menganalisis akar penyebab anomali

Membandingkan nilai yang diharapkan dengan nilai anomali membantu Anda memahami penyebab perbedaan antara dua set.

Plugin KQL diffpatterns() membandingkan dua himpunan data dari struktur yang sama dan menemukan pola yang mencirikan perbedaan antara dua himpunan data.

Kueri ini membandingkan AzureDiagnostics penggunaan pada 15 Juni, outlier ekstrem dalam contoh kami, dengan penggunaan tabel pada hari lain:

Klik untuk menjalankan kueri

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

Kueri mengidentifikasi setiap entri dalam tabel seperti yang terjadi pada AnomalyDate (15 Juni) atau OtherDates. Plugin diffpatterns() kemudian membagi himpunan data ini - yang disebut A (OtherDates dalam contoh kami) dan B (AnomalyDate dalam contoh kami) - dan mengembalikan beberapa pola yang berkontribusi pada perbedaan dalam dua set:

Cuplikan layar memperlihatkan tabel dengan tiga baris. Setiap baris menunjukkan perbedaan antara penggunaan pada penggunaan anomali dan penggunaan garis besar.

Melihat hasil kueri, Anda bisa melihat perbedaan berikut:

  • Ada 24.892.147 instans penyerapan dari sumber daya CH1-GEARAMAAKS pada semua hari lain dalam rentang waktu kueri, dan tidak ada penyerapan data dari sumber daya ini pada 15 Juni. Data dari sumber daya CH1-GEARAMAAKS menyurati 73,36% dari total penyerapan pada hari lain dalam rentang waktu kueri dan 0% dari total penyerapan pada 15 Juni.
  • Ada 2.168.448 instans penyerapan dari sumber daya NSG-TESTSQLMI519 pada semua hari lain dalam rentang waktu kueri, dan 110.544 instans penyerapan dari sumber daya ini pada 15 Juni. Data dari sumber daya NSG-TESTSQLMI519 menyuplai 6,39% dari total penyerapan pada hari lain dalam rentang waktu kueri dan 25,61% penyerapan pada 15 Juni.

Perhatikan bahwa, rata-rata, ada 108.422 instans penyerapan dari sumber daya NSG-TESTSQLMI519 selama 20 hari yang membentuk periode hari lainnya (membagi 2.168.448 dengan 20). Oleh karena itu, penyerapan dari sumber daya NSG-TESTSQLMI519 pada 15 Juni tidak secara signifikan berbeda dari penyerapan dari sumber daya ini pada hari lain. Namun, karena tidak ada penyerapan dari CH1-GEARAMAAKS pada 15 Juni, penyerapan dari NSG-TESTSQLMI519 membentuk persentase yang jauh lebih besar dari total penyerapan pada tanggal anomali dibandingkan dengan hari lain.

Kolom PercentDiffAB memperlihatkan perbedaan titik persentase absolut antara A dan B (|PercentA - PercentB|), yang merupakan ukuran utama perbedaan antara dua set. Secara default, diffpatterns() plugin mengembalikan selisih lebih dari 5% antara dua himpunan data, tetapi Anda dapat mengubah ambang batas ini. Misalnya, untuk mengembalikan hanya perbedaan 20% atau lebih antara dua himpunan data, Anda dapat mengatur | evaluate diffpatterns(AnomalyDate, "OtherDates", "AnomalyDate", "~", 0.20) dalam kueri di atas. Kueri sekarang hanya mengembalikan satu hasil:

Cuplikan layar memperlihatkan tabel dengan satu baris yang menyajikan perbedaan antara penggunaan pada penggunaan anomali dan penggunaan garis besar. Kali ini, kueri tidak mengembalikan perbedaan kurang dari 20 persen antara dua himpunan data.

Catatan

Untuk informasi selengkapnya tentang diffpatterns() sintaksis dan penggunaan, lihat plugin pola diff.

Langkah berikutnya

Pelajari lebih lanjut tentang: