مستوى المقال: متوسط. محتاج تكون شغّلت تطبيق ويب ورا Nginx أو داخل Kubernetes، وسمعت عن Prometheus من قبل حتى لو ماستخدمتهوش بعمق. مش محتاج تكون خبير مراقبة.
ليه المتوسط بيكذب عليك في زمن الاستجابة
لو الداشبورد بتقولك إن متوسط زمن الاستجابة 91 مللي ثانية، ده مش معناه إن مستخدمينك مبسوطين. المتوسط بيخبّي أبطأ 5% من الطلبات، وهم بالظبط الناس اللي بتزعل وتسيب المنتج. في المقال ده هتعرف تقيس p95 وp99 صح بـ Prometheus، وتحط رقم حقيقي على معاناة أبطأ مستخدميك.
المشكلة باختصار
عندك API بيخدم 50 ألف طلب في الساعة. الجراف بيقول Average latency = 91ms، وانت مطمّن. بس فيه تذاكر دعم بتقول "الموقع بطيء". السبب إن توزيع زمن الاستجابة مش متماثل: أغلب الطلبات سريعة، وذيل طويل من الطلبات البطيئة بيوصل لثواني. المتوسط بيغرق وسط الطلبات السريعة، والذيل بيختفي.
مثال يقرّب الفكرة
تخيّل 10 زباين في محل قهوة. 9 منهم اتخدموا في 30 ثانية، وواحد استنى 5 دقايق عشان الماكينة علّقت. لو حسبت المتوسط: (9×30 + 300) ÷ 10 = 57 ثانية للزبون. الرقم ده بيقول "خدمة كويسة"، بس فيه زبون قعد 5 دقايق واتجنّن. المتوسط مسحه من الوجود.
الحل إنك متبصّش للمتوسط، تبصّ للترتيب. رتّب أزمنة الانتظار من الأصغر للأكبر، وبُص على "أسوأ حالة عند 90% أو 95% من الزباين". ده اللي بيحكي القصة الحقيقية.
ليه المتوسط بيكذب علميًا
زمن الاستجابة في الأنظمة الموزّعة توزيعه ملتوٍ لليمين (right-skewed): كتلة كبيرة عند القيم الصغيرة، وذيل طويل. المتوسط (mean) حسّاس جدًا للقيم المتطرفة في الذيل من ناحية، لكنه في نفس الوقت بتغرقه الكتلة الكبيرة من القيم الصغيرة. النتيجة: رقم واحد لا يمثّل لا الأغلبية ولا المتضررين.
البديل هو المئينات (Percentiles). الـ p95 هو القيمة اللي 95% من الطلبات أقل منها. يعني p95 = 213ms معناه: 95 طلب من كل 100 خلصوا في أقل من 213 مللي ثانية، و5 طلبات أخدوا أكتر. الـ p99 بيركّز على أسوأ 1% — وغالبًا هو اللي بيكسر تجربة المستخدم في أوقات الذروة.
إزاي Prometheus بيحسب الـ p95
Prometheus مبيخزّنش كل طلب على حدة، ده هيفجّر التخزين. بدل كده بيستخدم نوع مقياس اسمه Histogram. الفكرة إنك بتحدّد "دلاء" (buckets) مسبقًا بحدود عليا، وكل طلب بيزوّد عدّاد كل دلو حدّه العلوي أكبر من زمن الطلب. فبتطلع عندك أعداد تراكمية.
لحساب p95، دالة histogram_quantile بتلاقي الدلو اللي بيعدّي عنده خط الـ 95%، وتعمل استيفاء خطي جواه. في الرسمة فوق، الـ 95% واقعة بين دلو le=1 (عند 89%) ودلو le=2.5 (عند 97%)، فالنتيجة التقريبية حوالي 2.1 ثانية. ركّز: الرقم ده تقريبي بدقة الدلاء، مش قيمة مضبوطة.
مثال تنفيذي: كود + PromQL
أول حاجة، عرّف الـ Histogram بدلاء منطقية لتطبيقك. لو الأهداف بتاعتك بالمللي ثانية، خلّي الدلاء حواليها. مثال بمكتبة Prometheus الرسمية في بايثون:
from prometheus_client import Histogram, start_http_server
import time
# الدلاء بالثواني، مضبوطة حوالي أهداف الأداء (SLO) بتاعتك
REQUEST_LATENCY = Histogram(
"http_request_duration_seconds",
"زمن معالجة طلب HTTP",
buckets=(0.05, 0.1, 0.25, 0.5, 1, 2.5, 5),
)
@REQUEST_LATENCY.time() # بيقيس زمن الدالة تلقائيًا
def handle_request():
time.sleep(0.08) # شغلك الحقيقي هنا
if __name__ == "__main__":
start_http_server(8000) # /metrics على المنفذ 8000
while True:
handle_request()
بعد ما الـ metrics تطلع، احسب p95 على آخر 5 دقايق بـ PromQL:
histogram_quantile(
0.95,
sum(rate(http_request_duration_seconds_bucket[5m])) by (le)
)
و p99 نفس الحكاية بتغيير الرقم لـ 0.99. لو عايز تفصل حسب المسار، ضيف route في الـ by. النتيجة رقم واحد بيقولك: أسوأ 5% من طلباتك بياخدوا كام فعلًا.
المقايضات (Trade-offs)
- الدقة مقابل التكلفة: النتيجة تقريبية بحدود الدلاء. عايز دقة أعلى قرب خط الـ SLO؟ زوّد دلاء هناك. بتكسب دقة، بتخسر عدد سلاسل زمنية أكبر.
- الكارديناليتي (Cardinality): كل دلو × كل تركيبة labels = سلسلة زمنية مستقلة. 7 دلاء × 20 مسار × 5 أكواد حالة = 700 سلسلة من مقياس واحد. الافتراض هنا إن عندك كارديناليتي معقولة؛ لو حطّيت
user_idكـ label هتفجّر Prometheus. - الحذف المتناسق (Coordinated Omission): لو أداة القياس نفسها بطؤت وقت الحمل العالي، ممكن متسجّلش أبطأ الطلبات، فيطلع p99 متفائل غلط. خلّي القياس عند حافة الخدمة (مثلًا في الـ Ingress) مش جوه الكود بس.
متى لا تستخدم هذه الطريقة
لو حجم الترافيك صغير جدًا (عشرات الطلبات في الدقيقة)، المئينات هتبقى مهزوزة إحصائيًا، والأفضل تسجّل الطلبات فردية وتحللها. ولو محتاج قيمة p99 مضبوطة للمليمتر (مثلًا أنظمة تداول)، الـ Histogram التقريبي مش كفاية؛ استخدم قياس دقيق أو HDR Histogram. وأخيرًا، متحطّش labels عالية الكارديناليتي عشان "تفصّل أكتر"؛ ده بيحوّل المراقبة لمشكلة أكبر من اللي بتحلها.
الخطوة التالية
افتح تعريف الـ Histogram في خدمتك، وظبّط الدلاء حوالي هدف الأداء بتاعك (لو SLO عندك 300ms، خلّي دلاء عند 0.2 و0.3 و0.5). بعدين حط histogram_quantile(0.95, ...) على لوحة Grafana، واعمل تنبيه يضرب لما p95 يعدّي الـ SLO لمدة 5 دقايق. أول مرة هتشوف الرقم الحقيقي، هتفهم شكوى "الموقع بطيء" اللي مكنتش شايفها في المتوسط.
المصادر
- Prometheus Docs — Histograms and summaries (شرح الدلاء والمئينات رسميًا)
- Prometheus Docs — دالة histogram_quantile (آلية الاستيفاء الخطي)
- Google SRE Book — Monitoring Distributed Systems (الإشارات الذهبية الأربع، ومنها زمن الاستجابة بالمئينات)
- مكتبة Prometheus الرسمية لبايثون (client_python) (توثيق نوع Histogram المستخدم في الكود)