تخطَّ إلى المحتوى

🏗️ شرح المايكروسيرفيس (Microservices)

المراقبة والتتبع الموزع

الدرس 14 من 25· ⏱ 2 دقائق قراءة

التحدي

في النظام الموزع، الطلب الواحد يمر عبر خدمات متعددة. كيف تتبع مساره بالكامل؟

OpenTelemetry

مكتبة مفتوحة المصدر لجمع التتبع والمقاييس والسجلات.

const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');

const provider = new NodeTracerProvider();
provider.addSpanProcessor(
  new SimpleSpanProcessor(new JaegerExporter({
    endpoint: 'http://jaeger:14268/api/traces',
  }))
);
provider.register();

const tracer = provider.getTracer('user-service');

إنشاء Spans

// تتبع طلب HTTP عبر الخدمات
async function createUser(req, res) {
  const span = tracer.startSpan('create-user');
  span.setAttribute('user.email', req.body.email);

  try {
    const user = await db.users.create(req.body);
    span.setAttribute('user.id', user.id);

    // إرسال حدث مع trace context
    const headers = {};
    tracer.inject(span, 'http_text_format', headers);

    await axios.post('http://notification-service/send-welcome', {
      userId: user.id,
    }, { headers });  // تمرير trace context

    span.setStatus({ code: SpanStatusCode.OK });
    res.json(user);
  } catch (err) {
    span.recordException(err);
    span.setStatus({ code: SpanStatusCode.ERROR });
    res.status(500).json({ error: err.message });
  } finally {
    span.end();
  }
}

التتبع عبر HTTP

// نقل trace context بين الخدمات
const { propagation } = require('@opentelemetry/api');

app.use((req, res, next) => {
  // استخراج context من الطلب الوارد
  const activeContext = propagation.extract(
    'http_text_format',
    req.headers
  );

  // إنشاء span جديد ضمن نفس trace
  const span = tracer.startSpan(
    req.method + ' ' + req.path,
    { parent: activeContext }
  );

  // تخزين span للاستخدام
  req.span = span;
  next();
});

Jaeger Dashboard

بعد ربط Jaeger، يمكنك:

  • رؤية مسار الطلب عبر كل الخدمات
  • معرفة أين حدث التأخير
  • تحليل الأخطاء والفشل

المقاييس (Metrics)

const { MeterProvider } = require('@opentelemetry/sdk-metrics-base');
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');

const exporter = new PrometheusExporter({ port: 9464 });
const meter = new MeterProvider().getMeter('user-service');

const requestCount = meter.createCounter('requests_total', {
  description: 'إجمالي الطلبات',
});

const requestDuration = meter.createHistogram('request_duration_ms', {
  description: 'مدة الطلب بالملليثانية',
  unit: 'ms',
});

// استخدام
app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    requestCount.add(1, { path: req.path, method: req.method, status: res.statusCode });
    requestDuration.record(Date.now() - start, { path: req.path });
  });
  next();
});

السجلات (Logs) الموحدة

const pino = require('pino');

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  formatters: {
    level(label) { return { level: label }; },
  },
  // إضافة trace ID لكل سجل
  mixin() {
    return {
      traceId: span?.spanContext()?.traceId,
      service: 'user-service',
      environment: process.env.NODE_ENV,
    };
  },
});

logger.info({ userId: '123', action: 'create' }, 'تم إنشاء مستخدم جديد');

أدوات

الأداةالاستخدام
Jaegerتتبع موزع
Prometheusمقاييس وتنبيهات
Grafanaلوحات عرض
ELK Stackسجلات مركزية
OpenTelemetryجمع موحد للبيانات

⚠️ بدون المراقبة والتتبع، أنت تعمل في الظلام — ابني Observability من اليوم الأول

🎯 التالي: 14-security

شرح المراقبة والتتبع الموزع — المايكروسيرفيس (Microservices) بالعربي
المراقبة والتتبع الموزعالمايكروسيرفيس (Microservices) بالعربي · The Code Fix

هل كان هذا الدرس مفيدًا؟