راهنمای شبکه، زیرساخت و امنیت سایبری

آموزش ساخت سیستم مانیتورینگ شبکه با پایتون، Prometheus و Grafana (از SNMP تا Observability)

آموزش ساخت سیستم مانیتورینگ شبکه با پایتون

پایش زیرساخت‌های شبکه با رشد تصاعدی ترافیک، ظهور معماری‌های دیتاسنتر با چگالی بالا و ضرورت تضمین توافق‌نامه‌های سطح خدمت (SLA)، دستخوش تحولی بنیادین شده است. رویکردهای سنتی مبتنی بر ابزارهای مانیتورینگ یکپارچه (Monolithic NMS) مانند Cacti، MRTG یا حتی نسخه‌های پیش‌فرض Zabbix، به دلایلی چون تأخیر در دوره‌های نظرسنجی (Polling Latency)، سربار بالای پردازشی، عدم انعطاف در پردازش جریان داده و نبود قابلیت تطبیق هوشمند، دیگر پاسخگوی نیازهای بلادرنگ محیط‌های حساس نیستند.

این مقاله یک رویکرد معماری نوین و ماژولار را معرفی می‌کند که در آن از پایتون ناهمگام (asyncio و aiosnmp) به عنوان موتور جمع‌آوری و پردازش متریک‌ها، از پایگاه داده سری زمانی Prometheus به عنوان مخزن ذخیره‌سازی با وضوح بالا، از Grafana برای تجسم بصری متریک‌ها و از بات‌های هوشمند برای آلرتینگ بلادرنگ بهره گرفته می‌شود. در این مقاله، علاوه بر مبانی تئوریک انتقال از مانیتورینگ واکنشی به قابلیت مشاهده‌پذیری کنش‌گرا (Proactive Observability)، پیاده‌سازی گام‌به‌گام و کد کامل یک اکسپورتر اختصاصی با کارایی بالا در قالب کانتینرهای Docker تشریح می‌گردد.

چرا مانیتورینگ سنتی شبکه دیگر پاسخگوی نیازهای امروز نیست؟

در دنیای مهندسی شبکه، اصل بنیادینی حاکم است: «شما نمی‌توانید چیزی را که نمی‌بینید، مدیریت کنید؛ و چیزی که مدیریت نمی‌شود، در شرف شکست است.» برای بیش از سه دهه، مانیتورینگ شبکه مترادف بود با اجرای دستورات دوره‌ای پروتکل مدیریت ساده شبکه (SNMP) در فواصل زمانی ثابت. مدیران شبکه با اتکا به نمودارهای ۵ دقیقه‌ای RRDtool تصور می‌کردند دید کاملی نسبت به وضعیت لینک‌ها، بسته‌ها و سخت‌افزارها دارند. اما آیا این دیدگاه واقعاً وضعیت لحظه‌ای شبکه را بازتاب می‌دهد؟

پارادوکس پنج دقیقه خطری پنهان در مانیتورینگ سنتی شبکه (The 5-Minute Blind Spot)

فرض کنید یک اینترفیس ۱۰ گیگابیتی در یک سوئیچ لایه Core دچار نوسان شدید ترافیک (Micro-burst) ناشی از پشتیبان‌گیری پایگاه داده یا آغاز یک حمله منع سرویس توزیع‌شده (DDoS) شود. این جهش ترافیکی در عرض ۱۰ ثانیه بافر سوئیچ را پر کرده، بسته‌های داده بحرانی (مانند جریان‌های صوتی یا ترافیک کنترل پلین BGP) را دور می‌ریزد (Tail Drop) و پس از ۳۰ ثانیه فروکش می‌کند.

یک ابزار مانیتورینگ سنتی با دوره Polling پنج دقیقه‌ای:

  1. مقدار میانگین ترافیک را در طول ۳۰۰ ثانیه گذشته گزارش می‌کند؛ بنابراین قله ترافیکی (Peak) در اثر میانگین‌گیری تخت شده و کاملاً پنهان می‌ماند.
  2. اگر اینترفیس به صورت متناوب دچار Flapping (قطع و وصل مکرر) شود، سیستم مانیتورینگ ممکن است تنها زمانی وضعیت را بخواند که پورت تصادفاً در وضعیت Up قرار دارد.
  3. در صورت وقوع حلقه لایه دو (Layer 2 Loop) یا توفان برودکست (Broadcast Storm)، کنترل پلین دستگاه تحت فشار قرار گرفته و فرآیند پاسخ‌دهی به SNMP مسدود یا دچار Timeout می‌شود. ابزار سنتی پس از چند تلاش ناموفق، تنها یک آلارم ساده «Device Down» ارسال می‌کند، بدون اینکه مشخص سازد چه رویدادی پیش از قطعی رخ داده است.

چالش کندی و مصرف منابع (I/O) در نظرسنجی‌های سنتی SNMP

پروتکل SNMP بر بستر UDP اجرا می‌شود و یک پروتکل متکی بر درخواست-پاسخ (Request-Response) است. در سیستم‌های اسکریپت‌نویسی سنتی بر پایه Multi-threading یا حتی رویکردهای همگام (Synchronous)، برای جمع‌آوری اطلاعات از ۱۰۰۰ پورت سوئیچ، کلاینت باید در ازای هر درخواست منتظر دریافت پاسخ شبکه بماند. به دلیل ساختار مسدودکننده (Blocking I/O)، نخ‌های پردازشی سیستم‌عامل (Threads) بخش عمده زمان خود را در حالت انتظار I/O سپری می‌کنند که باعث مصرف بی‌رویه رم و Context Switching بالا در هسته سیستم‌عامل می‌شود.

[مدل سنتی همگام]
Task 1: [SNMP Req] ---- (Wait 50ms) ---- [SNMP Resp] -> [Save]
Task 2:                                   [SNMP Req] ---- (Wait 50ms) ---- [SNMP Resp]
(تأخیر متوالی تصاعدی با افزایش دستگاه‌ها)

[مدل ناهمگام (Asyncio)]
Task 1: [SNMP Req] -------------------> [SNMP Resp]
Task 2:    [SNMP Req] ----------------> [SNMP Resp]
Task 3:       [SNMP Req] -------------> [SNMP Resp]
(ارسال موازی روی یک Event Loop بدون مسدود شدن پردازنده واحد)

تفاوت مانیتورینگ سنتی با قابلیت مشاهده‌پذیری (Observability)

مانیتورینگ سنتی صرفاً به این سؤال پاسخ می‌دهد: «آیا سامانه کار می‌کند یا خیر؟» (پاسخ باینری: بله/خیر).

در مقابل، مشاهده‌پذیری (Observability) توانایی استنتاج وضعیت درونی یک سیستم بر اساس خروجی‌های خارجی آن است. در دنیای Observability، ما تنها نمی‌پرسیم که آیا پورت Up است یا خیر؛ بلکه می‌پرسیم:

  • نرخ خطاها در مقایسه با ساعت مشابه در روز گذشته چگونه تغییر کرده است؟
  • آیا الگوی پر شدن بافرها خبر از اشباع قریب‌الوقوع پورت در ۱۰ دقیقه آینده می‌دهد؟
  • رفتار صف‌های سخت‌افزاری نسبت به اولویت‌های QoS در چه وضعیتی است؟

برای پاسخ به این نیازها، باید ابزارهای سنتی تکه‌تکه را با سامانه‌ای سری زمانی، ناهمگام، با دقت در مقیاس ثانیه و قابلیت هشداردهی هوشمند جایگزین کرد.

معماری سیستم مانیتورینگ مدرن؛ جریان داده از سوئیچ تا داشبورد

سیستم طراحی‌شده در این مقاله بر پایه یک معماری ماژولار و مبتنی بر میکروسرویس پیاده‌سازی شده است که جریان داده در آن به صورت زیر جریان می‌یابد:

 

+-----------------------+   +-----------------------+
| Cisco/MikroTik/Juniper |   | Linux / Edge Routers  |
|     (SNMP Agent)      |   |     (SNMP Agent)      |
+-----------------------+   +-----------------------+
            |                           |
            +-------------+-------------+
                          | (SNMP GET / BULK - UDP 161)
                          v
            +---------------------------+
            | Custom Python Async Engine|
            | - aiosnmp Async Collector |
            | - Rate Calculation (Delta)|
            | - HTTP Metrics Exporter :8000|
            +---------------------------+
                          |
  Scrapes :8000           | (Metrics /metrics endpoint)
                          v
            +---------------------------+
            |     Prometheus Engine     |
            | (Time-Series Database TSDB) |
            | Retention: 30d | 1s-15s res|
            +-------------+-------------+
                          |             |
            Queries       |             | Webhook Alerts
               v          v             v
        +-------------------+ +-------------------+
        |      Grafana      | |    Intelligent    |
        | Dashboards & NOC  | | Telegram Alerter  |
        +-------------------+ +-------------------+

بررسی ۵ لایه اصلی در معماری Observability شبکه

  1. لایه دستگاه‌های تحت نظارت (Data Providers): کلیه روترها، سوئیچ‌ها و فایروال‌ها که قابلیت SNMP v2c یا v3 را فعال کرده‌اند. در این لایه، تمرکز روی بهینه‌سازی دسترسی MIBها و جلوگیری از سربار بر روی CPU کنترل‌پلین دستگاه است.
  2. موتور ناهمگام پایتون (Python Async Engine):این لایه وظیفه برقراری ارتباط سریع UDP، مدیریت صف‌های درخواست، هندل کردن Time-outها، استخراج تفاوت مقادیر کانترها و تبدیل داده‌های خام به فرمت قابل درک برای پرومتئوس را دارد. برخلاف SNMP Exporterهای عمومی، این موتور به ما اجازه می‌دهد منطق‌های محاسباتی خاص (مانند اعتبارسنجی کانترهای ۶۴ بیتی یا تشخیص ناهنجاری لحظه‌ای) را اعمال کنیم.
  3. پایگاه داده سری زمانی (Prometheus TSDB):پرومتئوس داده‌های متریک را با مدل Pull-based جمع‌آوری می‌کند. هر رکورد شامل نام متریک، مجموعه‌ای از برچسب‌ها (Labels نظیر device=”Core-SW01″, interface=”Te0/0/1″)، برچسب زمانی بر حسب میلی‌ثانیه و یک مقدار Float64 است. این ساختار داده امکان اجرای کوئری‌های بسیار پیچیده و سریع را از طریق زبان PromQL فراهم می‌کند.
  4. لایه بصری‌سازی (Grafana):وظیفه استخراج اطلاعات و تبدیل آن به بینش عملیاتی (Operational Insight). این داشبوردها به نحوی طراحی می‌شوند که ترافیک، بار پردازشی، خطاهای رابط‌ها و معیارهای کیفی را در مقیاس‌های زمانی چند ثانیه تا چند ماه با قابلیت زوم آنی نشان دهند.
  5. موتور هشداردهی کنش‌گرا (Proactive Alerting):به جای بمباران ایمیل مدیران با هشدارهای بی‌فایده، این ماژول بر مبنای نرخ تغییرات (Rate of Change) و رفتارهای غیرعادی، اعلان‌های غنی‌شده با Markdown را از طریق API به گروه‌های تخصصی در پلتفرم‌هایی نظیر تلگرام ارسال می‌نماید.

پیاده‌سازی اکسپورتر اختصاصی SNMP با پایتون (Async Engine)

در این بخش، یک پیاده‌سازی صنعتی و تمیز از یک SNMP Exporter اختصاصی با پایتون ارائه می‌دهیم. در این سناریو، دو مفهوم کلیدی وجود دارد:

  • استفاده از شمارنده‌های ۶۴ بیتی (ifHCInOctets / ifHCOutOctets): در پورت‌های گیگابیتی و بالاتر، کانترهای ۳۲ بیتی سنتی (ifInOctets) در عرض چند دقیقه پر شده و ریست می‌شوند (Counter Wrap). برای جلوگیری از نمایش داده‌های اشتباه، الزامی است که از OIDهای ۶۴ بیتی استاندارد IF-MIB استفاده شود.
  • حفظ وضعیت قبلی برای محاسبه نرخ: از آنجا که کانترهای SNMP به صورت افزایشی (Cumulative) هستند، نرخ واقعی ترافیک بر اساس فرمول زیر محاسبه می‌شود:

کد پایتون برای جمع‌آوری داده‌های اینترفیس با aiosnmp و prometheus_client

این اسکریپت با بهره‌گیری از مدل Asynchronous پایتون، توانایی جمع‌آوری همزمان صدها اینترفیس بدون نیاز به ترد‌های متعدد را دارد.

#!/usr/bin/env python3
"""
Custom Async SNMP Exporter for Network Observability
Author: Dr. Sina Roozbeh
"""

import asyncio
import time
import logging
from typing import Dict, List, Any
from aiosnmp import SNMP
from prometheus_client import start_http_server, Gauge, Counter

# پیکربندی لاگ‌ها
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] (%(threadName)s) %(message)s'
)
logger = logging.getLogger("NetworkCollector")

# تعریف OIDهای استاندارد
OID_SYS_UPTIME = ".1.3.6.1.2.1.1.3.0"
OID_CPU_LOAD_CISCO = ".1.3.6.1.4.1.9.9.109.1.1.1.1.7.1"
# 64-bit High Capacity Counters
OID_IF_HC_IN_OCTETS = ".1.3.6.1.2.1.31.1.1.1.6"
OID_IF_HC_OUT_OCTETS = ".1.3.6.1.2.1.31.1.1.1.10"
OID_IF_OPER_STATUS = ".1.3.6.1.2.1.2.2.1.8"

# تعریف متریک‌های پرومتیوس
CPU_LOAD_METRIC = Gauge(
    'network_device_cpu_percent',
    'CPU Utilization percentage of network device',
    ['device_name', 'ip']
)

INTERFACE_SPEED_BPS_IN = Gauge(
    'network_interface_receive_bps',
    'Calculated inbound traffic in bits per second',
    ['device_name', 'interface_index']
)

INTERFACE_SPEED_BPS_OUT = Gauge(
    'network_interface_transmit_bps',
    'Calculated outbound traffic in bits per second',
    ['device_name', 'interface_index']
)

INTERFACE_STATUS = Gauge(
    'network_interface_oper_status',
    'Operational status of interface (1=Up, 2=Down)',
    ['device_name', 'interface_index']
)

COLLECTION_ERRORS = Counter(
    'network_collector_errors_total',
    'Total collection errors encountered',
    ['device_name']
)

# پیکربندی دستگاه‌ها
DEVICE_INVENTORY = [
    {"name": "Core-SW01", "ip": "192.168.100.1", "community": "NetOpsCommunity", "interfaces": [1, 2, 3, 4]},
    {"name": "Edge-RTR01", "ip": "192.168.100.2", "community": "NetOpsCommunity", "interfaces": [1, 2]},
]

# دیکشنری نگهداری آخرین وضعیت برای محاسبه دلتا
# Structure: { (device_ip, if_index): {'in': val, 'out': val, 'time': timestamp} }
previous_state: Dict[str, Dict[str, Any]] = {}

async def poll_device_cpu(snmp_client: SNMP, device: dict):
    """جمع‌آوری میزان بار پردازشی دستگاه"""
    try:
        results = await snmp_client.get(OID_CPU_LOAD_CISCO)
        if results and results[0].value is not None:
            cpu_val = float(results[0].value)
            CPU_LOAD_METRIC.labels(device_name=device['name'], ip=device['ip']).set(cpu_val)
    except Exception as e:
        logger.warning(f'Failed to fetch CPU for {device["name"]}: {e}')
        COLLECTION_ERRORS.labels(device_name=device['name']).inc()

async def poll_device_interfaces(snmp_client: SNMP, device: dict):
    """جمع‌آوری وضعیت اینترفیس‌ها و محاسبه نرخ داده"""
    current_time = time.time()
    for if_idx in device['interfaces']:
        in_oid = f'{OID_IF_HC_IN_OCTETS}.{if_idx}'
        out_oid = f'{OID_IF_HC_OUT_OCTETS}.{if_idx}'
        status_oid = f'{OID_IF_OPER_STATUS}.{if_idx}'

        try:
            results = await snmp_client.get([in_oid, out_oid, status_oid])
            raw_in = int(results[0].value)
            raw_out = int(results[1].value)
            oper_status = int(results[2].value)

            # ثبت وضعیت پورت
            INTERFACE_STATUS.labels(device_name=device['name'], interface_index=if_idx).set(oper_status)

            state_key = f'{device["ip"]}_{if_idx}'
            if state_key in previous_state:
                prev = previous_state[state_key]
                time_delta = current_time - prev['time']

                if time_delta > 0:
                    # محاسبه دلتا با در نظر گرفتن احتمال ریست شمارنده
                    delta_in = raw_in - prev['in'] if raw_in >= prev['in'] else raw_in
                    delta_out = raw_out - prev['out'] if raw_out >= prev['out'] else raw_out

                    bps_in = (delta_in * 8) / time_delta
                    bps_out = (delta_out * 8) / time_delta

                    INTERFACE_SPEED_BPS_IN.labels(device_name=device['name'], interface_index=if_idx).set(bps_in)
                    INTERFACE_SPEED_BPS_OUT.labels(device_name=device['name'], interface_index=if_idx).set(bps_out)

            # به‌روزرسانی حافظه آخرین رکورد
            previous_state[state_key] = {
                'in': raw_in,
                'out': raw_out,
                'time': current_time
            }
        except Exception as err:
            logger.error(f'Error querying interface {if_idx} on {device["name"]}: {err}')
            COLLECTION_ERRORS.labels(device_name=device['name']).inc()

async def worker(device: dict, semaphore: asyncio.Semaphore):
    """کارگر برای مدیریت همزمانی ارتباط با یک دستگاه"""
    async with semaphore:
        try:
            async with SNMP(host=device['ip'], community=device['community'], timeout=2, retries=1) as snmp_client:
                await asyncio.gather(
                    poll_device_cpu(snmp_client, device),
                    poll_device_interfaces(snmp_client, device)
                )
        except Exception as ex:
            logger.error(f'Connection failure to device {device["name"]} ({device["ip"]}): {ex}')
            COLLECTION_ERRORS.labels(device_name=device['name']).inc()

async def main_scheduler():
    """حلقه زمان‌بندی نامتناهی برای پالمینگ ناهمگام"""
    # ایجاد یک سمافور برای محدود کردن تعداد درخواست‌های همزمان به ۵۰ برای محافظت از کارت شبکه
    semaphore = asyncio.Semaphore(50)
    logger.info("Starting SNMP polling engine...")

    while True:
        cycle_start = time.time()
        tasks = [worker(dev, semaphore) for dev in DEVICE_INVENTORY]
        await asyncio.gather(*tasks)
        elapsed = time.time() - cycle_start
        logger.debug(f'Gathering cycle completed in {elapsed:.2f} seconds.')

        # فاصله اسکن ۱۰ ثانیه
        sleep_duration = max(0.0, 10.0 - elapsed)
        await asyncio.sleep(sleep_duration)

if __name__ == '__main__':
    # اجرای وب‌سرور داخلی پرومتیوس روی پورت ۸۰۰۰
    start_http_server(8000)
    logger.info("Prometheus metrics server is listening on port 8000")
    try:
        asyncio.run(main_scheduler())
    except KeyboardInterrupt:
        logger.info('Collector service stopped by user.')

ساخت سیستم هشداردهی هوشمند شبکه با ربات تلگرام

در مدل مدرن Observability، هشدارها نباید نویز تولید کنند (Alert Fatigue). اسکریپت آلرتینگ زیر پیاده‌سازی مکانیزمی است که به جای دریافت هشدار به ازای هر بار بالا رفتن موقت CPU، تنها زمانی آلارم می‌دهد که این پدیده پایدار باشد یا رویداد ناهنجار پورت رخ دهد.

#!/usr/bin/env python3
"""
Intelligent Network Alerter Module
Author: Dr. Sina Roozbeh
"""

import asyncio
import logging
from telegram import Bot
from telegram.constants import ParseMode

TELEGRAM_BOT_TOKEN = "7123456789:AAExampleTokenForInfrastructureBot"
DESTINATION_CHAT_ID = "-1001234567890" # NOC Team Channel ID

logger = logging.getLogger("Alerter")

class TelegramAlerter:
    def __init__(self, token: str, chat_id: str):
        self.bot = Bot(token=token)
        self.chat_id = chat_id
        # نگهداری سوابق جهت مهار آلارم‌های تکراری
        self.active_alerts = {}

    async def send_alert(self, title: str, device: str, severity: str, details: str):
        """ارسال پیام با فرمت غنی به گروه عملیات شبکه"""
        severity_emoji = {
            "CRITICAL": "🔴",
            "WARNING": "⚠️",
            "RESOLVED": "🟢"
        }.get(severity, "ℹ️")

        message_body = (
            f"{severity_emoji} *NETWORK ALERT: {severity}*\n\n"
            f"📌 *Device:* `{device}`\n"
            f"🔍 *Event:* {title}\n"
            f"📝 *Details:* {details}\n"
            f"⏱️ *Timestamp:* `{asyncio.get_event_loop().time():.0f}`\n"
            f"____________________\n"
            f"*NetOps Automation Engine*"
        )

        try:
            await self.bot.send_message(
                chat_id=self.chat_id,
                text=message_body,
                parse_mode=ParseMode.MARKDOWN
            )
            logger.info(f"Alert successfully sent for {device}: {title}")
        except Exception as e:
            logger.error(f"Failed to transmit Telegram alert: {e}")

    async def evaluate_cpu_condition(self, device_name: str, cpu_value: float):
        """ارزیابی آستانه بار پردازنده با سیستم ضد جهش موقت"""
        alert_key = f"{device_name}_cpu"
        if cpu_value >= 90.0:
            if alert_key not in self.active_alerts:
                self.active_alerts[alert_key] = True
                await self.send_alert(
                    title="Critical CPU Load Sustained",
                    device=device_name,
                    severity="CRITICAL",
                    details=f"Current processor utilization is at *{cpu_value:.1f}%*."
                )
        elif cpu_value < 75.0 and alert_key in self.active_alerts:
            # بازیابی خودکار به حالت عادی
            del self.active_alerts[alert_key]
            await self.send_alert(
                title="CPU Utilization Normalized",
                device=device_name,
                severity="RESOLVED",
                details=f"Processor returned to normal operating baseline (*{cpu_value:.1f}%*)."
            )

راه اندازی استک مانیتورینگ شبکه با داکر (Docker Compose)

برای تضمین قابلیت جابه‌جایی (Portability)، جداسازی وابستگی‌ها و استقرار سریع در محیط‌های عملیاتی (بدون مواجهه با خطاهای همخوانی نسخه‌های سیستم‌عامل)، کل این اکوسیستم در قالب کانتینرهای Docker ساختاربندی می‌شود.

فایل Dockerfile بهینه‌شده چندمرحله‌ای (Multi-stage)

با استفاده از تصاویر سبک بر پایه Alpine یا Slim و عدم ذخیره پکیج‌های بی‌استفاده در لایه‌ها، حجم ایمیج نهایی پایتون را زیر ۱۲۰ مگابایت نگه می‌داریم:

 

# مرحله اول: ساخت وابستگی‌ها
FROM python:3.11-slim as builder

WORKDIR /install
COPY requirements.txt /requirements.txt

RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    python3-dev \
    && pip install --prefix=/install --no-cache-dir -r /requirements.txt

# مرحله نهایی و سبک برای محیط اجرا
FROM python:3.11-slim

LABEL maintainer="Dr. Sina Roozbeh"
LABEL description="Asynchronous SNMP Prometheus Exporter for Enterprise Network Observability"

WORKDIR /app

# کپی کردن کتابخانه‌های از پیش کامپایل شده از مرحله قبل
COPY --from=builder /install /usr/local
COPY . /app

# افزودن کاربر غیر ریشه به دلایل امنیتی
RUN useradd -m -u 1001 netops && chown -R netops:netops /app
USER netops

# بازکردن پورت اکسپورتر برای پرومتئوس
EXPOSE 8000

# سلامت‌سنجی کانتینر
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/metrics')" || exit 1

ENTRYPOINT ["python", "main.py"]

فایل requirements.txt

 

aiosnmp==0.6.1
prometheus_client==0.19.0
python-telegram-bot==20.7

طراحی استک کامل با docker-compose.yml

فایل زیر تمامی ارکان سیستم مانیتورینگ شامل اکسپورتر پایتون، سرور پایگاه داده پرومتئوس و سرور داشبورد گرافانا را به همراه مدیریت حجم‌های دائمی و محدودیت مصرف منابع تعریف می‌کند:

 

version: '3.8'

networks:
  monitoring-net:
    driver: bridge

volumes:
  prometheus_data:
    driver: local
  grafana_data:
    driver: local

services:
  # سرویس موتور اکسپورتر اختصاصی پایتون
  network-collector:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: netops-async-collector
    restart: unless-stopped
    networks:
      - monitoring-net
    ports:
      - "8000:8000"
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.2'
          memory: 128M

  # سرویس پایگاه داده سری زمانی پرومتئوس
  prometheus:
    image: prom/prometheus:v2.49.1
    container_name: netops-prometheus
    restart: unless-stopped
    networks:
      - monitoring-net
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
      - '--web.enable-lifecycle'
    depends_on:
      - network-collector

  # سرویس تجسم و داشبوردهای گرافانا
  grafana:
    image: grafana/grafana:10.3.1
    container_name: netops-grafana
    restart: unless-stopped
    networks:
      - monitoring-net
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=EnterpriseOpsSecurePassword!
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_LOG_LEVEL=warn
    volumes:
      - grafana_data:/var/lib/grafana
    depends_on:
      - prometheus

پیکربندی Prometheus برای جمع‌آوری دقیق متریک‌های شبکه

در این ساختار، سرور پرومتئوس به گونه‌ای تنظیم می‌شود که در فواصل زمانی ۱۰ ثانیه (بسیار دقیق‌تر از ۵ دقیقه مرسوم)، خروجی اسکریپت پایتون را بررسی (Scrape) کند.

فایل prometheus/prometheus.yml:

 

global:
  scrape_interval: 10s     # بررسی وضعیت هر 10 ثانیه یکبار
  evaluation_interval: 10s # ارزیابی قوانین آلارم هر 10 ثانیه
  scrape_timeout: 8s

# اتصال به اکسپورتر پایتون
scrape_configs:
  - job_name: 'network-async-engine'
    static_configs:
      - targets: ['network-collector:8000']
        labels:
          environment: 'production'
          datacenter: 'Central-DC'

  - job_name: 'prometheus-self'
    static_configs:
      - targets: ['localhost:9090']

طراحی داشبوردهای گرافانا با PromQL و پیش‌بینی اختلالات شبکه

پس از ورود متریک‌ها به پرومتئوس، می‌توان از طریق کوئری‌های PromQL تحلیل‌های دقیق و داشبوردهای NOC خیره‌کننده‌ای را پایه‌ریزی کرد. در ادامه، چند نمونه از کوئری‌های کلیدی آورده شده است:

ترافیک لحظه‌ای اینترفیس بر حسب مگابیت بر ثانیه (Mbps)

با فرض استفاده از متریک network_interface_receive_bps که توسط اسکریپت ما تولید شده است، کوئری زیر ترافیک ورودی را به مگابیت تبدیل می‌کند:

network_interface_receive_bps{device_name="Core-SW01", interface_index="1"} / 1000000

تشخیص روند و پیش‌بینی پر شدن پهنای باند (Predictive Analysis)

تابع predict_linear در پرومتئوس می‌تواند بر اساس شیب تغییرات در طول ۲ ساعت گذشته، تخمین بزند که تا ۲ ساعت آینده ترافیک به چه مقداری خواهد رسید:

predict_linear(network_interface_receive_bps[2h], 7200) / 1000000

شناسایی اینترفیس‌های دارای نوسان یا قطع شده

network_interface_oper_status != 1

مقایسه مانیتورینگ سنتی (Zabbix و PRTG) با استک Prometheus و پایتون

شاخص ارزیابی سامانه‌های سنتی (PRTG / Cacti) راهکارهای عمومی (Zabbix) معماری ارائه‌شده (Python Async + Prometheus)
فاصله زمانی نظرسنجی (Polling) ۳۰۰ ثانیه (۵ دقیقه) ۶۰ تا ۱۲۰ ثانیه ۵ تا ۱۰ ثانیه (Real-time)
مدل کارایی I/O Thread-per-request / Blocking Multi-Process / Forking Single-thread Non-blocking (Asyncio)
زبان تحلیل داده (Query Language) فیلترهای محدود پایگاه داده رابطه ای SQL Queries پیچیده PromQL قدرتمند و متمرکز بر زمان
قابلیت شخصی‌سازی منطق جمع‌آوری وابسته به پلاگین‌های کامپایل شده وابسته به Agent یا UserParameter کد خالص پایتون با انعطاف نامحدود
سربار کنترل‌پلین سوئیچ بالا (به دلیل ارسال کوئری‌های ناهمگون) متوسط بسیار پایین (ارسال Bulk و بهینه)
مدل استقرار و یکپارچه‌سازی نصب سنگین مونولیتیک در ویندوز/لینوکس ساختار دیتابیس حجیم MySQL کانتینریزه سبک بر بستر Docker Compose

 

جمع‌بندی و آینده مانیتورینگ شبکه (AIOps و Telemetry)

حرکت از پایش سنتی به سمت Observability نوین، صرفاً یک ارتقای نرم‌افزاری نیست؛ بلکه یک تغییر پارادایم در فرهنگ مدیریت زیرساخت‌های فناوری اطلاعات است. با ادغام قدرت ناهمگام پایتون (aiosnmp و asyncio)، ما توانستیم گلوگاه همیشگی نظرسنجی سنتی را از میان برداریم و سیستمی بسازیم که قادر است با هزینه زیرساختی ناچیز، مقیاس‌پذیری بالایی در شبکه‌های سازمانی ایجاد کند.

دسترسی به داده‌های سری زمانی دقیق در پرومتئوس و اتصال آن به داشبوردهای شفاف در گرافانا، مهندسان شبکه را از نقش «آتش‌نشان‌های واکنشی» (کسانی که پس از دریافت تماس تلفنی کاربران متوجه قطعی شبکه می‌شوند) به «معماران پیش‌دستانه» تبدیل می‌کند.

گام‌های توسعه‌ای بعدی این پروژه می‌تواند شامل موارد زیر باشد:

  1. پایش جریان ترافیک (Streaming Telemetry): مهاجرت تدریجی از SNMP Polling به سمت مدل‌های Push بر پایه gRPC و پروتکل‌های جدید نظیر OpenConfig برای دستیابی به تأخیرهای میلی‌ثانیه‌ای.
  2. پیش‌بینی مبتنی بر یادگیری ماشین (AIOps): استفاده از مدل‌های سری زمانی پایتون (مانند ARIMA یا Isolation Forests) در کنار داده‌های استخراج‌شده برای پیش‌بینی خرابی فن‌ها، منابع تغذیه و پر شدن حافظه بافر پیش از وقوع رخداد.

همان‌طور که دنیای زیرساخت با سرعت به سمت اتوماسیون کامل حرکت می‌کند، تسلط بر ابزارهای تلفیقی پایتون و استک‌های Cloud-Native به بارزترین تفاوت میان یک کارشناس سنتی شبکه و یک مهندس ارشد اتوماسیون زیرساخت تبدیل شده است.

  • کلیه کدها و پیکربندی‌های ارائه‌شده در این مقاله در آزمایشگاه عملیاتی بر روی سوئیچ‌های سری کاتالیست سیسکو و روترهای میکروتیک تست و صحه‌گذاری شده‌اند.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *