التتبع الموزع وOpenTelemetry

OpenTelemetry: المعيار الموحد

18 دقيقة الدرس 3 من 28

OpenTelemetry: المعيار الموحد

قبل عام 2019، كان كل مزود لخدمات المراقبة يشحن عميله الخاص، ومجموعة أدواته البرمجية الخاصة، وبروتوكول نقل بياناته الخاص. كان دمج أدوات المراقبة في تطبيق ما يعني اختيار مزود بعينه مسبقاً وتضمين ذلك الاختيار في شيفرتك البرمجية. أي تغيير لاحق كان يستلزم اقتلاع آلاف الأسطر من استدعاءات أدوات المراقبة. جاء OpenTelemetry (اختصاراً OTel) ليكسر هذا القيد مرة واحدة وإلى الأبد.

ما هو OpenTelemetry فعلياً؟

OpenTelemetry هو معيار مفتوح ومُدرج تحت مظلة CNCF ومجموعة من المكتبات لتوليد بيانات المراقبة وجمعها وتصديرها: التتبع والمقاييس والسجلات. وهو محايد تجاه المزودين بحكم تصميمه. تُعِد الأدوات مرة واحدة، ثم توجّه البيانات إلى أي خلفية تشاء — Jaeger أو Datadog أو Honeycomb أو Grafana Tempo أو AWS X-Ray — بتغيير سطر إعداد واحد فقط، دون المساس بشيفرة تطبيقك.

يُعرِّف OTel ثلاث طبقات متمايزة:

  • API — واجهات برمجية لكل لغة لإنشاء الامتدادات (Spans) وتسجيل المقاييس وإصدار سجلات. الـ API خفيف ومتعمَّد. يمكن استدعاؤه من كود المكتبات حتى لو لم يكن هناك SDK (تصبح الاستدعاءات بلا تأثير). هذا ما تُوثِّقه المكتبات مفتوحة المصدر.
  • SDK — التنفيذ الفعلي للـ API. يتولى الـ SDK قرارات أخذ العينات (Sampling) وخطوط المعالجة والمُصدِّرين (Exporters). يُعِد مالكو التطبيقات الـ SDK ويزودونه عند بدء التشغيل؛ ولا يتعامل معه مؤلفو المكتبات قط.
  • OTLP (بروتوكول OpenTelemetry) — بروتوكول النقل. gRPC (المنفذ 4317) أو HTTP/protobuf (المنفذ 4318). بات OTLP اليوم لغة المراقبة المشتركة: كل خلفية جدية تدعمه بشكل أصلي. استخدام OTLP يعني أنك لم تعد مرتبطاً بنموذج JSON الخاص بـ Zipkin أو صيغة Thrift الخاصة بـ Jaeger.
لماذا يهم الفصل بين API والـ SDK: يمكن لمكتبة HTTP مفتوحة المصدر شائعة الاستخدام أن تُدرج استدعاءات OTel API لإنشاء الامتدادات بأمان دون أن تُجبر مستخدميها على أي خلفية مراقبة. إذا ثبّت مالك التطبيق OTel SDK، أصبحت تلك الامتدادات حقيقية. وإن لم يفعل، فالاستدعاءات لا تكاد تكلف شيئاً. هذا هو النمط الذي تتبناه كل إطارات العمل الكبرى (Spring Boot وExpress وDjango وLaravel).

بنية OTel في لمحة

OpenTelemetry architecture: API, SDK, Collector, and vendor backends Your Application OTel API Tracer / Meter / Logger OTel SDK Sampling · Processors Exporters Auto-Instrumentation Zero-code agent / hooks OTLP OTel Collector Receivers Processors Exporters :4317 gRPC / :4318 HTTP Jaeger / Tempo Trace backends Prometheus / Mimir Metrics backends Loki / Datadog Log backends OTLP
بنية OpenTelemetry: تقع API/SDK داخل تطبيقك، ويستقبل Collector بيانات OTLP ويوزعها على عدة خلفيات في آنٍ واحد.

الحياد تجاه المزودين في الواقع العملي

الفائدة الملموسة: مع OTel يمكنك توجيه بيانات التتبع ذاتها إلى Jaeger (مستضاف ذاتياً ومجاني) لفريق مناوبتك، وفي الوقت نفسه إلى Honeycomb أو Datadog لمنصة SRE الخاصة بك — دون المساس بتطبيقك البتة. يجعل نموذج خط المعالجة في Collector هذا مجرد تغيير في الإعداد، لا تغييراً في الكود.

في Google وUber وغيرهما من المشغّلين الكبار، يكون الإعداد الإنتاجي المعتاد كالتالي:

  1. تُصدِر التطبيقات OTLP إلى Collector جانبي (sidecar) محلي أو DaemonSet (وليس مباشرةً إلى الخلفية — فأي انقطاع في الشبكة داخل عملية التطبيق سيُضيِّع الامتدادات).
  2. يُطبِّق Collector أخذ عينات قائم على الذيل (tail-based sampling)، ويُثري الامتدادات ببيانات تعريف Kubernetes، ويوزعها على عدة خلفيات.
  3. تستطيع الفرق تبديل الخلفيات أو إضافة خلفيات جديدة دون نشر أي تحديث للتطبيق.

التعليم التلقائي مقابل التعليم اليدوي

يوفر OTel تعليماً تلقائياً (auto-instrumentation) لمعظم الأطر الكبرى: يُعالج عميل Java إطار Spring Boot واتصالات JDBC وgRPC وعملاء HTTP عبر حقن البايت كود عند بدء تشغيل JVM. تلتف أداة opentelemetry-instrument في Python على Django/FastAPI/SQLAlchemy تلقائياً. يستخدم Node.js حزمة @opentelemetry/auto-instrumentations-node. تحصل على امتدادات لكل طلب وارد واتصال HTTP صادر واستعلام قاعدة بيانات دون أي تغيير في الكود.

يُحجز التعليم اليدوي — باستخدام OTel API مباشرةً — للامتدادات على مستوى الأعمال: "معالجة الدفعة" و"تقييم درجة المخاطر" و"تصيير خلاصة التوصيات". هذه هي الامتدادات التي تشرح فعلاً لماذا حدث التأخر، لا مجرد أن استدعاء HTTP كان بطيئاً.

نمط الشركات الكبرى: ابدأ بالتعليم التلقائي للحصول على تغطية 80% فوراً. ثم علِّم مساراتك التجارية الأكثر أهمية يدوياً. تعامل مع الامتدادات المخصصة كواجهة برمجية من الدرجة الأولى — سمِّها بالمفهوم التجاري لا بتفاصيل التنفيذ (order.process لا OrderService.processOrder).

إعداد OTel SDK باختصار (Python)

يوضح ما يلي كيفية إعداد الـ SDK مع مُصدِّر OTLP — هذا ما يُشغَّل عند بدء التطبيق، في خطاف تهيئة الإطار أو في وحدة tracing.py مخصصة:

# tracing.py — OTel SDK bootstrap (Python) from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.sdk.resources import Resource resource = Resource.create({ "service.name": "checkout-service", "service.version": "2.4.1", "deployment.environment": "production", }) exporter = OTLPSpanExporter( endpoint="http://otel-collector:4317", # gRPC بلا TLS داخل الكلستر # endpoint="https://collector.prod:4317", # TLS للاتصالات بين الكلسترات ) provider = TracerProvider(resource=resource) provider.add_span_processor(BatchSpanProcessor(exporter)) trace.set_tracer_provider(provider) # في معالج الطلبات: tracer = trace.get_tracer("checkout-service") def process_order(order_id: str): with tracer.start_as_current_span("order.process") as span: span.set_attribute("order.id", order_id) span.set_attribute("order.region", "eu-west-1") # ... منطق الأعمال

لاحظ الـ resource: كل امتداد يُصدره هذا الـ SDK يحمل service.name وservice.version وdeployment.environment. هذه اتفاقيات دلالية (Semantic Conventions) من OTel — أسماء سمات موحدة تستخدمها الخلفيات لتجميع آثار التتبع وتصفيتها. الاتساق عبر أسطولك من الخدمات أمر بالغ الأهمية: إذا ابتكر خمسة فرق مفاتيح خاصة بهم لأسماء الخدمات، لن تستطيع أي خلفية ربطها ببعض.

OTLP: بروتوكول النقل

OTLP بروتوكول معرَّف بـ Protocol Buffers يعمل فوق gRPC أو HTTP. نقل gRPC (المنفذ 4317) هو المفضل لأحمال العمل الإنتاجية ذات الحجم الكبير: يُعدِّد الطلبات عبر اتصال TCP واحد، ويُطبِّق الضغط الخلفي، ويضغط البيانات بكفاءة. أما نقل HTTP (المنفذ 4318) فيفيد حين يكون gRPC محجوباً بالوكلاء أو عند الإرسال من المتصفح.

تفصيل تشغيلي مهم: تُجمِّع مُصدِّرات OTLP الامتدادات افتراضياً. يُخزِّن BatchSpanProcessor الامتدادات في الذاكرة ويُفرِّغها وفق جدول زمني (افتراضياً: كل 5 ثوانٍ، بحد أقصى 512 امتداداً للدفعة الواحدة). وهذا يعني:

مشكلة إنتاجية — الإغلاق السلس: إذا انهار تطبيقك أو قُتل بسبب نفاد الذاكرة، فإن الامتدادات المُخزَّنة في BatchSpanProcessor ستُفقد. استدعِ دائماً provider.shutdown() في معالج SIGTERM الخاص بك، واضبط max_export_batch_size بتحفظ. Collector الجانبي يُخفف من هذه المخاطرة — الامتدادات في بفر Collector تنجو من إعادة تشغيل Pod التطبيق.

الاتفاقيات الدلالية

يُوفر OTel سجلاً من أسماء السمات الموحدة لـ HTTP وقواعد البيانات والرسائل وRPC وغيرها. هذه ليست اقتراحات — إنها المفردات المشتركة التي تجعل آثار التتبع عبر الفرق واللغات مقروءةً في أي خلفية. أمثلة:

  • http.method وhttp.status_code وhttp.url — امتدادات HTTP
  • db.system وdb.statement وdb.name — امتدادات قواعد البيانات
  • messaging.system وmessaging.destination — امتدادات Kafka/RabbitMQ
  • rpc.system وrpc.service وrpc.method — امتدادات gRPC

اعتماد الاتفاقيات منذ البداية يعني أن لوحات Grafana وقواعد التنبيه ستعمل لخدمات كل فريق دون تخصيص لكل فريق على حدة. تجاهلها يعني أن كل فريق سيبني مخطط سماته الخاص، وسيقضي فريق المنصة وقته في كتابة تحويلات رسم السمات (attribute-mapping transforms) في Collector — وهو دين تقني باهظ الثمن على نطاق واسع.

# التحقق من استقبال Collector للامتدادات (راجع السجلات أو استخدم grpc_cli): grpcurl -plaintext -d '{}' otel-collector:4317 opentelemetry.proto.collector.trace.v1.TraceService/Export # أو تحقق من نقطة صحة Collector: curl http://otel-collector:13133/ # عرض عدد الامتدادات من مقاييس Prometheus الخاصة بـ Collector: curl http://otel-collector:8888/metrics | grep otelcol_receiver_accepted_spans

ضمان OpenTelemetry بسيط لكنه عميق الأثر: استثمارك في المراقبة ملكٌ لك أنت، لا لمزودك. مع تطور الخلفيات والمزودين، يظل توثيق أدواتك ثابتاً. على نطاق الشركات الكبرى — آلاف الخدمات وعشرات الفرق ونشر متعدد السحابة — هذه القابلية للنقل ليست ميزة كمالية، بل متطلب معماري أساسي.

ES
Edrees Salih
منذ ساعة

We are still cooking the magic in the way!