كيفية استخدام بروميثيوس للكشف عن الحالات الشاذة في GitLab


إحدى الميزات الأساسية للغة الاستعلام Prometheus هي تجميع السلاسل الزمنية في الوقت الفعلي . يمكنك أيضًا استخدام لغة الاستعلام Prometheus للكشف عن الحالات الشاذة في بيانات السلاسل الزمنية. 

قام فريق Mail.ru Cloud Solutions بترجمة مقال لمهندس فريق البنية التحتية لـ GitLab ، حيث ستجد أمثلة برمجية يمكنك تجربتها على أنظمتك.

ما هو الكشف عن الشذوذ؟


هناك أربعة أسباب رئيسية تحدد أهمية الكشف عن الشذوذ لـ GitLab:

  1. تشخيص الحوادث : يمكننا اكتشاف الخدمات التي تجاوزت نطاقها الطبيعي عن طريق تقليل وقت اكتشاف الحوادث (MTTD) ، وبالتالي ، تقديم حل أسرع للمشكلة.
  2. الكشف عن تدهور الأداء : على سبيل المثال ، إذا تم إدخال انحدار في خدمة يتسبب في وصولها إلى خدمة أخرى كثيرًا ، فيمكننا اكتشاف هذه المشكلة وإصلاحها بسرعة.
  3. الكشف عن الإساءة والقضاء عليها : يوفر GitLab آليات التسليم والتكامل ( GitLab CI / CD ) والاستضافة (صفحات GitLab) وعدد محدود من المستخدمين الذين يمكنهم استخدام هذه الآليات.
  4. الأمان : يعد الكشف عن الشذوذ أمرًا مهمًا للكشف عن الاتجاهات غير المعتادة في سلسلة GitLab الزمنية.

لهذه الأسباب وغيرها ، قرر مؤلف المقالة معرفة كيفية تكوين تعريف الشذوذ في سلسلة GitLab الزمنية باستخدام استعلامات وقواعد Prometheus.

ما هو مستوى التجميع الصحيح؟


أولاً ، يجب تجميع السلاسل الزمنية بشكل صحيح. في المثال أدناه ، استخدمنا عداد http_requests_total القياسي لاسترداد البيانات ، على الرغم من أن العديد من المقاييس الأخرى ستفعل ذلك أيضًا.

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

يحتوي مقياس الاختبار هذا على العديد من المعلمات: الطريقة ، وحدة التحكم ، رمز الحالة (كود_الحالة) ، البيئة ، بالإضافة إلى المعلمات التي أضافها Prometheus نفسه ، على سبيل المثال ، الوظيفة والمثال.

تحتاج الآن إلى اختيار المستوى الصحيح لتجميع البيانات. كثير جدًا ، قليل جدًا - كل هذا مهم للكشف عن الحالات الشاذة. إذا كانت البيانات مجمعة جدًا ، فهناك مشكلتان محتملتان:

  1. يمكنك تخطي الشذوذ لأن التجميع يخفي المشاكل التي تحدث في مجموعات فرعية من بياناتك.
  2. إذا وجدت شذوذًا ، فمن الصعب ربطه بجزء منفصل من نظامك دون بذل جهد إضافي.

إذا لم يتم تجميع البيانات بشكل كافٍ ، فقد يؤدي ذلك إلى زيادة عدد الإيجابيات الخاطئة ، فضلاً عن التفسير غير الصحيح للبيانات الصالحة على أنها خاطئة.

بناءً على خبرتنا ، فإن المستوى الأكثر صحة للتجميع هو مستوى الخدمة ، أي أننا نضمن تسمية العمل (الوظيفة) والبيئة (البيئة) ، ونتجاهل جميع التصنيفات الأخرى.

التجميع ، الذي سنناقشه طوال المقالة ، يشمل: الوظيفة - http_request ، التجميع - خمس دقائق ، والتي يتم حسابها على أساس العمل والبيئة في خمس دقائق.

- 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

من المثال أعلاه ، يمكن ملاحظة أنه من سلسلة http_requests_total ، يتم اختيار المجموعات الفرعية في سياق العمل والبيئة ، ثم يتم النظر في عددها في خمس دقائق.

استخدام نقاط Z للكشف عن الشذوذ


يمكن تطبيق المبادئ الأساسية للإحصاءات للكشف عن الشذوذ.

إذا كنت تعرف المتوسط والانحراف المعياري لسلسلة Prometheus ، فيمكنك استخدام أي عينة في السلسلة لحساب الدرجة z. 

الدرجة Z عبارة عن قياس الانتشار النسبي للقيمة الملحوظة أو المقاسة ، والتي توضح عدد الانحرافات المعيارية التي ينتشرها بالنسبة لمتوسط ​​القيمة

أي أن الدرجة z = 0 تعني أن النتيجة z متطابقة مع متوسط ​​القيمة في مجموعة البيانات مع التوزيع القياسي ، وتعني الدرجة z = 1 أن الانحراف المعياري = 1.0 من المتوسط.

نفترض أن البيانات الأساسية لها توزيع طبيعي ، مما يعني أن 99.7 ٪ من العينات لها درجة z من 0 إلى 3. كلما كانت الدرجة z من الصفر ، قل احتمال وجودها. 

نطبق هذه الخاصية للكشف عن الحالات الشاذة في سلسلة بيانات بروميثيوس:

  1. نحن نحسب المتوسط ​​والانحراف المعياري للمقياس باستخدام بيانات ذات حجم عينة كبير. في هذا المثال ، نستخدم البيانات الأسبوعية. إذا افترضنا أن السجلات يتم تقييمها مرة واحدة في الدقيقة ، فسيكون لدينا في الأسبوع ما يزيد قليلاً عن 10000 عينة.

    # 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. يمكننا حساب الدرجة z لاستعلام Prometheus بمجرد أن نحصل على المتوسط ​​والانحراف المعياري للتجميع.

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


بناءً على المبادئ الإحصائية للتوزيعات العادية ، افترض أن أي قيمة خارج النطاق من +3 إلى -3 ستكون شاذة. وفقًا لذلك ، يمكننا إنشاء تحذير حول مثل هذه الحالات الشاذة. على سبيل المثال ، سوف نتلقى تنبيهًا عندما يتجاوز التجميع لدينا هذا النطاق لأكثر من خمس دقائق.


رسم بياني لعدد الطلبات في الثانية لخدمة صفحات GitLab لمدة 48 ساعة. تم تمييز الدرجة Z في النطاق من +3 إلى -3 باللون الأخضر.

قد يصعب تفسير الدرجة Z على الرسوم البيانية ، حيث لا تحتوي هذه القيمة على وحدة قياس. لكن الشذوذ في هذا الرسم البياني سهل التحديد. كل شيء يتجاوز المنطقة الخضراء ، والذي يُظهر ممرًا للقيم بنقاط z من -3 إلى +3 ، سيكون قيمة غير طبيعية.

ماذا تفعل إذا كان توزيع البيانات غير طبيعي


نفترض أن توزيع البيانات أمر طبيعي. خلاف ذلك ، ستكون النتيجة z الخاصة بنا خاطئة.

هناك الكثير من الحيل الإحصائية لتحديد الحالة الطبيعية لتوزيع البيانات ، ولكن أفضل طريقة هي التحقق من أن النتيجة الضريبية للبيانات تقع في النطاق من -4.0 إلى +4.0.

استعلامان من بروميثيوس يظهران الحد الأدنى والأقصى من النقاط z:

(
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

إذا كانت نتائجك في النطاق من -20 إلى +20 ، فهذا يعني أنه تم استخدام الكثير من البيانات وتم تشويه النتائج. تذكر أيضًا أنه يجب العمل مع الصفوف المجمعة. تتضمن المقاييس التي لا تحتوي على توزيع عادي معلمات مثل معدل الخطأ والتأخير وأطوال قائمة الانتظار وما إلى ذلك. لكن العديد من هذه المقاييس ستعمل بشكل أفضل مع عتبات التنبيه الثابتة.

كشف الشذوذ الموسمي الاحصائي


على الرغم من أن حساب الدرجات z يعمل بشكل جيد مع التوزيع الطبيعي لبيانات السلاسل الزمنية ، إلا أن هناك طريقة ثانية يمكن أن تعطي نتائج كشف شذوذ أكثر دقة. هذا هو استخدام الموسمية الإحصائية. 

الموسمية هي سمة من سمات مقياس السلاسل الزمنية عندما يخضع هذا المقياس لتغيرات منتظمة وقابلة للتنبؤ تتكرر في كل دورة.


مخطط الطلبات في الثانية (RPS) من الاثنين إلى الأحد لمدة أربعة أسابيع متتالية

يوضح الرسم البياني أعلاه RPS (عدد الطلبات في الثانية) لمدة سبعة أيام - من الاثنين إلى الأحد ، لمدة أربعة أسابيع متتالية. يسمى هذا النطاق الذي يستمر لسبعة أيام بـ "الإزاحة" ، أي النمط الذي سيتم استخدامه للقياس.

كل أسبوع على الرسم البياني هو لون مختلف. يشار إلى موسمية البيانات من خلال تسلسل الاتجاهات الموضحة على الرسم البياني - كل صباح يوم الاثنين نلاحظ زيادة مماثلة في RPS ، وفي المساء يوم الجمعة نلاحظ دائمًا انخفاضًا في RPS.

باستخدام الموسمية في بيانات السلاسل الزمنية لدينا ، يمكننا التنبؤ بدقة أكبر بحدوث حالات شاذة واكتشافها. 

كيفية استخدام الموسمية


يستخدم بروميثيوس العديد من الآليات الإحصائية المختلفة لحساب الموسمية.

أولاً ، قم بإجراء حساب ، مضيفًا اتجاه نمو للأسبوع إلى نتائج الأسبوع السابق. يتم حساب اتجاه النمو كما يلي: اطرح المتوسط ​​المتحرك للأسبوع الماضي من المتوسط ​​المتحرك للأسبوع الماضي.

- 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

يتضح أن التكرار الأول "ضيق" إلى حد ما - نستخدم نافذة الخمس دقائق من هذا الأسبوع والأسبوع السابق للحصول على توقعاتنا.

في التكرار الثاني ، نقوم بتوسيع تغطيتنا من خلال أخذ متوسط ​​فترة الأربع ساعات للأسبوع السابق ومقارنتها بالأسبوع الحالي. 

وبالتالي ، إذا حاولنا التنبؤ بقيمة المقياس في الساعة الثامنة صباح يوم الاثنين ، بدلاً من نفس النافذة التي تستغرق خمس دقائق في الأسبوع السابق ، فإننا نأخذ متوسط ​​قيمة المقياس من الساعة السادسة إلى العاشرة صباح يوم الاثنين السابق.

- 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

أشار الطلب إلى 166 ساعة ، أي ساعتين أقل من أسبوع كامل (7 * 24 = 168) ، لأننا نريد استخدام فترة أربع ساعات بناءً على الوقت الحالي ، لذلك نحتاج إلى أن تكون الإزاحة ساعتين أقل من أسبوع كامل. 


RPS الحقيقي (الأصفر) والمتوقع (الأزرق) في أسبوعين

توضح مقارنة RPS الفعلية مع توقعاتنا أن حساباتنا كانت دقيقة إلى حد ما. ومع ذلك ، فإن هذه الطريقة لها عيب.
 
على سبيل المثال ، في 1 مايو ، تم استخدام GitLab بشكل أقل من المعتاد أيام الأربعاء ، حيث كان هذا اليوم يوم عطلة. نظرًا لأن اتجاه النمو المقدر يعتمد على كيفية استخدام النظام في الأسبوع السابق ، فإن توقعاتنا للأسبوع المقبل ، أي يوم الأربعاء ، 8 مايو ، أعطت RPS أقل من الواقع.

يمكن تصحيح هذا الخطأ من خلال عمل ثلاثة تنبؤات لثلاثة أسابيع متتالية قبل الأربعاء 1 مايو ، أي الأربعاء الثلاثة السابق. يظل الطلب كما هو ، ولكن يتم تعديل الإزاحة.

- 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)


هناك ثلاث توقعات على الرسم البياني لمدة ثلاثة أسابيع قبل 8 مايو ، مقارنة مع RPS الفعلي ليوم الأربعاء 8 مايو. يمكنك أن ترى أن التوقعين دقيقان للغاية ، لكن توقعات الأسبوع من 1 مايو لا تزال غير دقيقة.

بالإضافة إلى ذلك ، نحن لا نحتاج إلى ثلاث تنبؤات ، نحتاج إلى توقع واحد. متوسط ​​القيمة ليس خيارًا ، لأنه سيتم تعتيمه بواسطة بيانات RPS المشوهة بدءًا من 1 مايو. بدلاً من ذلك ، تحتاج إلى حساب الوسيط. لا يحتوي Prometheus على استعلام متوسط ​​، ولكن يمكننا استخدام التجميع الكمي بدلاً من الوسيط.

المشكلة الوحيدة هي أننا نحاول تضمين ثلاث سلاسل في التجميع ، وهذه السلسلة الثلاثة هي في الواقع نفس السلسلة في ثلاثة أسابيع. وبعبارة أخرى ، لديهم نفس التسميات ، لذلك من الصعب تجميعها معًا. 

لتجنب الالتباس ، نقوم بإنشاء تسمية تسمى الإزاحة ونستخدم وظيفة استبدال الملصق لإضافة إزاحة لكل من الأسابيع الثلاثة. ثم في التجميع الكمي نتجاهل هذه التصنيفات ، وهذا يعطينا في المتوسط ​​ثلاثة.

- 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)

الآن أصبحت توقعاتنا مع متوسط ​​ثلاث مجموعات أكثر دقة.


متوسط ​​التوقعات مقابل RPS الفعلي

كيف تكتشف أن توقعاتنا دقيقة حقًا


للتحقق من دقة التوقعات ، يمكننا العودة إلى الدرجة z. يتم استخدامه لقياس تناقض العينة مع توقعاتها في الانحرافات المعيارية. كلما زاد الانحراف المعياري عن التوقعات ، زادت احتمالية أن تكون قيمة معينة بعيدة.


نطاق الانحراف المتوقع هو من +1.5 إلى -1.5.

يمكنك تغيير مخطط Grafana لاستخدام توقعات موسمية ، بدلاً من المتوسط ​​المتحرك الأسبوعي. نطاق القيم الطبيعية لفترة معينة من اليوم مظلل باللون الأخضر. كل ما يتجاوز المنطقة الخضراء يعتبر شيئًا بعيدًا. في هذه الحالة ، حدث الخروج بعد ظهر يوم الأحد ، عندما واجه مزود الخدمة السحابية بعض مشكلات الشبكة.

من الممارسة السليمة استخدام ± 2 درجة z للتنبؤات الموسمية.

كيفية إعداد التنبيهات باستخدام بروميثيوس


إذا كنت ترغب في إعداد تنبيه للأحداث غير الطبيعية ، فيمكنك تطبيق قاعدة بروميثيوس البسيطة إلى حد ما ، والتي تتحقق مما إذا كانت الدرجة z لمؤشر في النطاق بين +2 و -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

في GitLab ، نستخدم قاعدة توجيه مخصصة ترسل تنبيهًا عبر Slack عندما تكتشف أي حالات شاذة ، ولكنها لا تتصل بفريق الدعم لدينا.

كيفية الكشف عن الشذوذ في GitLab باستخدام بروميثيوس


  1. يمكن استخدام بروميثيوس للكشف عن بعض التشوهات.
  2. التجميع الصحيح هو المفتاح لإيجاد الشذوذ.
  3. يكون تسجيل Z فعالًا إذا كانت بياناتك ذات توزيع طبيعي.
  4. الموسمية الإحصائية هي آلية قوية للكشف عن الشذوذ.

تمت الترجمة بدعم من Mail.ru Cloud Cloud Solutions .

لا تزال مفيدة :

  1. طرق التخزين المؤقت البسيطة في GitLab CI: دليل صور .
  2. أدوات GitLab CE الجاهزة والمخصصة في سوق MCS
  3. قناة Telegram حول التحول الرقمي .

All Articles