Skip to main content
مستندات
مرکز آموزش

مدیریت محتوا را با راهنماهای جامع، آموزش‌ها و مستندات API به‌خوبی یاد بگیرید

لینک‌های سریع

مقیاس‌پذیر کردن نظارت بر محتوا

راه‌اندازی نظارتی که برای ۱٬۰۰۰ پیام در روز جواب می‌دهد، در مقیاس یک میلیون پیام از کار می‌افتد: محدودیت‌های نرخ درخواست دردسرساز می‌شوند، تأخیر هر فراخوانی روی هم جمع می‌شود و هزینه‌ها سر به فلک می‌کشند. این راهنما نشان می‌دهد چگونه نظارت Discuse را به پایپ‌لاین‌های پرترافیک وصل کنید — چه زمانی مسدود کنید، چه زمانی بررسی را در پس‌زمینه انجام دهید، چه چیزهایی را کش کنید و چطور در زمان اوج بار مسیر جایگزین انتخاب کنید.

وقتی نظارت در مقیاس بزرگ‌تر دچار مشکل می‌شود، چه چیزی از کار می‌افتد؟

هر مشکل مقیاس‌پذیری یک علت مشخص و یک راه‌حل مشخص دارد:

چالش تأثیر راه‌حل
رشد حجم محدودیت نرخ API، افزایش هزینه‌ها پردازش ناهمگام، کش‌کردن
الزامات تأخیر تجربه کاربری ضعیف نظارت پیش از انتشار، صف‌بندی
مدیریت هزینه محدودیت‌های بودجه مسیریابی هوشمند، کش‌کردن
یکنواختی اعمال نامتوازن قوانین پیکربندی متمرکز
مدیریت اوج بار افت کیفیت سرویس مقیاس‌پذیری خودکار، صف‌ها

از کدام الگوی معماری باید استفاده کنم؟

الگوی ۱: پیش‌نظارتی همگام

مناسب برای: محتوای کم‌حجم و پرریسک (پرداخت‌ها، مسائل حقوقی)

User Input → API Call → Moderation → Decision → Response
                ↓
           (Blocking call)
// Simple synchronous flow
async function createPost(content) {
  // Check moderation before saving
  const result = await checkModeration(content);

  if (result.has_violations) {
    throw new ModerationError(result.message);
  }

  // Safe to publish
  return await savePost(content);
}

مزایا: ساده، بازخورد فوری معایب: تأخیر را افزایش می‌دهد، توان پردازش را محدود می‌کند

الگوی ۲: پس‌نظارتی ناهمگام

مناسب برای: محتوای پرحجم و کم‌ریسک‌تر (نظرها، پیام‌ها)

User Input → Save (Pending) → Publish → Background Check → Action
                                              ↓
                                    ┌────────┴────────┐
                                    ↓                 ↓
                                  Safe            Violation
                                    ↓                 ↓
                                  Keep             Remove
// Async flow with queue
async function createPost(content) {
  // Save immediately with pending status
  const post = await savePost(content, { status: 'pending' });

  // Queue for async moderation
  await moderationQueue.add('check-content', {
    postId: post.id,
    content: content
  });

  return post;
}

// Background worker
moderationQueue.process('check-content', async (job) => {
  const result = await checkModeration(job.data.content);

  if (result.has_violations) {
    await removePost(job.data.postId);
    await notifyUser(job.data.postId, 'content_removed');
  } else {
    await updatePost(job.data.postId, { status: 'approved' });
  }
});

مزایا: غیرمسدودکننده، مناسب برای حجم بالا معایب: محتوای زیان‌بار ممکن است برای مدت کوتاهی قابل مشاهده باشد

الگوی ۳: نظارت چندلایه

مناسب برای: رویکردی متعادل همراه با بهینه‌سازی هزینه

User Input → Quick Check → High Confidence? ──Yes──► Auto-decision
                              │
                              No
                              ↓
                         Full Analysis ──► Decision
async function tieredModeration(content) {
  // Tier 1: Fast local checks (regex, blocklists)
  const localResult = await quickLocalCheck(content);
  if (localResult.definiteViolation) {
    return { action: 'block', source: 'local' };
  }

  // Tier 2: Cached API results
  const cacheKey = hashContent(content);
  const cached = await cache.get(cacheKey);
  if (cached) {
    return { action: cached.action, source: 'cache' };
  }

  // Tier 3: Full API check
  const apiResult = await checkModeration(content);
  await cache.set(cacheKey, apiResult, TTL);

  return { action: determineAction(apiResult), source: 'api' };
}

الگوی ۴: پخش به چند مسیر همراه با تجمیع

مناسب برای: چند نوع بررسی با مقیاس‌پذیری مستقل

                    ┌──► Text Check ──┐
                    │                  │
User Input ──► Router ──► Image Check ──► Aggregator ──► Decision
                    │                  │
                    └──► Link Check ──┘
async function parallelModeration(content) {
  const checks = [];

  if (content.text) {
    checks.push(checkText(content.text));
  }

  if (content.images?.length) {
    checks.push(checkImages(content.images));
  }

  if (content.links?.length) {
    checks.push(checkLinks(content.links));
  }

  // Run all checks in parallel
  const results = await Promise.all(checks);

  // Aggregate results
  return aggregateResults(results);
}

function aggregateResults(results) {
  // Most severe result wins
  const hasViolation = results.some(r => r.has_violations);
  const maxScore = Math.max(...results.map(r => r.max_score || 0));

  return {
    has_violations: hasViolation,
    max_score: maxScore,
    details: results
  };
}

راهبردهای کش‌کردن

کش‌کردن بر اساس محتوا

نتایج را برای محتوای یکسان کش کنید:

const cache = new Redis();

async function checkWithCache(content) {
  const hash = crypto.createHash('sha256')
    .update(content.text || '')
    .update(JSON.stringify(content.images || []))
    .digest('hex');

  // Check cache first
  const cached = await cache.get(`mod:${hash}`);
  if (cached) {
    return { ...JSON.parse(cached), cached: true };
  }

  // API call
  const result = await callModerationAPI(content);

  // Cache for 24 hours
  await cache.setex(`mod:${hash}`, 86400, JSON.stringify(result));

  return { ...result, cached: false };
}

کش‌کردن بر اساس کاربر

تصمیم‌ها را برای متخلفان تکراری کش کنید:

async function checkUserHistory(userId) {
  const recentViolations = await cache.get(`violations:${userId}`);

  if (recentViolations > 5) {
    // Flag for enhanced scrutiny
    return { enhancedModeration: true };
  }

  return { enhancedModeration: false };
}

async function recordViolation(userId) {
  await cache.incr(`violations:${userId}`);
  await cache.expire(`violations:${userId}`, 86400 * 7); // 7 days
}

مدیریت صف

صف‌های اولویت‌دار

انواع مختلف محتوا را با اولویت‌های متفاوت مدیریت کنید:

const queues = {
  critical: new Queue('moderation-critical'),  // Reports, appeals
  high: new Queue('moderation-high'),          // Public posts
  normal: new Queue('moderation-normal'),      // Comments, DMs
  low: new Queue('moderation-low')             // Profile updates
};

async function queueForModeration(content, priority = 'normal') {
  const queue = queues[priority] || queues.normal;

  return queue.add('check', {
    contentId: content.id,
    type: content.type,
    data: content
  }, {
    priority: getPriorityNumber(priority),
    timeout: getTimeout(priority)
  });
}

رعایت محدودیت نرخ

هر کلید API یک محدودیت تعداد درخواست در دقیقه دارد؛ عبور از آن باعث می‌شود API درخواست را با خطای "rate limit exceeded" رد کند. از سمت خودتان درخواست‌ها را محدود کنید تا زیر این سقف بمانید و سهمیه را برای فراخوانی‌های تکراری هدر ندهید. سقف دقیقه‌ای محدودکننده را مطابق RPM پیکربندی‌شده برای کلیدتان تنظیم کنید:

const Bottleneck = require('bottleneck');

const limiter = new Bottleneck({
  maxConcurrent: 50,                   // Cap parallel requests
  minTime: 20,                         // Min 20ms between requests
  reservoir: YOUR_KEY_RPM,             // Match your API key's per-minute limit
  reservoirRefreshAmount: YOUR_KEY_RPM,
  reservoirRefreshInterval: 60 * 1000  // Refill each minute
});

async function rateLimitedCheck(content) {
  return limiter.schedule(() => checkModeration(content));
}

سهمیه از محدودیت نرخ جداست: هر فراخوانی از سقف ماهانه درخواست‌های API در پلن شما کم می‌کند، و شیء usage در پاسخ، مقادیر api_requests_used، api_requests_limit و api_requests_remaining را گزارش می‌دهد تا بتوانید ظرفیت باقی‌مانده را زیر نظر داشته باشید.

صف‌های نامه‌های مرده

تلاش‌های ناموفق برای بررسی محتوا را مدیریت کنید:

moderationQueue.process('check-content', async (job) => {
  try {
    const result = await checkModeration(job.data.content);
    await applyDecision(job.data.contentId, result);
  } catch (error) {
    if (job.attemptsMade < 3) {
      throw error; // Retry
    }

    // Move to dead letter queue after 3 attempts
    await deadLetterQueue.add('failed-moderation', {
      ...job.data,
      error: error.message,
      attempts: job.attemptsMade
    });

    // Apply safe default (hold for review)
    await holdForManualReview(job.data.contentId);
  }
});

بهینه‌سازی هزینه

مسیریابی هوشمند

فقط زمانی از APIهای پولی استفاده کنید که واقعاً لازم است:

async function smartModeration(content) {
  // Step 1: Free local checks
  const localResult = runLocalFilters(content);
  if (localResult.isDefinitelySpam) {
    return { action: 'block', cost: 0 };
  }

  // Step 2: Check cache (free)
  const cached = await getCachedResult(content);
  if (cached) {
    return { action: cached.action, cost: 0 };
  }

  // Step 3: Risk-based API call
  const riskScore = calculateRiskScore(content, localResult);

  if (riskScore < 0.2) {
    // Low risk: approve without API call
    return { action: 'approve', cost: 0 };
  }

  // Step 4: API call for uncertain content
  const apiResult = await checkModeration(content);
  return {
    action: determineAction(apiResult),
    cost: calculateApiCost(content)
  };
}

کنترل هم‌زمانی

نقطهٔ پایانی /api/v2/check در هر فراخوانی، یک ارسال را امتیازدهی می‌کند. برای «دسته‌بندی» کارها، آیتم‌ها را در ورکر خود گروه‌بندی کنید و به‌جای انتظار برای یک درخواست تکیِ چندآیتمی، آن‌ها را به‌صورت هم‌زمان و در قالب یک pool با ظرفیت محدود پخش کنید. بررسی‌ای که شامل چند URL رسانه‌ای باشد، خودش یک فراخوانی محسوب می‌شود و همهٔ آن‌ها را پوشش می‌دهد — یک فراخوانی سنگین از نظر تصویر، ارزان‌تر از چندین فراخوانی تک‌تصویری است.

// Bounded concurrency: many items, capped parallel calls.
async function processBatch(items, concurrency = 10) {
  const results = [];
  for (let i = 0; i < items.length; i += concurrency) {
    const slice = items.slice(i, i + concurrency);
    const settled = await Promise.allSettled(
      slice.map(item => checkModeration(item.content))
    );
    results.push(...settled);
  }
  return results;
}

یک درخواست تکی می‌تواند تا 10 URL تصویر، 5 URL GIF، 3 URL ویدئو، 5 URL سند و 20 لینک را به‌همراه متن تا سقف 10,000 نویسه در خود داشته باشد — بنابراین رسانه‌های یک ارسال را به‌جای تقسیم‌کردن، در یک فراخوانی واحد تجمیع کنید.

پایش و هشداردهی

داشبورد معیارهای کلیدی

const metrics = {
  // Volume metrics
  total_requests: new Counter('moderation_requests_total'),
  requests_per_second: new Gauge('moderation_rps'),

  // Latency metrics
  latency_p50: new Histogram('moderation_latency_p50'),
  latency_p99: new Histogram('moderation_latency_p99'),

  // Queue metrics
  queue_depth: new Gauge('moderation_queue_depth'),
  processing_time: new Histogram('moderation_processing_time'),

  // Cost metrics
  api_calls: new Counter('moderation_api_calls'),
  estimated_cost: new Counter('moderation_estimated_cost'),

  // Accuracy metrics
  violations_detected: new Counter('moderation_violations'),
  false_positives: new Counter('moderation_false_positives')
};

قوانین هشداردهی

# Alert on queue backup
- alert: ModerationQueueBackup
  expr: moderation_queue_depth > 10000
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: Moderation queue backing up

# Alert on high latency
- alert: ModerationLatencyHigh
  expr: moderation_latency_p99 > 5000
  for: 2m
  labels:
    severity: critical
  annotations:
    summary: Moderation latency exceeding 5 seconds

# Alert on high error rate
- alert: ModerationErrorRate
  expr: rate(moderation_errors_total[5m]) / rate(moderation_requests_total[5m]) > 0.01
  for: 5m
  labels:
    severity: critical
  annotations:
    summary: Moderation error rate above 1%

مقیاس‌پذیری زیرساخت

مقیاس‌پذیری افقی

# Kubernetes HPA for moderation workers
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: moderation-worker
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: moderation-worker
  minReplicas: 3
  maxReplicas: 50
  metrics:
  - type: External
    external:
      metric:
        name: queue_depth
      target:
        type: AverageValue
        averageValue: 100

کاهش تأخیر برای کاربران جهانی

Discuse API از طریق یک URL پایه واحد در دسترس است: https://api.discuse.com. برای پایین نگه‌داشتن تأخیر در ترافیک جهانی، workerهای مدیریت محتوای خودتان را نزدیک کاربران خود اجرا کنید و اجازه دهید آن‌ها API را فراخوانی کنند، به‌جای اینکه این فراخوانی را به‌صورت هم‌زمان از مسیر درخواستِ روبه‌روی کاربر در منطقه‌ای دور انجام دهید. این کار را با الگوهای مدیریت محتوای پس از انتشار به‌صورت ناهمگام و کش‌کردن که در بالا آمده‌اند ترکیب کنید تا یک رفت‌وبرگشت کند هرگز کاربر را معطل نکند.

خلاصهٔ بهترین روش‌ها

  1. با رویکردی تهاجمی کش کنید: محتوای یکسان، نتیجهٔ کش‌شده برمی‌گرداند. API همچنین محتوای یکسان را برای هر پروژه در یک بازهٔ زمانی کوتاه حذف تکراری می‌کند و cached: true را برمی‌گرداند.
  2. از صف‌ها استفاده کنید: پردازش ناهمگام برای حجم بالا.
  3. لایه‌بندی را پیاده‌سازی کنید: محلی → کش → API.
  4. همه‌چیز را پایش کنید: عمق صف، تأخیر، و میزان مصرف نسبت به سهمیه‌تان.
  5. برای خرابی برنامه داشته باشید: صف‌های نامهٔ مرده و جایگزین‌های امن.
  6. به‌صورت افقی مقیاس‌پذیر شوید: کارگرهای بیشتر، نه ماشین‌های بزرگ‌تر.
  7. هزینه را بهینه کنید: مسیریابی هوشمند، فراخوانی‌های تکراری کمتر، و رسانه‌های تجمیع‌شده در هر درخواست.

گام‌های بعدی

نوشته تیم Discuse · آخرین به‌روزرسانی June 2026

مقاله‌های مرتبط

راهنمای مدیریت محتوای AI

یادگیری ماشین چگونه به سامانه‌های مدرن مدیریت محتوا قدرت می‌دهد

پیکربندی آستانه‌های تشخیص

موارد مثبت و منفی کاذب را برای کاربرد خود متعادل کنید