راه‌اندازی Observability با LGTM و Pyroscope، بخش ۳: متریک‌ها با Mimir و داشبورد در Grafana

در بخش دوم اپلیکیشن Django را با روش GitOps مستقر کردیم. حالا اولین سیگنال از سیگنال‌های Observability را اضافه می‌کنیم: متریک‌ها. متریک‌ها داده‌های عددی و سری‌زمانی هستند؛ مانند تعداد درخواست‌ها در ثانیه، نرخ خطا و تأخیر پاسخ‌دهی.

مسیر داده در این بخش چهار حلقه دارد: اپلیکیشن متریک‌ها را نمایان می‌کند، یک جمع‌کننده آن‌ها را برمی‌دارد، یک پایگاه ذخیره‌سازی نگه‌شان می‌دارد، و در نهایت Grafana آن‌ها را رسم می‌کند:

  • Django با کتابخانه‌ی django-prometheus متریک‌ها را روی مسیر /metrics نمایان می‌کند.
  • Grafana Alloy نقش جمع‌کننده (collector) را دارد و متریک‌ها را از pod ها می‌خواند.
  • Mimir پایگاه ذخیره‌سازی متریک‌ها و سازگار با Prometheus است.
  • Grafana داده‌ها را از Mimir می‌خواند و در داشبورد نمایش می‌دهد.

همه‌ی این اجزا نیز مانند اپلیکیشن، به‌شکل مانیفست در همان مخزن قرار می‌گیرند و Argo CD آن‌ها را روی cluster مستقر می‌کند.

نمایان‌کردن متریک‌ها در Django

ابتدا کتابخانه‌ی django-prometheus را به اپلیکیشن اضافه می‌کنیم. این کتابخانه با دو middleware، متریک‌های درخواست و پاسخ را جمع می‌کند و یک مسیر /metrics در اختیار می‌گذارد. در فایل settings.py:

INSTALLED_APPS = [
    "django_prometheus",
    # ...
]

MIDDLEWARE = [
    "django_prometheus.middleware.PrometheusBeforeMiddleware",
    # ... other middleware ...
    "django_prometheus.middleware.PrometheusAfterMiddleware",
]

و در فایل urls.py مسیر متریک‌ها را اضافه می‌کنیم:

urlpatterns = [
    path("", include("django_prometheus.urls")),
    # ... other routes ...
]

پس از استقرار نسخه‌ی جدید، خروجی /metrics شامل شمارنده‌هایی مانند تعداد درخواست‌ها و پاسخ‌هاست. این خروجی خام را Alloy می‌خواند و به Mimir می‌فرستد؛ سپس می‌توانیم همان داده را از Mimir بازخوانی کنیم:

خروجی متریک‌های Django و بازخوانی همان داده از Mimir
در بالا، شمارنده‌های خام Django روی /metrics؛ سپس همان متریک پس از عبور از Alloy، با یک پرس‌وجوی PromQL از Mimir بازخوانی می‌شود.

جمع‌آوری با Grafana Alloy

Alloy جمع‌کننده‌ی واحدی است که در ادامه‌ی مجموعه برای لاگ و ردیابی هم از آن استفاده می‌کنیم. پیکربندی آن روشن و خوانا است: ابتدا pod ها را کشف می‌کند، سپس فقط pod های اپلیکیشن را نگه می‌دارد، از آن‌ها متریک می‌خواند و به Mimir می‌فرستد:

discovery.kubernetes "pods" {
  role = "pod"
}

prometheus.scrape "guestbook" {
  targets         = discovery.relabel.guestbook.output
  forward_to      = [prometheus.remote_write.mimir.receiver]
  metrics_path    = "/metrics"
  scrape_interval = "15s"
}

prometheus.remote_write "mimir" {
  endpoint {
    url = "http://mimir.observability.svc:8080/api/v1/push"
  }
}

رابط کاربری Alloy این زنجیره را به‌شکل یک نمودار نشان می‌دهد و سلامت هر جزء را مشخص می‌کند:

نمودار اجزای Alloy: کشف، انتخاب، خواندن و ارسال متریک‌ها
نمودار Alloy: از کشف pod ها (discovery.kubernetes) و انتخاب pod های هدف (discovery.relabel) تا خواندن متریک‌ها (prometheus.scrape) و ارسال به Mimir (prometheus.remote_write). همه در وضعیت Healthy هستند.

داشبورد به‌شکل کد و روش RED

برای اینکه داشبورد قابل بازتولید و نسخه‌پذیر باشد، به‌جای ساختن دستی، آن را به‌شکل یک فایل JSON در Git نگه می‌داریم و از طریق provisioning به Grafana می‌دهیم. برای طراحی داشبورد از روش RED استفاده می‌کنیم که سه پرسش کلیدی درباره‌ی هر سرویس را پاسخ می‌دهد:

  • Rate (نرخ): چند درخواست در ثانیه دریافت می‌شود؟
  • Errors (خطاها): چه تعداد از پاسخ‌ها با خطا همراه‌اند؟
  • Duration (تأخیر): پاسخ‌دهی چه‌قدر طول می‌کشد؟

هر پنل با یک پرس‌وجوی PromQL روی متریک‌های Django ساخته می‌شود؛ برای نمونه، نرخ درخواست و صدک ۹۵ تأخیر:

sum(rate(django_http_requests_total_by_method_total[5m]))

histogram_quantile(0.95,
  sum(rate(django_http_requests_latency_seconds_by_view_method_bucket[5m])) by (le))

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

داشبورد RED در Grafana با داده‌ی واقعی
داشبورد RED در Grafana: نرخ درخواست، نرخ خطای 5xx (اینجا صفر)، تأخیر (صدک ۵۰ و ۹۵) و تعداد کل درخواست‌ها. داده‌ها از Mimir خوانده می‌شوند.

جمع‌بندی و بخش بعد

در این بخش زنجیره‌ی کامل متریک را ساختیم: نمایان‌کردن متریک در Django، جمع‌آوری با Alloy، ذخیره در Mimir و نمایش در یک داشبورد RED که به‌شکل کد نگه‌داری می‌شود. متریک‌ها به ما می‌گویند «چه‌قدر» و «چه زمانی» مشکلی رخ داده است.

در بخش بعد سیگنال دوم را اضافه می‌کنیم: لاگ‌ها را با Loki جمع‌آوری می‌کنیم تا بفهمیم «چرا» یک مشکل رخ داده است.

بخش‌های این مجموعه

← بازگشت به وبلاگ