OpenTelemetry Collector: اعزل الـ telemetry قبل ما تكسر التطبيق
لو كل microservice عندك بيبعت traces وmetrics مباشرة لأداة المراقبة، فأنت رابط استقرار التطبيق باستقرار مسار المراقبة. الحل العملي هنا: حط OpenTelemetry Collector في النص، وخليه يجمع، يضغط، ويقرر إيه يتبعت وإيه يتساب.
مستوى القارئ: محترف
المشكلة باختصار
اللي بيحصل فعلاً في فرق كتير إن كل خدمة فيها OTLP exporter يبعث مباشرة إلى SaaS monitoring أو Jaeger أو backend خارجي. الطريقة دي بسيطة في البداية، لكنها بتفشل لما عدد الخدمات يكبر. لو عندك 40 خدمة، وكل خدمة بتطلع 300 request telemetry في الدقيقة، فأنت بتعمل حوالي 12,000 طلب تصدير في الدقيقة قبل ما المستخدم نفسه يضغط على النظام.
الافتراض إن عندك تطبيق موزع بحجم متوسط: 20 إلى 60 خدمة، وtraffic ثابت، وأنت عايز traces للأخطاء والطلبات البطيئة أكثر من traces لكل طلب طبيعي. في الحالة دي، إرسال كل شيء مباشرة مكلف ومزعج. بتكسب بساطة الإعداد، لكن بتخسر التحكم في التكلفة والضغط والفلترة.
مثال بسيط قبل التعريف العلمي
ركز في المثال ده: عندك فرع شركة فيه 40 موظف، وكل موظف يرسل تقريرًا منفصلًا للإدارة كل 5 دقائق. الإدارة هتستلم مئات الرسائل الصغيرة. الأفضل إن فيه مسؤول في الفرع يجمع التقارير، يحذف التكرار، ويرسل ملخصًا واضحًا. OpenTelemetry Collector بيعمل نفس الدور تقريبًا، لكن مع traces وmetrics وlogs.
علميًا، الـ Collector هو خدمة مستقلة تستقبل telemetry غالبًا عبر OTLP، تمررها على processors مثل memory_limiter وbatch وtail_sampling، ثم تصدرها إلى exporters مثل OTLP, Prometheus, Jaeger, أو أي backend مدعوم. التطبيق يظل ينتج نفس الإشارات، لكن قرار التجميع والتصفية ينتقل لخارج التطبيق.
إعداد عملي قابل للنسخ
أفضل طريقة كبداية: شغّل Collector قريب من الخدمات، سواء كـ sidecar في حالات خاصة أو كخدمة مستقلة داخل نفس الشبكة. المثال التالي config مختصر يشتغل كفكرة أساسية. عدّل endpoint النهائي حسب backend عندك.
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_mib: 512
spike_limit_mib: 128
batch:
timeout: 5s
send_batch_size: 1024
tail_sampling:
decision_wait: 10s
num_traces: 50000
policies:
- name: keep-errors
type: status_code
status_code:
status_codes: [ERROR]
- name: keep-slow-requests
type: latency
latency:
threshold_ms: 750
exporters:
otlp:
endpoint: monitoring.example.com:4317
tls:
insecure: false
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, tail_sampling, batch]
exporters: [otlp]
metrics:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [otlp]شغله محليًا للتجربة:
docker run --rm \
-p 4317:4317 -p 4318:4318 \
-v "$PWD/otel-collector-config.yaml:/etc/otelcol/config.yaml" \
otel/opentelemetry-collector-contrib:latest \
--config=/etc/otelcol/config.yamlبعدها وجّه التطبيق إلى OTEL_EXPORTER_OTLP_ENDPOINT=http://collector:4318 بدل endpoint الخارجي. كده التطبيق بقى يتكلم مع خدمة داخلية أسرع وأسهل في التحكم.
الأرقام: قبل وبعد
في سيناريو واقعي لفريق عنده 35 خدمة، الإرسال المباشر عمل حوالي 12,000 طلب telemetry في الدقيقة. بعد إضافة batch انخفض العدد إلى 2,400 طلب تقريبًا. بعد tail_sampling للـ traces، وصل الحمل إلى 950 طلب في الدقيقة مع الاحتفاظ بالأخطاء والطلبات أبطأ من 750ms. الأرقام هنا تقديرية مبنية على workload متوسط، لكنها كافية لتوضيح الاتجاه.
الـ trade-off هنا واضح. بتكسب تقليل ضغط الشبكة، endpoint واحد للتغيير، وسياسات sampling مركزية. بتخسر مكوّن جديد لازم تراقبه، وذاكرة إضافية للـ Collector، وتأخير بسيط بسبب batch وtail sampling. لو decision_wait عندك 10 ثواني، فبعض traces مش هتظهر فورًا في لوحة المراقبة.
ما الذي تراقبه بعد التشغيل؟
- Queue أو dropped data: لو في بيانات بتقع، زوّد الموارد أو قلل sampling.
- Memory usage: لا ترفع
num_tracesبدون حد ذاكرة واضح. - Export latency: لو backend بطيء، الـ Collector هيبان عليه الضغط قبل التطبيق.
- نسبة الاحتفاظ بالأخطاء: تأكد إن كل traces ذات status ERROR بتوصل فعلاً.
بدل ما تزود sampling عشوائيًا، ابدأ بسياسة واضحة: احتفظ بكل الأخطاء، كل الطلبات فوق 750ms، و1% فقط من الطلبات الطبيعية لو احتجت baseline. كده أنت بتدفع على الإشارة المهمة، مش الضوضاء.
متى لا تستخدم هذه الطريقة
لا تستخدم Collector من أول يوم لو عندك monolith صغير وترافيك محدود وأداة مراقبة واحدة. الإعداد المباشر أبسط. لا تستخدم tail_sampling لو محتاج رؤية فورية لكل trace في debugging حي. ولا تستخدم Collector كعذر لإرسال بيانات حساسة؛ التنظيف لازم يحصل قبل التصدير أو بسياسات processors واضحة.
كمان لو فريقك لا يراقب الـ Collector نفسه، فأنت نقلت نقطة الفشل ولم تحلها. على الأقل راقب CPU، الذاكرة، وعدد البيانات المرفوضة. لو الـ Collector وقع تمامًا، لازم exporter في التطبيق يفشل بهدوء ولا يوقف request المستخدم.
المصادر
- OpenTelemetry Collector documentation
- OpenTelemetry batch processor
- OpenTelemetry memory limiter processor
- OpenTelemetry tail sampling processor
الخطوة التالية
الخطوة التالية: خذ خدمة واحدة فقط، وجّه OTLP endpoint بتاعها إلى Collector داخلي لمدة يوم، وقارن عدد export requests قبل وبعد. لو الأخطاء والطلبات البطيئة لسه واصلة بوضوح، وسّع التجربة على باقي الخدمات.