أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

المنصة مبنية على الوضوح، التطبيق، والنتيجة النافعة: شرح مرتب يساعدك تفهم الأدوات، تكتب كودًا أفضل، وتستخدم الذكاء الاصطناعي بوعي داخل العمل الحقيقي.

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

Tail Sampling بالعربي: قلل تكلفة الـ Tracing من غير ما تعمي نفسك

📅 ٢٤ أبريل ٢٠٢٦⏱ 4 دقائق قراءة
Tail Sampling بالعربي: قلل تكلفة الـ Tracing من غير ما تعمي نفسك

Tail Sampling بالعربي: قلل تكلفة الـ Tracing من غير ما تعمي نفسك

مستوى القارئ: متوسط

هتخرج من المقال بإعداد عملي يخلي OpenTelemetry Collector يحتفظ بالـ traces المهمة، بدل ما يبعث كل الضوضاء لنظام التخزين.

المشكلة باختصار

الطريقة الشائعة إنك تشغل tracing وتبعت كل span إلى Tempo أو Jaeger أو أي backend. الطريقة دي بتفشل لما حجم الطلبات يكبر. هتشوف كل حاجة، لكن هتدفع في storage وnetwork وquery latency، وبعد شهر هتبدأ تقلل retention بدل ما تصلح التصميم.

الافتراض إن عندك خدمة API بتستقبل حوالي 5 ملايين request يوميًا، وكل request ينتج trace متوسطه 12 span. لو احتفظت بكل شيء، أنت بتتعامل مع 60 مليون span يوميًا. حتى لو كل span بعد الضغط حجمه 500 بايت فقط، ده حوالي 30GB بيانات خام يوميًا قبل metadata والفهارس.

مخطط بصري يوضح OpenTelemetry Collector بين التطبيقات ونظام تخزين traces مع تطبيق tail sampling

الفكرة: قرار العينة بعد ما الـ trace يكتمل

ركز في الفرق. Head sampling بياخد القرار في بداية الطلب. يعني ممكن يرمي request فشل في آخر خطوة لأنه كان اختار من البداية إنه لا يحتفظ به. Tail sampling يستنى شوية، يجمع spans الخاصة بنفس trace_id، ثم يقرر.

مثال بسيط: عندك طلب checkout بدأ طبيعي، وبعد 1.8 ثانية فشل في payment provider. لو استخدمت sampling عشوائي 5% من البداية، غالبًا الطلب ده هيختفي. مع tail sampling تقدر تقول: احتفظ بكل ERROR، واحتفظ بكل trace أبطأ من 2000ms، وخد 5% فقط من النجاح العادي.

علميًا، الـ OpenTelemetry Collector مبني من receivers وprocessors وexporters داخل pipelines. الـ processor يقدر يغير أو يفلتر البيانات قبل التصدير، والـ tail_sampling processor في توزيعة contrib يقيّم traces بناءً على policies مثل status_code وlatency وprobabilistic.

إعداد عملي قابل للنسخ

استخدم الإعداد التالي كبداية. هو يستقبل traces عبر OTLP، يحمي الذاكرة، يطبق tail sampling، ثم يرسل النتائج إلى Tempo. عدّل endpoint حسب بيئتك.

YAML
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

processors:
  memory_limiter:
    check_interval: 5s
    limit_mib: 1024
    spike_limit_mib: 256

  tail_sampling:
    decision_wait: 20s
    num_traces: 50000
    expected_new_traces_per_sec: 2500
    decision_cache:
      sampled_cache_size: 100000
      non_sampled_cache_size: 100000
    policies:
      - name: keep-errors
        type: status_code
        status_code:
          status_codes: [ERROR]
      - name: keep-slow-traces
        type: latency
        latency:
          threshold_ms: 2000
      - name: sample-success-noise
        type: probabilistic
        probabilistic:
          sampling_percentage: 5

  batch:
    timeout: 5s
    send_batch_size: 1024

exporters:
  otlp/tempo:
    endpoint: tempo:4317
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [memory_limiter, tail_sampling, batch]
      exporters: [otlp/tempo]

الترتيب مهم. ضع processors اللي تضيف سياق مهم قبل tail_sampling. بعد tail_sampling استخدم batch عشان التصدير يبقى أقل تكلفة. لو عندك k8sattributes أو resource processor، غالبًا مكانهم قبل tail_sampling.

مخطط قرار tail sampling يوضح الاحتفاظ بالأخطاء والطلبات الأبطأ من ثانيتين ونسبة خمسة بالمئة من الطلبات الناجحة

الأرقام المتوقعة والـ trade-off

لو 2% من الطلبات errors أو أبطأ من 2 ثانية، ومعاهم 5% من باقي النجاح، هتحتفظ تقريبًا بـ 6.9% من traces بدل 100%. في مثال 60 مليون span يوميًا، ده ينزل الحجم النظري من 30GB إلى حوالي 2.1GB يوميًا. الرقم تقديري، لكنه كافي لتوضيح الاتجاه.

الـ trade-off هنا واضح. بتكسب تكلفة تخزين أقل وqueries أسرع وتحقيقات أوضح وقت الأعطال. بتخسر ذاكرة داخل الـ Collector، لأن tail_sampling لازم يحتفظ بـ traces مؤقتًا لحد decision_wait. كمان لو spans لنفس trace وصلت لأكثر من Collector instance بدون load balancing مناسب، القرار ممكن يبقى ناقص.

راقب مؤشرات الـ Collector نفسها. لو decision_wait قريب من زمن وصول spans المتأخرة، ارفعه تدريجيًا من 20s إلى 30s. ولو الذاكرة بتضغط، قلل num_traces أو زوّد موارد الـ Collector. أفضل طريقة هنا إنك تقيس قبل وبعد، مش تغير الأرقام بالمزاج.

متى لا تستخدم هذه الطريقة

لا تستخدم tail sampling كحل أول لو حجم الـ traffic صغير والتكلفة مش مشكلة. Head sampling أبسط وأقل استهلاكًا للذاكرة. لا تستخدمه أيضًا لو التحقيقات عندك تحتاج 100% من traces لأسباب امتثال أو forensics. وفي بيئات latency شديدة الحساسية، اختبر Collector منفصل قبل الإنتاج لأن القرار بيتأخر لحد اكتمال الـ trace أو انتهاء decision_wait.

مصادر راجعتها

  • OpenTelemetry Collector Configuration: يوضح بنية receivers وprocessors وexporters وservice pipelines.
  • OpenTelemetry Collector Processors: يذكر tail sampling وmemory limiter كـ processors مدعومة.
  • Tail Sampling Processor README: يوضح policies مثل latency وstatus_code وprobabilistic، والتنبيه الخاص بتجميع spans لنفس trace.
  • OpenTelemetry tail sampling sample configuration: مثال رسمي حديث لفكرة الاحتفاظ بالأخطاء والطلبات البطيئة حسب criticality.

الخطوة التالية

الخطوة التالية: شغّل الإعداد على staging لمدة ساعة، وقارن عدد traces المصدّرة قبل وبعد. لو الأخطاء والطلبات الأبطأ من 2 ثانية ظاهرة بوضوح، انقل نفس السياسة للإنتاج مع مراقبة ذاكرة الـ Collector.

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة