مستوى المقال: محترف. موجّه لمهندسي الـ backend والـ SRE اللي بيشغّلوا خدمات مصغّرة في الإنتاج ومحتاجين يلاقوا سبب البطء بسرعة.
لو طلب POST /checkout بياخد 742 مللي ثانية وانت بتقلّب في لوجات 7 خدمات عشان تعرف مين المتسبّب، انت بتضيّع وقتك. الـ Distributed Tracing بيوريك الخدمة المسؤولة بالظبط في أقل من دقيقة، من غير ما تخمّن.
التتبّع الموزّع بـ OpenTelemetry: حدّد الخدمة اللي بتبطّئ نظامك
المشكلة باختصار
في المعمارية المتجانسة (monolith)، البطء بيتقاس بـ profiler واحد. في الخدمات المصغّرة، الطلب الواحد بيعدي على 5 لـ 15 خدمة عبر الشبكة. اللوج بيقولك إن كل خدمة "اشتغلت"، لكن مفيش حاجة بتربط سطور اللوج المتفرّقة في رحلة طلب واحدة. النتيجة: P95 latency بيرتفع، ومحدش عارف الخدمة المتسبّبة.
الـ tracing بيحل ده بإنه بيدّي كل طلب معرّف واحد بيتنقل مع الطلب من خدمة لخدمة. كل خدمة بتسجّل الجزء بتاعها تحت نفس المعرّف، فتقدر تجمّعهم وتشوف الرحلة كاملة.
المفهوم الأساسي: trace و span وانتشار السياق
قبل التعريف العلمي، خد المثال ده. تخيّل شحنة بتتبعت من مخزن لباب البيت. الشركة بتديها رقم تتبّع واحد. كل محطة (الفرز، الشحن الدولي، مكتب التوزيع، المندوب) بتسجّل دخول وخروج الشحنة تحت نفس الرقم. في الآخر بتفتح صفحة التتبّع وتشوف كل محطة أخدت قد إيه، وتعرف فين الشحنة اتأخرت.
دلوقتي التعريف الدقيق. الـ trace هو رحلة الطلب الكاملة عبر النظام، وله معرّف trace_id فريد. كل عملية داخل الرحلة (نداء HTTP، استعلام DB، نداء خارجي) بتتسجّل كـ span له span_id، ووقت بداية ونهاية، وعلاقة أب-ابن مع الـ span اللي ناداه. لما تجمّع كل الـ spans بنفس الـ trace_id بترتّبهم زمنيًا، بتطلع لوحة شلالية (waterfall) بتوريك أنهي span أخد أطول وقت.
القطعة اللي بتخلّي ده يشتغل عبر الشبكة اسمها context propagation: الخدمة بتبعت الـ trace_id و span_id الحالي في هيدر HTTP اسمه traceparent حسب مواصفة W3C Trace Context. شكله كده:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01الخدمة اللي بتستقبل الهيدر ده بتكمّل نفس الـ trace بدل ما تبدأ واحد جديد. ده اللي بيربط الخدمات مع بعض في رحلة واحدة.
التطبيق العملي: instrumentation بـ OpenTelemetry
OpenTelemetry (اختصارًا OTel) هو المعيار الموحّد تحت مظلة CNCF لتوليد الـ traces والـ metrics والـ logs. ميزته إنه vendor-neutral: بتجمّع البيانات مرة واحدة وتبعتها لأي backend (Jaeger، Tempo، Datadog) من غير ما تغيّر كود التطبيق.
أسرع طريقة في بايثون هي الـ auto-instrumentation. بيلفّ مكتبات شائعة (Flask، requests، psycopg) تلقائيًا من غير تعديل كود: