MONITORING

هشداردهی اصولی: چهار سیگنال طلایی، SLO و طراحی Alert خوب

کدام متریک‌ها را مانیتور کنیم؟ چهار سیگنال طلایی، روش‌های RED و USE، تعریف SLI و SLO، error budget و قواعد طراحی هشدارهایی که شبانه بیدارتان نمی‌کنند.

اگر هر شب چند هشدار می‌گیرید که نیازی به اقدام ندارند، خیلی زود هشدارها را نادیده می‌گیرید؛ و آن شبی که هشدار واقعی بیاید، همان بی‌توجهی مشکل‌ساز می‌شود. این پدیده «خستگی از هشدار» (alert fatigue) است و راه حل آن طراحی هشدار، نه اضافه‌کردن ابزار است. این راهنما می‌گوید چه چیزی را مانیتور کنید (چهار سیگنال طلایی)، چه زمانی هشدار بدهید (علامت‌ها نه علت‌ها)، و چگونه با SLO و error budget هشدارهایی بنویسید که واقعاً ارزش بیدارکردن کسی را دارند.

چهار سیگنال طلایی

کتاب SRE گوگل چهار معیار را برای هر سرویس کاربرمحور پیشنهاد می‌کند. اگر فقط چهار چیز را مانیتور کنید، همین‌ها باشد:

سیگنالپرسشمثال متریک
Latency (تأخیر)پاسخ‌دادن چقدر طول می‌کشد؟ (موفق و ناموفق جدا)histogram_quantile(0.95, …)
Traffic (ترافیک)چقدر درخواست می‌رسد؟rate(http_requests_total[5m])
Errors (خطا)چه درصدی شکست می‌خورد؟rate(…{status=~"5.."}) / rate(…)
Saturation (اشباع)سیستم چقدر به سقف ظرفیت نزدیک است؟دیسک، حافظه، طول صف، pool اتصال

RED و USE: دو قالب ساده‌تر

  • RED (برای سرویس‌ها): Rate، Errors، Duration؛ همان سه سیگنال اول.
  • USE (برای منابع مثل CPU، دیسک، شبکه): Utilization، Saturation، Errors.

با این دو قالب می‌توانید برای هر مؤلفه‌ی جدید، بدون فکر زیاد، فهرست متریک‌های ضروری را بسازید. نحوه‌ی نوشتن کوئری‌های آن‌ها در راهنمای PromQL آمده است.

هشدار روی علامت، نه علت

یک اصل ساده، اغلب فرق هشدار خوب و بد را می‌سازد: برای چیزی که کاربر حس می‌کند هشدار (page) بدهید، نه برای چیزی که ممکن است باعث آن شود.

علامت (هشدار بدهید)علت احتمالی (داشبورد/تیکت)
درصد خطای ۵xx بالاCPU بالا، حافظه کم، ری‌استارت پادها
تأخیر p95 از هدف بیشتر شدکندی دیتابیس، پر بودن صف
سرویس در دسترس نیست (up == 0)کرش، OOM، قطع شبکه
دیسک تا ۴ ساعت دیگر پر می‌شودرشد لاگ یا داده

مصرف CPU یا حافظه‌ی بالا، اگر کاربر را متأثر نکند، مشکل نیست. هشدار روی علت یعنی صدها هشدار که فقط بعضی‌شان به مشکل واقعی می‌رسند. استثنا، اشباع‌هایی است که قطعی را حتمی کرده‌اند (دیسک در حال پر شدن، گواهی در حال انقضا) و علامت هنوز ظاهر نشده است.

SLI، SLO و error budget

  • SLI (شاخص): یک اندازه‌گیری، مثل «نسبت درخواست‌های موفق به کل» یا «نسبت درخواست‌های سریع‌تر از ۳۰۰ms».
  • SLO (هدف): مقدار هدف آن شاخص در یک بازه، مثل «۹۹٫۹٪ درخواست‌ها در ۳۰ روز موفق باشند».
  • Error budget (بودجه‌ی خطا): تفاوت ۱۰۰٪ و SLO؛ مقدار خطایی که مجاز است.

بودجه‌ی خطا برای یک بازه‌ی ۳۰روزه:

SLOخطای مجازمعادل قطعی در ۳۰ روز
99%1%≈ 7.2 ساعت
99.9%0.1%≈ 43.2 دقیقه
99.95%0.05%≈ 21.6 دقیقه
99.99%0.01%≈ 4.3 دقیقه

SLO را بر اساس نیاز واقعی کاربر انتخاب کنید، نه بالاترین عدد ممکن: هر «نُه» اضافه هزینه‌ی مهندسی را چند برابر می‌کند. وقتی بودجه باقی است، تیم می‌تواند ریسک کند و ویژگی تازه منتشر کند؛ وقتی تمام شد، تمرکز به پایداری برمی‌گردد.

هشدار بر پایه‌ی نرخ مصرف بودجه (burn rate)

هشدار «درصد خطا از ۰٫۱٪ بیشتر شد» دو مشکل دارد: برای یک اوج کوتاه بی‌اهمیت هم هشدار می‌دهد و برای یک خطای کوچک ولی طولانی هیچ‌وقت. روش بهتر، burn rate است: بودجه با چه سرعتی نسبت به حالت عادی مصرف می‌شود. burn rate برابر ۱ یعنی بودجه دقیقاً در پایان بازه تمام می‌شود، و ۱۴٫۴ یعنی در یک ساعت ۲٪ از بودجه‌ی ماهانه مصرف می‌شود.

الگوی توصیه‌شده در کتاب SRE Workbook گوگل، ترکیب چند پنجره است: یک پنجره‌ی بلند برای اطمینان از جدی‌بودن، و یک پنجره‌ی کوتاه برای اینکه هشدار بعد از برطرف‌شدن مشکل خاموش شود:

واکنشburn rateپنجره‌ی بلندپنجره‌ی کوتاه
Page (فوری)14.41h5m
Page66h30m
Ticket (غیرفوری)13d6h

نمونه‌ی قاعده‌ی Prometheus برای SLO برابر ۹۹٫۹٪ (بودجه ۰٫۰۰۱):

groups:
  - name: slo-api
    rules:
      - alert: ErrorBudgetBurnFast
        expr: |
          (
            sum(rate(http_requests_total{job="api",status=~"5.."}[1h]))
              / sum(rate(http_requests_total{job="api"}[1h])) > (14.4 * 0.001)
          )
          and
          (
            sum(rate(http_requests_total{job="api",status=~"5.."}[5m]))
              / sum(rate(http_requests_total{job="api"}[5m])) > (14.4 * 0.001)
          )
        labels:
          severity: page
        annotations:
          summary: "API is burning error budget 14x faster than allowed"
          runbook_url: "https://wiki.example.com/runbooks/api-errors"
YAMLYAML Validatorنحو فایل قواعد هشدار را پیش از بارگذاری در Prometheus بررسی کنید.

برای سرویس‌های پرترافیک، محاسبه‌ی نسبت‌ها با recording rule‌ها (مثلاً job:http_error_ratio:rate5m) هم کوئری‌ها را سبک می‌کند و هم خوانایی قواعد را بالا می‌برد.

ویژگی‌های یک هشدار خوب

  1. قابل‌اقدام: کسی که هشدار را می‌گیرد باید بداند چه کاری انجام دهد. اگر پاسخ «هیچ» است، آن هشدار نباید وجود داشته باشد.
  2. فوری: فقط چیزهایی که باید همین الان رسیدگی شوند بیدارکننده باشند. بقیه تیکت یا اعلان کاری در ساعت اداری.
  3. قابل‌فهم: عنوان بگوید چه خراب است و روی کدام سرویس؛ و لینک runbook (قدم‌های بررسی و رفع) و داشبورد مرتبط داشته باشد.
  4. بدون نوسان: از for استفاده کنید تا فقط مشکل پایدار هشدار بدهد.
  5. غیرتکراری: یک مشکل یک هشدار؛ نه ده‌ها هشدار هم‌زمان برای یک علت.
  6. آزمایش‌شده: هشدار را حداقل یک‌بار عمداً فعال کنید تا مطمئن شوید به مقصد می‌رسد.
annotations:
  summary: "{{ $labels.instance }}: disk will be full in 4 hours"
  description: "Free space is {{ $value | humanizePercentage }} and shrinking."
  runbook_url: "https://wiki.example.com/runbooks/disk-full"
  dashboard: "https://grafana.example.com/d/nodes?var-instance={{ $labels.instance }}"

مسیریابی در Alertmanager: گروه‌بندی، سرکوب و سکوت

Alertmanager فقط ارسال‌کننده‌ی هشدار نیست؛ سه ابزار ضدنویز دارد:

  • گروه‌بندی (group_by): ده هشدار مرتبط را در یک پیام می‌فرستد.
  • سرکوب (inhibit_rules): وقتی هشدار علت‌ریشه‌ای فعال است، هشدارهای ناشی از آن را خاموش می‌کند (مثلاً اگر یک نود پایین است، هشدار تک‌تک پادهای روی آن لازم نیست).
  • سکوت (silence): برای نگهداری برنامه‌ریزی‌شده، هشدارها را موقتاً بی‌صدا می‌کند.
route:
  receiver: ticket
  group_by: [alertname, service]
  routes:
    - matchers: [severity="page"]
      receiver: oncall
      repeat_interval: 1h
    - matchers: [severity="warning"]
      receiver: ticket
      repeat_interval: 12h

inhibit_rules:
  - source_matchers: [severity="page"]
    target_matchers: [severity="warning"]
    equal: [service]            # اگر page برای همان سرویس فعال است، warning را ساکت کن

receivers:
  - name: oncall
    webhook_configs: [{ url: "http://notifier.internal:8080/page" }]
  - name: ticket
    webhook_configs: [{ url: "http://notifier.internal:8080/ticket" }]

برای مسیریابی با regex (مثلاً match_re روی نام سرویس)، الگو را قبل از استفاده امتحان کنید؛ Alertmanager هم مثل Prometheus از RE2 و تطابق کامل استفاده می‌کند.

/.*/Regex Testerالگوهای regex مورد استفاده در مسیریابی و label matcher را آزمایش کنید.

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

هشدارها مثل کد، با زمان فرسوده می‌شوند. ماهی یک‌بار، هشدارهای ارسال‌شده را مرور کنید و برای هرکدام بپرسید:

  • چند بار فعال شد و چند بار منجر به اقدام شد؟ هشدار با نسبت اقدام پایین را حذف یا کم‌حساس کنید.
  • آیا مشکل‌های واقعی را بدون هشدار از دست دادیم؟ پس‌از هر حادثه بپرسید «کدام هشدار باید می‌گفت؟».
  • runbook هنوز درست است؟

در ثبت زمان حوادث و تطبیق آن با زمان هشدار، تبدیل timestamp بین UTC و زمان محلی خطای رایجی است:

TSUnix Timestamp Converterیک زمان را بین UTC و زمان محلی تبدیل کنید تا خط زمانی حادثه با هشدارها هم‌خوان شود.

چک‌لیست شروع

  1. برای هر سرویس مهم، چهار سیگنال طلایی را در داشبورد داشته باشید.
  2. یک SLO ساده (مثلاً دسترس‌پذیری ۹۹٫۹٪) تعریف کنید و SLI آن را با PromQL بنویسید.
  3. دو هشدار burn-rate (سریع و کند) و چند هشدار اشباع (دیسک، گواهی) بنویسید؛ نه بیشتر.
  4. برای هر هشدار runbook و لینک داشبورد بگذارید.
  5. سرکوب و گروه‌بندی را در Alertmanager فعال کنید.
  6. ماهانه بازبینی کنید و هشدارهای بی‌اقدام را حذف کنید.

جمع‌بندی و مطالعه‌ی بعدی

هشدار خوب کم، دقیق و قابل‌اقدام است: بر علامت‌های کاربر (خطا و تأخیر) تکیه می‌کند، با SLO و burn rate میزان فوریت را مشخص می‌کند و با گروه‌بندی و سرکوب نویز را کم می‌کند. اگر هنوز استک مانیتورینگ ندارید، راه‌اندازی Prometheus، Grafana و Alertmanager را اجرا کنید و کوئری‌های لازم را از راهنمای PromQL بردارید.

پرسش‌های متداول

SLO و SLA چه فرقی دارند؟
SLO هدف داخلی قابل‌اندازه‌گیری است (مثلاً ۹۹٫۹٪ درخواست‌ها موفق). SLA قرارداد با مشتری است و معمولاً جریمه یا جبران مالی دارد. SLO را همیشه سخت‌گیرانه‌تر از SLA بگذارید تا پیش از نقض قرارداد، هشدار بگیرید.
چه تعداد هشدار «page» در هفته قابل‌قبول است؟
قاعده‌ی کلی این است که هر شیفت آنکال کمتر از چند هشدار قابل‌اقدام داشته باشد. اگر بیشتر هشدارها به اقدامی نمی‌انجامند یا خودشان برطرف می‌شوند، حساسیت را کم کنید یا آن‌ها را به تیکت یا داشبورد تبدیل کنید.
چرا هشدار روی CPU بالا توصیه نمی‌شود؟
CPU بالا لزوماً مشکل نیست و کاربر را متأثر نمی‌کند؛ علت احتمالی است، نه علامت. ترجیحاً روی خطا و تأخیر هشدار بدهید و CPU را در داشبورد و برای عیب‌یابی بعد از هشدار استفاده کنید. استثنا: وقتی اشباع به‌زودی به قطعی می‌انجامد (مثل پرشدن دیسک).
error budget چیست و به چه دردی می‌خورد؟
بودجه‌ی خطا همان مقدار قابل‌قبول خطا است (۱۰۰٪ منهای SLO). تا وقتی بودجه باقی است، تیم می‌تواند ریسک کند و ویژگی جدید منتشر کند؛ وقتی بودجه تمام شد، تمرکز به پایداری برمی‌گردد. این کار بحث «سرعت یا پایداری» را به یک عدد تبدیل می‌کند.