Cara menggunakan Prometheus untuk mendeteksi anomali di GitLab


Salah satu fitur dasar dari bahasa permintaan Prometheus adalah agregasi waktu-nyata dari rangkaian waktu . Anda juga dapat menggunakan bahasa permintaan Prometheus untuk mendeteksi anomali dalam data deret waktu. 

Tim Cloud Solutions Mail.ru telah menerjemahkan sebuah artikel oleh insinyur tim infrastruktur GitLab , di mana Anda akan menemukan contoh kode yang dapat Anda coba pada sistem Anda.

Untuk apa deteksi anomali?


Ada empat alasan utama yang menentukan pentingnya deteksi anomali untuk GitLab:

  1. Diagnostik Insiden : kami dapat mendeteksi layanan mana yang telah melampaui ruang lingkup normalnya dengan mengurangi waktu deteksi insiden (MTTD) dan, karenanya, menawarkan solusi yang lebih cepat untuk masalah tersebut.
  2. Deteksi penurunan kinerja : misalnya, jika regresi diperkenalkan ke layanan yang terlalu sering mengakses layanan lain, kami dapat dengan cepat mendeteksi dan memperbaiki masalah ini.
  3. Deteksi dan penghapusan pelanggaran : GitLab menyediakan mekanisme pengiriman dan integrasi ( GitLab CI / CD ) dan hosting (Halaman GitLab) dan sejumlah pengguna yang dapat menggunakan mekanisme ini.
  4. Keselamatan : Deteksi anomali penting untuk mendeteksi tren yang tidak biasa dalam seri waktu GitLab.

Untuk alasan ini dan lainnya, penulis artikel memutuskan untuk mencari cara mengkonfigurasi definisi anomali dalam seri waktu GitLab menggunakan kueri dan aturan Prometheus.

Apa tingkat agregasi yang benar?


Pertama, deret waktu harus dikumpulkan dengan benar. Dalam contoh di bawah ini, kami menggunakan penghitung http_requests_total standar untuk mengambil data, meskipun banyak metrik lainnya juga akan melakukannya.

http_requests_total{
 job="apiserver",
 method="GET",
 controller="ProjectsController",
 status_code="200",
 environment="prod"
}

Metrik pengujian ini memiliki beberapa parameter: metode, pengontrol, kode status (status_code), lingkungan, ditambah parameter yang ditambahkan oleh Prometheus sendiri, misalnya, pekerjaan dan instance.

Sekarang Anda harus memilih tingkat agregasi data yang tepat. Terlalu banyak, terlalu sedikit - semua ini penting untuk mendeteksi anomali. Jika data terlalu teragregasi, ada dua masalah potensial:

  1. Anda dapat melewati anomali karena agregasi menyembunyikan masalah yang terjadi pada himpunan bagian data Anda.
  2. Jika Anda menemukan anomali, sulit untuk menghubungkannya dengan bagian yang terpisah dari sistem Anda tanpa upaya tambahan.

Jika data tidak cukup dikumpulkan, ini dapat menyebabkan peningkatan jumlah positif palsu, serta interpretasi yang salah dari data yang valid sebagai salah.

Berdasarkan pengalaman kami, tingkat agregasi yang paling benar adalah tingkat layanan, yaitu, kami menyertakan label pekerjaan (pekerjaan) dan lingkungan (lingkungan), dan membuang semua label lainnya.

Agregasi, yang akan kita bahas di seluruh artikel, meliputi: job - http_request, agregasi - lima menit, yang dihitung berdasarkan pekerjaan dan lingkungan dalam lima menit.

- record: job:http_requests:rate5m
expr: sum without(instance, method, controller, status_code)
(rate(http_requests_total[5m]))
# --> job:http_requests:rate5m{job="apiserver", environment="prod"}  21321
# --> job:http_requests:rate5m{job="gitserver", environment="prod"}  2212
# --> job:http_requests:rate5m{job="webserver", environment="prod"}  53091

Dari contoh di atas, jelas bahwa dari himpunan himpunan seri http_requests_total dipilih dalam konteks pekerjaan dan lingkungan, maka jumlah mereka dianggap selama lima menit.

Menggunakan Z-score untuk mendeteksi anomali


Prinsip dasar statistik dapat diterapkan untuk mendeteksi anomali.

Jika Anda mengetahui rata-rata dan standar deviasi dari seri Prometheus, maka Anda dapat menggunakan sampel apa pun dalam seri untuk menghitung skor-z. 

Skor-Z adalah ukuran penyebaran relatif dari nilai yang diamati atau diukur, yang menunjukkan berapa banyak standar deviasi penyebarannya relatif terhadap nilai rata - rata

Yaitu, skor-z = 0 berarti skor-z identik dengan nilai rata-rata dalam dataset dengan distribusi standar, dan skor-z = 1 berarti bahwa standar deviasi = 1,0 dari rata-rata.

Kami berasumsi bahwa data dasar memiliki distribusi normal, yang berarti bahwa 99,7% sampel memiliki skor-z dari 0 hingga 3. Semakin jauh skor-z dari nol, semakin kecil kemungkinannya untuk ada. 

Kami menerapkan properti ini untuk mendeteksi anomali dalam seri data Prometheus:

  1. Kami menghitung mean dan standar deviasi untuk metrik menggunakan data dengan ukuran sampel yang besar. Untuk contoh ini, kami menggunakan data mingguan. Jika kita menganggap bahwa catatan dievaluasi satu menit sekali, maka dalam seminggu kita akan memiliki lebih dari 10.000 sampel.

    # Long-term average value for the series
    - record: job:http_requests:rate5m:avg_over_time_1w
    expr: avg_over_time(job:http_requests:rate5m[1w])
    
    # Long-term standard deviation for the series
    - record: job:http_requests:rate5m:stddev_over_time_1w
    expr: stddev_over_time(job:http_requests:rate5m[1w])

  2. Kita dapat menghitung skor-z untuk kueri Prometheus segera setelah kita mendapatkan mean dan standar deviasi untuk agregasi.

    # Z-Score for aggregation
    (
    job:http_requests:rate5m -
    job:http_requests:rate5m:avg_over_time_1w
    ) /  job:http_requests:rate5m:stddev_over_time_1w


Berdasarkan prinsip statistik distribusi normal, anggaplah bahwa nilai apa pun di luar kisaran +3 hingga -3 akan menjadi anomali. Dengan demikian, kita dapat membuat peringatan tentang anomali semacam itu. Misalnya, kami akan menerima peringatan ketika agregasi kami melampaui rentang ini selama lebih dari lima menit.


Grafik jumlah permintaan per detik ke layanan Halaman GitLab selama 48 jam. Skor-Z dalam kisaran dari +3 hingga -3 disorot dalam warna

hijau.Z-skor dapat menjadi sulit untuk ditafsirkan pada grafik, karena nilai ini tidak memiliki unit pengukuran. Tetapi anomali dalam grafik ini sangat sederhana untuk ditentukan. Segala sesuatu yang melampaui zona hijau, yang menunjukkan koridor nilai dengan skor-z dari -3 hingga +3, akan menjadi nilai anomali.

Apa yang harus dilakukan jika distribusi data tidak normal


Kami berasumsi bahwa distribusi data adalah normal. Kalau tidak, skor-z kami akan salah.

Ada banyak trik statistik untuk menentukan normalitas distribusi data, tetapi cara terbaik adalah memeriksa bahwa data Anda z-skor terletak di kisaran -4,0 hingga +4,0.

Dua kueri Prometheus yang menunjukkan skor-z minimum dan maksimum:

(
max_over_time(job:http_requests:rate5m[1w]) - avg_over_time(job:http_requests:rate5m[1w])
) / stddev_over_time(job:http_requests:rate5m[1w])
# --> {job="apiserver", environment="prod"}  4.01
# --> {job="gitserver", environment="prod"}  3.96
# --> {job="webserver", environment="prod"}  2.96

(
 min_over_time(job:http_requests:rate5m[<1w]) - avg_over_time(job:http_requests:rate5m[1w])
) / stddev_over_time(job:http_requests:rate5m[1w])
# --> {job="apiserver", environment="prod"}  -3.8
# --> {job="gitserver", environment="prod"}  -4.1
# --> {job="webserver", environment="prod"}  -3.2

Jika hasil Anda berada dalam kisaran -20 hingga +20, ini berarti bahwa terlalu banyak data telah digunakan dan hasilnya terdistorsi. Ingat juga bahwa Anda harus bekerja dengan baris teragregasi. Metrik yang tidak memiliki distribusi normal mencakup parameter seperti tingkat kesalahan, penundaan, panjang antrian, dan sebagainya. Tetapi banyak dari metrik ini akan bekerja lebih baik dengan ambang waspada tetap.

Deteksi anomali musiman berdasarkan statistik


Meskipun penghitungan skor-z berfungsi baik dengan distribusi normal data deret waktu, ada metode kedua yang dapat memberikan hasil deteksi anomali yang lebih akurat. Ini adalah penggunaan musiman statistik. 

Musiman adalah karakteristik dari metrik seri waktu ketika metrik ini mengalami perubahan reguler dan dapat diprediksi yang diulang dalam setiap siklus.


Bagan permintaan per detik (RPS) dari Senin hingga Minggu selama empat minggu berturut-turut

Bagan di atas menggambarkan RPS (jumlah permintaan per detik) selama tujuh hari - dari Senin hingga Minggu, selama empat minggu berturut-turut. Rentang tujuh hari ini disebut "offset", yaitu pola yang akan digunakan untuk pengukuran.

Setiap minggu pada tabel adalah warna yang berbeda. Musiman data ditunjukkan oleh urutan tren yang ditunjukkan pada grafik - setiap Senin pagi kami mengamati peningkatan RPS yang serupa, dan pada malam hari Jumat kami selalu mengamati penurunan RPS.

Dengan menggunakan musiman dalam data deret waktu kami, kami dapat lebih akurat memprediksi terjadinya anomali dan deteksi mereka. 

Cara menggunakan musiman


Prometheus menggunakan beberapa mekanisme statistik yang berbeda untuk menghitung musiman.

Pertama, kami membuat perhitungan, menambahkan tren pertumbuhan untuk minggu ke hasil minggu sebelumnya. Tren pertumbuhan dihitung sebagai berikut: kurangi rata-rata bergerak untuk minggu terakhir dari rata-rata bergerak selama seminggu terakhir.

- record: job:http_requests:rate5m_prediction
  expr: >
    job:http_requests:rate5m offset 1w          # Value from last period
    + job:http_requests:rate5m:avg_over_time_1w # One-week growth trend
    — job:http_requests:rate5m:avg_over_time_1w offset 1w

Iterasi pertama ternyata agak "sempit" - kami menggunakan jendela lima menit minggu ini dan minggu sebelumnya untuk mendapatkan perkiraan kami.

Pada iterasi kedua, kami memperluas cakupan kami dengan mengambil rata-rata periode empat jam untuk minggu sebelumnya dan membandingkannya dengan minggu ini. 

Jadi, jika kami mencoba memprediksi nilai metrik pada pukul delapan pagi pada hari Senin, alih-alih jendela lima menit yang sama pada minggu sebelumnya, kami mengambil nilai rata-rata metrik dari enam menjadi sepuluh pada pagi hari Senin sebelumnya.

- record: job:http_requests:rate5m_prediction
  expr: >
    avg_over_time(job:http_requests:rate5m[4h] offset 166h) # Rounded value from last period
    + job:http_requests:rate5m:avg_over_time_1w    # Add 1w growth trend
    - job:http_requests:rate5m:avg_over_time_1w offset 1w

Permintaan menunjukkan 166 jam, yaitu dua jam kurang dari seminggu penuh (7 * 24 = 168), karena kami ingin menggunakan periode empat jam berdasarkan waktu saat ini, jadi kami perlu offset menjadi dua jam kurang dari seminggu penuh. 


RPS nyata (kuning) dan diprediksi (biru) dalam dua minggu

. Perbandingan RPS aktual dengan perkiraan kami menunjukkan bahwa perhitungan kami cukup akurat. Namun, metode ini memiliki kelemahan.
 
Misalnya, 1 Mei, GitLab digunakan kurang dari biasanya pada hari Rabu, karena hari ini adalah hari libur. Karena tren pertumbuhan yang diperkirakan tergantung pada bagaimana sistem itu digunakan pada minggu sebelumnya, perkiraan kami untuk minggu berikutnya, yaitu, pada hari Rabu, 8 Mei, memberikan RPS yang lebih rendah daripada yang sebenarnya.

Kesalahan ini dapat diperbaiki dengan membuat tiga perkiraan selama tiga minggu berturut-turut sebelum Rabu, 1 Mei, yaitu tiga hari Rabu sebelumnya. Permintaannya tetap sama, tetapi offsetnya disesuaikan.

- record: job:http_requests:rate5m_prediction
  expr: >
   quantile(0.5,
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 166h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 1w
       , "offset", "1w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 334h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 2w
       , "offset", "2w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 502h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 3w
       , "offset", "3w", "", "")
   )
   without (offset)


Ada tiga perkiraan pada grafik selama tiga minggu sebelum 8 Mei, dibandingkan dengan RPS yang sebenarnya untuk Rabu, 8 Mei. Anda dapat melihat bahwa kedua ramalan itu sangat akurat, tetapi ramalan untuk minggu 1 Mei tetap tidak akurat.Selain

itu, kita tidak memerlukan tiga ramalan, kita memerlukan satu ramalan. Nilai rata-rata bukan pilihan, karena akan dikaburkan oleh data RPS kami yang terdistorsi mulai 1 Mei. Sebagai gantinya, Anda perlu menghitung median. Prometheus tidak memiliki kueri median, tetapi kita bisa menggunakan agregasi kuantil alih-alih median.

Satu-satunya masalah adalah bahwa kami mencoba untuk memasukkan tiga seri dalam agregasi, dan tiga seri ini sebenarnya seri yang sama dalam tiga minggu. Dengan kata lain, mereka memiliki label yang sama, jadi sulit untuk menyatukannya. 

Untuk menghindari kebingungan, kami membuat label yang disebut offset dan menggunakan fungsi ganti label untuk menambahkan offset pada masing-masing tiga minggu. Kemudian dalam agregasi kuantil kita membuang label-label ini, dan ini memberi kita rata-rata tiga.

- record: job:http_requests:rate5m_prediction
  expr: >
   quantile(0.5,
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 166h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 1w
       , "offset", "1w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 334h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 2w
       , "offset", "2w", "", "")
     or
     label_replace(
       avg_over_time(job:http_requests:rate5m[4h] offset 502h)
       + job:http_requests:rate5m:avg_over_time_1w — job:http_requests:rate5m:avg_over_time_1w offset 3w
       , "offset", "3w", "", "")
   )
   without (offset)

Sekarang perkiraan kami dengan median tiga agregasi telah menjadi lebih akurat.


Perkiraan median versus RPS aktual

Cara mengetahui bahwa perkiraan kami benar-benar akurat


Untuk memeriksa keakuratan ramalan, kita dapat kembali ke skor-z. Ini digunakan untuk mengukur perbedaan sampel dengan perkiraan dalam standar deviasi. Semakin besar standar deviasi dari perkiraan, semakin tinggi kemungkinan bahwa nilai tertentu adalah outlier.


Kisaran deviasi yang diproyeksikan adalah dari +1.5 ke -1.5.

Anda dapat mengubah grafik Grafana kami untuk menggunakan perkiraan musiman, daripada rata-rata bergerak mingguan. Kisaran nilai normal untuk waktu tertentu dalam sehari diarsir dalam warna hijau. Segala sesuatu yang melampaui zona hijau dianggap sebagai pencilan. Dalam hal ini, pencilan terjadi pada hari Minggu sore, ketika penyedia cloud kami mengalami beberapa masalah jaringan.

Merupakan praktik yang baik untuk menggunakan skor ± 2 z untuk prakiraan musiman.

Cara mengatur peringatan dengan Prometheus


Jika Anda ingin mengatur peringatan untuk kejadian abnormal, Anda dapat menerapkan aturan Prometheus yang cukup sederhana, yang memeriksa apakah skor-z indikator berada dalam kisaran antara +2 dan -2.

- alert: RequestRateOutsideNormalRange
  expr: >
   abs(
     (
       job:http_requests:rate5m - job:http_requests:rate5m_prediction
     ) / job:http_requests:rate5m:stddev_over_time_1w
   ) > 2
  for: 10m
  labels:
    severity: warning
  annotations:
    summary: Requests for job {{ $labels.job }} are outside of expected operating parameters

Di GitLab, kami menggunakan aturan perutean kustom yang mengirimkan peringatan melalui Slack ketika mendeteksi anomali, tetapi tidak menghubungi tim dukungan kami.

Cara mendeteksi anomali di GitLab menggunakan Prometheus


  1. Prometheus dapat digunakan untuk mendeteksi beberapa kelainan.
  2. Agregasi yang tepat adalah kunci untuk menemukan anomali.
  3. Skor Z efektif jika data Anda memiliki distribusi normal.
  4. Statistik musiman adalah mekanisme yang kuat untuk mendeteksi anomali.

Diterjemahkan dengan dukungan dari Mail.ru Cloud Solutions .

Masih bermanfaat :

  1. Metode Caching Sederhana di GitLab CI: Panduan Gambar .
  2. Alat GitLab CE yang dibuat dan dikustomisasi di pasar MCS
  3. Saluran Telegram kami tentang transformasi digital .

All Articles