OpenTelemetry بالعربي: لاحق الـ 200ms المختفية بين 6 خدمات microservices
السيرفر بيرجّع الـ API في 1.4 ثانية. Prometheus بيقولك إن DB latency متوسطها 80ms والـ CPU عند 12%. Grafana نضيفة. Logs ما فيهاش errors. لكن الزائر بيشتكي. السبب بالظبط: 200ms بتضيع كل request بين خدمتين من الستة، وانت مش شايفها لأن الـ metrics بتشوف averages، مش spans فردية.
OpenTelemetry بيقفل الفجوة دي بسطر instrumentation واحد لكل خدمة: بياخد الطلب من لحظة دخوله للـ gateway، يلاحقه عبر كل خدمة وكل DB query وكل Redis call، ويرسمه كـ waterfall بيقولك أي خدمة أكلت كام millisecond بالظبط.
المشكلة باختصار
الفرق بين الثلاثة بسيط: Metrics بتقول لك "في مشكلة". Logs بتقول لك "في error". Traces بتقول لك "في الخدمة X، خد Z millisecond، والسبب call لـ Redis اتعمله timeout بعد retry فشل". الفرق هنا هو نفس الفرق بين "العربية بتسخن" وبين "الفان بلت محتاج تغيير".
في أنظمة microservices، طلب واحد ممكن يمر على 5 لـ 12 خدمة. من غير tracing، انت في الظلام. ضربة console.log في كل خدمة + إعادة deploy = ساعتين شغل لتشخيص حاجة كان trace كامل هيقولها في 30 ثانية.
مثال للمبتدئ — شركة الشحن
تخيّل شحنة من الإسكندرية للرياض. الشحنة بتمر على 5 محطات: مخزن المنشأ، الشاحنة، الميناء، الجمارك، شركة التوصيل المحلية. كل محطة بتحط ختم على ورقة الشحنة فيه وقت الدخول والخروج، ورقم الشحنة الموحد على كل الأختام.
لو الشحنة وصلت متأخرة 6 ساعات، الورقة دي بالظبط هي اللي بتقول لك "اتأخرت 5 ساعات في الجمارك"، مش "في حتة في السكة". OpenTelemetry trace هو نفس ورقة الشحنة دي للطلب اللي بيمر على خدماتك. كل محطة = service. كل ختم = span. وقت الدخول والخروج = start_time و end_time. ورقم الشحنة الموحد على كل الأختام = trace_id.
التعريف العلمي الدقيق
بعد ما المثال وضّح الفكرة، دلوقتي التعريف بدقة:
- Trace: مجموعة spans مرتبطة بنفس الـ trace_id (UUID 128-bit) تمثل دورة حياة طلب واحد عبر النظام.
- Span: وحدة عمل واحدة (HTTP call، DB query، function execution). بيحتوي على span_id، parent_span_id (لبناء الشجرة)، start_time/end_time، attributes زي
http.methodوdb.statement، و events (لحظات داخل الـ span زي retry أو cache miss). - Context Propagation: الميكانيزم اللي بيمشّي الـ trace_id من خدمة لخدمة عبر HTTP headers. القاعدة المعيارية اسمها W3C Trace Context وبتستخدم header
traceparent. من غيره، كل خدمة هتعمل trace منفصل ومش هتعرف تربطهم.
مثال تنفيذي — instrumentation Node.js في 4 سطور
ملف tracing.js منفصل عن business logic: