সরাসরি পর্বে যান
পর্ব ৬৬ · ৮১-এর মধ্যে · মডিউল ১১

Alerting আর SLO — burn rate, on-call আর ভালো alert

Alerting and SLOs — Burn Rate, On-Call and Good Alerts

Taught in Bangla, this lesson separates SLI, SLO and SLA, chooses user-facing SLIs, and follows a real alert from a Prometheus rule through Alertmanager with for, grouping and silences. It judges alerts by precision, recall, detection and reset time, calculates burn rate with worked examples, writes multi-window, multi-burn-rate alerts, and covers page versus ticket, alert fatigue, runbooks and fair on-call schedules.

এই পর্বে যা শিখবেন

  • ব্যবহারকারীর চোখে একটি SLI বেছে SLO আর SLA থেকে আলাদা করা
  • Prometheus-এর rule থেকে Alertmanager-এর বার্তা পর্যন্ত একটি আসল alert-এর পথ: for, grouping, silence
  • Precision, recall, detection time আর reset time দিয়ে alert-এর মান মাপা
  • Burn rate হিসাব করে multi-window, multi-burn-rate alert লেখা ও যাচাই করা
  • Page বনাম ticket, noise কমানো, runbook আর একটি ন্যায্য on-call সূচি বানানো

১ · SLI, SLO আর SLA — মাপ, লক্ষ্য আর চুক্তি

রাত ৩টা। একজন প্রকৌশলীর ফোন বেজে উঠল: CPU 91%. তিনি ল্যাপটপ খুলে দেখলেন, সব ঠিক চলছে। পরের সপ্তাহে কোনো alert নেই, অথচ checkout-এ টানা দুই ঘণ্টা অনেকের টাকা কেটে গেল কিন্তু অর্ডার হলো না। প্রথমটিতে অকারণ ডাক, দ্বিতীয়টিতে আসল বিপদে নীরবতা। এই পর্ব এই দুটি সমস্যারই সমাধান।

সমাধানের শুরু একটি প্রশ্নে: ব্যবহারকারীর কাছে “ঠিক চলছে” মানে কী? সেটি মাপতে তিনটি শব্দ লাগে। শব্দগুলো প্রায় একসাথে বলা হয়, কিন্তু তিনটির কাজ আলাদা।

একটি লঞ্চঘাটের কথা ভাবুন। ঘাটের খাতায় লেখা থাকে কত ভাগ লঞ্চ সময়মতো ছেড়েছে: এটি SLI. কোম্পানি নিজেরা ঠিক করল মাসে ৯৮% লঞ্চ সময়মতো ছাড়বে: এটি SLO. আর টিকিটের পেছনে লেখা শর্ত, ৯৫%-এর নিচে নামলে ভাড়ার অংশ ফেরত: এটি SLA. খাতা, নিজের লক্ষ্য আর যাত্রীর সাথে চুক্তি, তিনটি তিন জিনিস।

SLISLOSLA
পুরো নামService Level IndicatorService Level ObjectiveService Level Agreement
কীমাপা সংখ্যাসেই সংখ্যার লক্ষ্যফল-সহ চুক্তি
উদাহরণগত ৩০ দিনে ৯৯.৯৩% অনুরোধ সফল৩০ দিনে ৯৯.৯% সফলমাসে ৯৯.৫%-এর নিচে নামলে বিলের অংশ ফেরত
কে ঠিক করেপ্রকৌশল দলপণ্য আর প্রকৌশল দল একসাথেব্যবসা, আইন আর গ্রাহক
ভাঙলে কী হয়কিছু না, এটি শুধু তথ্যনিজেদের error-budget policy চালু হয়টাকা ফেরত বা অন্য চুক্তিগত ফল

SLO সাধারণত SLA-র চেয়ে কড়া রাখা হয়। ওপরের উদাহরণে ৯৯.৯% বনাম ৯৯.৫%. মাঝের ফাঁকটি হলো নিরাপত্তার জায়গা: চুক্তি ভাঙার আগেই দল সতর্ক হয়। সব সেবার SLA থাকে না। অভ্যন্তরীণ সেবায় সাধারণত শুধু SLO থাকে। Cloud provider-এর SLA-র শর্ত, বাদ পড়া ঘটনা আর credit-এর হার provider-ভেদে আলাদা, তাই নিজের চুক্তি পড়ে নিতে হয়।

Error budget = ১ − SLO, সেটি আপনি পর্ব ৭-এ দেখেছেন: ৯৯.৯%, ৩০ দিন মানে ৪৩.২ মিনিটের সমতুল্য। সেটি আবার গণনা করব না। SLO-র নকশা আর budget-এর নীতির তত্ত্ব আছে System Design কোর্সের Observability পর্বে। এখানে প্রশ্নটি operational: এই budget-কে পাহারা দেবেন কীভাবে, আর ডাক দেবেন কখন।

২ · ব্যবহারকারীর চোখে SLI বাছাই

ভালো SLI শুরু হয় যন্ত্র থেকে নয়, ব্যবহারকারীর কাজ থেকে। প্রথমে একটি critical user journey বাছুন। একটি কাল্পনিক অনলাইন বাজার অ্যাপে সেগুলো হতে পারে “পণ্য খোঁজা” আর “অর্ডার শেষ করা”। তারপর প্রতিটির জন্য বলুন, “ভালো” ঘটনা কী।

SLI = ভালো ঘটনা ÷ বৈধ ঘটনা
অর্ডার: (২ সেকেন্ডের মধ্যে সফল উত্তর) ÷ (সব বৈধ অর্ডার অনুরোধ)

এই রূপের সুবিধা হলো ফল সবসময় ০% থেকে ১০০%-এর মধ্যে, আর ১০০% মানে সবচেয়ে ভালো। ফলে বিভিন্ন সেবা একই ভাষায় তুলনা করা যায়। The Site Reliability Workbook (Google, ২০১৮) সেবার ধরন অনুযায়ী এই রকম একটি তালিকা দেয়:

সেবার ধরনSLI“ভালো” মানে
অনুরোধ-উত্তর (API, ওয়েবসাইট)Availabilityউত্তর এসেছে, 5xx নয়
অনুরোধ-উত্তরLatencyসীমার মধ্যে উত্তর, যেমন ৩০০ ms
Data pipelineFreshnessData ১০ মিনিটের চেয়ে পুরোনো নয়
Data pipelineCorrectnessযাচাই করা ফলের সাথে মিলেছে
StorageDurabilityলেখা data পরে পড়া গেছে

কোথায় মাপবেন

একই SLI ভিন্ন জায়গায় মাপলে ভিন্ন সত্য দেখায়। Workbook একে বলে SLI-এর specification আর implementation-এর পার্থক্য: “কী মাপতে চাই” আর “কীভাবে মাপছি”।

কোথায়যা ধরেযা ফাঁকি যায়
Application metricসহজ, বিস্তারিত labelApp ক্র্যাশ করলে নিজের ব্যর্থতাই গোনে না
Load balancer log বা metricBackend উত্তর না দিলেও গোনা হয়DNS, CDN আর ব্যবহারকারীর network
Synthetic probeরাতে কম traffic-এও মাপ চলেনকল পথ, আসল ব্যবহারকারীর সব পথ নয়
Client-এর ভেতরেব্যবহারকারীর আসল অভিজ্ঞতার সবচেয়ে কাছেData দেরিতে আসে, আর আপনার হাতের বাইরের সমস্যাও মেশে

শুরুর জন্য load balancer ভালো জায়গা। পরে দরকার হলে client-এর মাপ যোগ করুন। একটি প্রশ্ন আগে ঠিক করতে হয়: “বৈধ” কোনগুলো? ভুল পাসওয়ার্ডের 401 সাধারণত গোনা হয় না, আর bot-এর traffic বাদ দেওয়াই ভালো। কিন্তু হঠাৎ 4xx-এর ঢল একটি ভুল client release-ও হতে পারে, তাই সেটি আলাদা করে দেখা দরকার।

CPU, memory বা queue-র দৈর্ঘ্য SLI নয়। ব্যবহারকারী CPU দেখেন না। গড় latency-ও ভালো SLI নয়, কারণ কিছু খুব ধীর অনুরোধ গড়ে হারিয়ে যায়। “৩০০ ms-এর মধ্যে উত্তর পাওয়া অনুরোধের শতাংশ” লিখলে percentile-এর ধারণাটি SLI-এর ভেতরেই ঢুকে যায়। Metric-এর গঠন আপনি পর্ব ৬৩ · Metric আর Prometheus-এ দেখেছেন।

SLO লেখার আগে একটি কাজ করুন: গত কয়েক সপ্তাহের log থেকে SLI হিসাব করে দেখুন। ৯৯.৯৯% লক্ষ্য লিখলেন, অথচ এখনই ৯৯.৮% চলছে, তাহলে প্রথম দিনেই budget শেষ। লক্ষ্য শুরু করুন বাস্তব থেকে, পরে ব্যবহারকারীর প্রয়োজন দেখে বাড়ান বা কমান।

৩ · একটি আসল alert-এর জীবন — Prometheus থেকে Alertmanager

তত্ত্বের আগে একটি আসল alert বাজিয়ে দেখি। Prometheus metric টেনে আনে আর নিয়ম যাচাই করে। সে নিজে কাউকে ডাকে না। ডাকার কাজ Alertmanager-এর।

Prometheus হলো টহলরত পাহারাদার: সে দেখে আগুন লেগেছে কি না। Alertmanager হলো ফায়ার সার্ভিসের নিয়ন্ত্রণ কক্ষ। এক আগুনের জন্য পঞ্চাশটি ফোন এলেও সে একটি গাড়িই পাঠায়, কে দায়িত্বে আছেন দেখে নেয়, আর আগে থেকে জানানো মহড়ার ধোঁয়ায় গাড়ি পাঠায় না।

পরীক্ষাটি নিচের মতো সাজানো: একটি ছোট Python app তিনটি route গোনে (/checkout, /search, /cart), একটি load container অনুরোধ পাঠায়, আর একটি নকল pager প্রতিটি webhook ছাপে। আউটপুট Docker Engine 29-এ, Prometheus v3.5.0 আর Alertmanager v0.28.1 দিয়ে একটি আসল run থেকে নেওয়া। সময়, id আর হার প্রতি run-এ আলাদা হবে। প্রকৃত নিয়মের ১ ঘণ্টা আর ৫ মিনিট অপেক্ষা না করে, এই পরীক্ষায় জানালা ছোট করা হয়েছে: ২ মিনিট আর ৩০ সেকেন্ড।

groups:
  - name: slo-recording
    rules:
      - record: route:error_ratio:rate30s
        expr: |
          sum by (service, route) (rate(http_requests_total{code="500"}[30s]))
          / sum by (service, route) (rate(http_requests_total[30s]))
      # rate2m is the same with [2m]
  - name: slo-alerts
    rules:
      - alert: FastBurn
        expr: |
          route:error_ratio:rate2m > (14.4 * 0.001)
          and route:error_ratio:rate30s > (14.4 * 0.001)
        for: 30s
        labels:
          severity: page
        annotations:
          summary: "{{ $labels.route }} is burning the error budget fast"
          runbook_url: "https://runbooks.example.com/shop/fast-burn"
      # SlowBurn: same shape, limit 1 * 0.001, severity: ticket

এখানে দুই রকম নিয়ম। Recording rule একটি হিসাব আগে করে নতুন নামে রাখে। Alert rule একটি শর্ত। for: 30s মানে শর্ত টানা ৩০ সেকেন্ড সত্য না থাকলে alert পাঠানো হবে না। ভাষাটি PromQL, যা পর্ব ৬৩-এ দেখেছেন। runbook_url-এর ঠিকানাটি কাল্পনিক।

route:
  receiver: pager
  group_by: [service, severity]
  group_wait: 10s
  group_interval: 30s
  repeat_interval: 1h
  routes:
    - matchers: ['severity="ticket"']
      receiver: ticket-queue
receivers:
  - name: pager
    webhook_configs:
      - url: http://abcl-al-pager:9000/page
        send_resolved: true
  - name: ticket-queue
    webhook_configs:
      - url: http://abcl-al-pager:9000/ticket
        send_resolved: false
inhibit_rules:
  - source_matchers: ['severity="page"']
    target_matchers: ['severity="ticket"']
    equal: [service, route]
সেটিংকাজ
group_byকোন label এক হলে alert-গুলো একটি বার্তায় জোড়া দেবে
group_waitনতুন group-এর প্রথম বার্তার আগে অপেক্ষা, যাতে সঙ্গীরা এসে পড়ে
group_intervalএকই group-এ নতুন কিছু হলে পরের বার্তার আগে অপেক্ষা
repeat_intervalকিছু না বদলালেও কতক্ষণ পরে আবার মনে করিয়ে দেবে
inhibit_rulesএকই route-এ page চললে ticket-এর বার্তা চেপে রাখবে

প্রথমে দুটি ফাইলই যন্ত্রে যাচাই করা হলো (/c হলো container-এর ভেতরে ফাইলের জায়গা):

$ promtool check rules /c/rules.yml
Checking /c/rules.yml
  SUCCESS: 4 rules found

$ amtool check-config /c/alertmanager.yml
Checking '/c/alertmanager.yml'  SUCCESS
Found:
 - global config
 - route
 - 1 inhibit rules
 - 2 receivers
 - 0 templates

এবার t+৩১ সেকেন্ডে /checkout আর /search-এ ৫% error ঢোকানো হলো। একটি ছোট script প্রতি সেকেন্ডে Prometheus-এর /api/v1/alerts পড়ে, আর অবস্থা বদলালে একটি লাইন লেখে:

t+   0s (no alerts)
t+  31s <-- 5% errors injected on /checkout and /search
t+  43s SlowBurn /checkout pending; SlowBurn /search pending
t+  59s FastBurn /checkout pending; FastBurn /search pending; …
t+  75s … SlowBurn /checkout firing; SlowBurn /search firing
t+  91s FastBurn /checkout firing; FastBurn /search firing; …

একটি alert-এর তিনটি অবস্থা: inactive, pending, firing. FastBurn t+৫৯-এ pending, কারণ ২ মিনিটের জানালায় error ধীরে জমে ১.৪৪% পেরোতে সময় নেয়। তারপর ৩০ সেকেন্ডের for পার হয়ে t+৯১-এ firing, ৫ সেকেন্ডের evaluation চক্রের জন্য ৩২ সেকেন্ড লেগেছে। শুধু firing alert Alertmanager-এ যায়। Pending অবস্থায় শর্ত মিথ্যা হলে কেউ জানতেও পারেন না।

নকল pager-এ যা পৌঁছাল (সময় একই ঘড়িতে আনা হয়েছে, লাইন ছোট করা):

t+  85s receiver=ticket-queue status=firing alerts=2
   SlowBurn /checkout firing runbook=…/shop/slow-burn
   SlowBurn /search firing runbook=…/shop/slow-burn
t+ 103s receiver=pager status=firing alerts=2
   FastBurn /checkout firing runbook=…/shop/fast-burn
   FastBurn /search firing runbook=…/shop/fast-burn

Grouping: দুটি route ব্যর্থ, কিন্তু ফোন বেজেছে একবার: alerts=2. একে বলে alert grouping. ৫০টি pod-এর সেবায় এই নিয়ম না থাকলে একটি বিভ্রাটে ৫০টি ডাক আসত। t+৯১-এ firing, t+১০৩-এ বার্তা: ১০ সেকেন্ডের group_wait-এর ফল।

আসল run-এর একটি সত্য: ticket গেছে page-এর আগে, কারণ SlowBurn-এর সীমা নিচু, সে আগে firing হয়েছে। Inhibition কাজ করে কেবল FastBurn firing হওয়ার পর। তাই বাস্তবে আগে একটি অপ্রয়োজনীয় ticket খুলতে পারে।

এবার silence. ধরুন /cart-এ একটি পরিকল্পিত কাজ চলবে। t+১৪১-এ silence বসিয়ে সেখানেও ৫% error ঢোকানো হলো। পুরো run-এ pager-এ /cart-এর একটি বার্তাও আসেনি (amtool-এর --alertmanager.url বাদ দিয়ে দেখানো):

$ amtool silence add route=/cart --duration=30m --author=rafi \
    --comment="planned cart migration"
bf1c8a30-e43b-474e-a4e9-256c0f9848aa

$ amtool alert query             # active: reaches a human
Alertname  Starts At                Summary                  State
FastBurn   2026-10-30 21:24:26 UTC  /search is burning …     active
FastBurn   2026-10-30 21:24:26 UTC  /checkout is burning …   active

$ amtool alert query --silenced  # a human chose this
Alertname  Starts At                Summary                  State
FastBurn   2026-10-30 21:26:36 UTC  /cart is burning …       suppressed

$ amtool alert query --inhibited # another alert covers this
Alertname  Starts At                Summary                  State
SlowBurn   2026-10-30 21:24:11 UTC  /checkout is burning …   suppressed
SlowBurn   2026-10-30 21:24:11 UTC  /search is burning …     suppressed

Silence বা inhibition alert মোছে না, শুধু বার্তা থামায়। /cart-এর alert t+২২১-এ Prometheus-এ firing ছিল, Alertmanager-এ suppressed. Silence-এ শেষ সময়, লেখক আর কারণ থাকে, তাই পরে হিসাব মেলানো যায়। Inhibition একটি নিয়ম: এখানে একই route-এ page চললে ticket চুপ।

t+২৩৩-এ error সরানো হলো, শুধু /search-এ ০.৫% রাখা হলো। ৩০ সেকেন্ডের জানালা নেমে যেতেই t+২৬২-তে FastBurn মুছে গেল, আর t+২৯০-এ status=resolved alerts=2 বার্তা এলো। ৩০ সেকেন্ডের group_interval-এর জন্য এই বিলম্ব। /search-এ তখন শুধু SlowBurn বাকি ছিল। এটিই page থেকে ticket-এ নেমে আসা।

এই পরীক্ষার প্রথম চেষ্টা ব্যর্থ হয়েছিল, আর সেটিই সবচেয়ে বড় শিক্ষা। App-এ error চলছিল, অথচ কোনো alert নেই। কারণ Prometheus 3 এমন target নেয় না, যার উত্তরে Content-Type ফাঁকা। Target-এর অবস্থা ছিল down, ত্রুটি: non-compliant scrape target sending blank Content-Type and no fallback_scrape_protocol specified for target. Metric না থাকায় নিয়মের ফল ফাঁকা, আর ফাঁকা মানে “সব শান্ত”। নীরব dashboard সবসময় ভালো খবর নয়। তাই up == 0-এর জন্য আলাদা alert রাখুন।

৪ · লক্ষণে alert, কারণে নয় — ভালো alert-এর চারটি মাপ

“CPU ৯০%”, “pod restart”, “disk ৮০%” হলো সম্ভাব্য কারণ। “Checkout-এ ৫% অনুরোধ ব্যর্থ” হলো লক্ষণ। ডাক্তার জ্বর দেখে রোগী ভর্তি করেন, প্রতিটি জীবাণু গুনে নয়। লক্ষণভিত্তিক alert-ও তাই: ব্যবহারকারী কষ্ট পেলে তবেই ডাক। Google-এর Rob Ewaschuk-এর লেখা “My Philosophy on Alerting” আর SRE বইয়ের monitoring অধ্যায় এই ধারণাকে জনপ্রিয় করে।

প্রশ্নকারণভিত্তিকলক্ষণভিত্তিক
সংকেতCPU, memory, restartError, ধীর উত্তর, পুরোনো data
ব্যবহারকারী কষ্ট না পেলেতবু ফোন বাজেবাজে না
অচেনা কারণের বিভ্রাটধরতে পারে নাধরে, কারণ যাই হোক
কারণের সংকেত থাকেPage-এDashboard আর runbook-এ

ব্যতিক্রমও আছে। “এই গতিতে disk ৪ ঘণ্টায় ভরবে” বা “certificate ৭ দিনে শেষ” এখনো ব্যবহারকারীকে কষ্ট দিচ্ছে না, কিন্তু এগুলো নিশ্চিত ভবিষ্যৎ লক্ষণ। এগুলো রাখুন, তবে সাধারণত ticket হিসেবে, আর সময় কম থাকলে page হিসেবে। ৩য় অংশে দেখা up বন্ধ হওয়াও তেমনই: মাপ বন্ধ হলে লক্ষণ দেখারই উপায় থাকে না।

চারটি মাপকাঠি

Alert ভালো কি মন্দ, তা তর্কে নয়, মাপে ঠিক হয়। Workbook-এর “Alerting on SLOs” অধ্যায় চারটি মাপ দেয়:

Precision

যতবার alert বেজেছে, তার কত ভাগ সত্যিই গুরুত্বপূর্ণ ছিল। ৪০ বারে ১০ বার আসল মানে ২৫%.

Recall

যত গুরুত্বপূর্ণ ঘটনা ঘটেছে, তার কত ভাগ ধরা পড়েছে। ৯টির ৬টি মানে ৬৭%.

Detection time

সমস্যা শুরু থেকে alert বাজা পর্যন্ত সময়। যত কম, তত কম ক্ষতি।

Reset time

সমস্যা মেটার পরও alert কতক্ষণ বাজে। লম্বা হলে মানুষ ভাবেন সমাধান কাজ করেনি।

এই চারটি একে অপরকে টানে। ছোট জানালা দ্রুত ধরে, কিন্তু ক্ষণিকের ঝাঁকুনিতেও বাজে, ফলে precision কমে। লম্বা জানালায় precision বাড়ে, কিন্তু detection আর reset দুটোই ধীর হয়। পরের দুই অংশের লক্ষ্য হলো চারটিকেই একসাথে ভালো রাখা।

৫ · Burn rate — budget কত দ্রুত পুড়ছে

“Error ১%” শুনে বিপদ বোঝা যায় না। ৯৯% SLO-তে এটি ঠিক লক্ষ্যে, ৯৯.৯৯%-এ ভয়ানক। আসল প্রশ্ন: এই গতিতে চললে budget কবে ফুরোবে? এই গতির নামই burn rate.

মাসের শুরুতে হাতে ৩০,০০০ টাকা। দিনে ১,০০০ টাকা খরচ মানে burn rate ১: মাসের শেষ দিনে টাকা শেষ, ঠিক হিসাবমতো। দিনে ২,০০০ মানে burn rate ২: ১৫ দিনেই শেষ। burn rate ৩০ মানে এক দিনে মাসের সব টাকা।

burn rate = error rate ÷ (১ − SLO)
খরচ হওয়া budget = burn rate × জানালা ÷ SLO-র সময়কাল

দুটি সূত্রই সরল ভাগ-গুণ। burn rate ১ মানে ঠিক SLO-র গতিতে খরচ। ৩০ দিনের সময়কাল মানে ৭২০ ঘণ্টা। হিসাব পুরো budget-কে ১ ধরে, তাই ফল ভগ্নাংশ বা শতাংশ।

সমাধান করা হিসাব ১. SLO ৯৯.৯%, error rate ০.৫%, টানা ৬ ঘণ্টা। burn rate = ০.০০৫ ÷ ০.০০১ = ৫. খরচ = ৫ × ৬ ÷ ৭২০ = ০.০৪১৬৭, মানে budget-এর ৪.১৭%. এই গতিতে budget ফুরোবে ৭২০ ÷ ৫ = ১৪৪ ঘণ্টায়, অর্থাৎ ৬ দিনে।

সমাধান করা হিসাব ২. SLO ৯৯.৯৫%, পূর্ণ বিভ্রাট (error rate ১০০%), ৩ মিনিট। burn rate = ১ ÷ ০.০০০৫ = ২,০০০. খরচ = ২,০০০ × ৩ ÷ ৪৩,২০০ = ০.১৩৮৯, মানে ১৩.৮৯%. মাত্র ৩ মিনিটে মাসের প্রায় সাত ভাগের এক ভাগ।

Workbook-এর সুপারিশকৃত তিনটি সীমা এই সূত্র থেকেই আসে। উল্টো করে লিখলে: burn rate = খরচ × সময়কাল ÷ জানালা। নিচের প্রোগ্রাম সেই টেবিল নিজে হিসাব করে যাচাই করে। সংখ্যা বদলে আপনার SLO-র জন্য চালিয়ে দেখতে পারেন।

// Recompute the SRE Workbook's multi-window table. SLO period: 30 days = 720 h.
const PERIOD_H = 30 * 24, SLO = 0.999, B = 1 - SLO;
const burnOf = (err, slo = SLO) => err / (1 - slo);       // error rate / (1 - SLO)
const used = (burn, hours) => burn * hours / PERIOD_H;    // burn x window / period
const pct = (x, d = 2) => (100 * x).toFixed(d) + "%";
const table = [["1 h", 1, "5 min", 14.4, "page"], ["6 h", 6, "30 min", 6, "page"],
               ["3 d", 72, "6 h", 1, "ticket"]];
console.log("long   short   burn  budget used  error > (99.9%)  empty in  action");
for (const [name, hours, short, burn, act] of table) {
  const days = PERIOD_H / burn / 24;
  console.log(name.padEnd(7) + short.padEnd(8) + String(burn).padStart(4) +
    pct(used(burn, hours), 1).padStart(13) + pct(burn * B).padStart(17) +
    (days.toFixed(2) + " d").padStart(10) + "  " + act);
}
console.log("\nbackwards: burn = budget used x period / window");
for (const [share, hours] of [[0.02, 1], [0.05, 6], [0.10, 72]])
  console.log(`  ${pct(share, 0)} in ${hours} h -> burn ${(share * PERIOD_H / hours).toFixed(1)}`);
// Detection time of the 1 h rule, starting from a clean window.
console.log("\nerror rate  burn   minutes until the 1 h rule at 14.4 fires");
for (const err of [0.01, 0.015, 0.02, 0.05, 0.10, 1]) {
  const burn = burnOf(err);
  const t = burn >= 14.4 ? (60 * 14.4 / burn).toFixed(1) : "never";
  console.log(pct(err).padStart(10) + burn.toFixed(0).padStart(6) + t.padStart(8));
}
console.log("\n1% errors under two SLOs");
for (const slo of [0.999, 0.9995]) {
  const burn = burnOf(0.01, slo), fires = burn >= 14.4;
  console.log(`  SLO ${(slo * 100).toFixed(2)}%: burn ${burn.toFixed(0)}, 14.4 rule ` +
    (fires ? `fires after ${(60 * 14.4 / burn).toFixed(1)} min` : "never fires") +
    `, budget empty in ${(PERIOD_H / burn).toFixed(0)} h`);
}

আউটপুট:

long   short   burn  budget used  error > (99.9%)  empty in  action
1 h    5 min   14.4         2.0%            1.44%    2.08 d  page
6 h    30 min     6         5.0%            0.60%    5.00 d  page
3 d    6 h        1        10.0%            0.10%   30.00 d  ticket

backwards: burn = budget used x period / window
  2% in 1 h -> burn 14.4
  5% in 6 h -> burn 6.0
  10% in 72 h -> burn 1.0

error rate  burn   minutes until the 1 h rule at 14.4 fires
     1.00%    10   never
     1.50%    15    57.6
     2.00%    20    43.2
     5.00%    50    17.3
    10.00%   100     8.6
   100.00%  1000     0.9

1% errors under two SLOs
  SLO 99.90%: burn 10, 14.4 rule never fires, budget empty in 72 h
  SLO 99.95%: burn 20, 14.4 rule fires after 43.2 min, budget empty in 36 h

প্রথম টেবিল Workbook-এর সংখ্যা মিলিয়ে দেয়: ১৪.৪ × ১ ÷ ৭২০ = ২%, ৬ × ৬ ÷ ৭২০ = ৫%, ১ × ৭২ ÷ ৭২০ = ১০%. burn ১৪.৪ মানে ৯৯.৯% SLO-তে error rate ১.৪৪%, আর পুরো budget ২.০৮ দিনে শেষ।

তৃতীয় টেবিলে ধরার সময়: জানালা ফাঁকা থেকে শুরু হলে নিয়ম বাজে যখন budget-এর ঠিক ২% খরচ হয়েছে, তাই সময় = ৬০ × ১৪.৪ ÷ burn মিনিট। Error ২% হলে ৪৩.২ মিনিট, পূর্ণ বিভ্রাটে ০.৯ মিনিট।

শেষ অংশটি সাবধানে পড়ুন। ৯৯.৯% SLO-তে ১% error মানে burn ১০, যা ১৪.৪-এর নিচে। তাই ১ ঘণ্টার দ্রুত নিয়ম কখনোই বাজবে না, বাজবে ৬ ঘণ্টার নিয়ম। একই ১% error ৯৯.৯৫% SLO-তে burn ২০, তখন দ্রুত নিয়ম ৪৩.২ মিনিটে বাজে। এজন্য পরের stepper-এ SLO ৯৯.৯৫% ধরা হয়েছে।

৬ · Multi-window, multi-burn-rate alert

একটি মাত্র burn rate দিয়ে সব ধরা যায় না। উঁচু সীমা বড় বিভ্রাট দ্রুত ধরে, কিন্তু ধীর ফুটো দেখে না। নিচু সীমা ফুটো ধরে, কিন্তু ছোট ঝাঁকুনিতেও বাজে। তাই Workbook-এর শেষ সুপারিশ কয়েকটি সীমা, আর প্রতিটিতে দুটি জানালা। একে বলে multi-window, multi-burn-rate alert.

Budget খরচলম্বা জানালাছোট জানালাBurn rateকাজ
২%১ ঘণ্টা৫ মিনিট১৪.৪Page
৫%৬ ঘণ্টা৩০ মিনিট৬Page
১০%৩ দিন৬ ঘণ্টা১Ticket

লম্বা জানালা বলে “ক্ষতিটি অর্থবহ”। ছোট জানালা বলে “সমস্যা এখনো চলছে”। দুটোই সীমা পেরোলে তবেই alert বাজে। Workbook-এর নিয়ম-অনুমান: ছোট জানালা লম্বাটির ১/১২. এতে precision আসে লম্বা জানালা থেকে, আর reset time আসে ছোট জানালা থেকে। ছবিতে সেটি দেখুন।

১% error-এর ১ ঘণ্টার burst · SLO ৯৯.৯৫% · সীমা ১৪.৪

Long window confirms the damage; short window ends the alert

Multi-window burn-rate timeline: দুই জানালার alert ৪৪–৬২ মিনিট, শুধু লম্বা জানালায় ৪৪–৭৭ মিনিট 01020 সীমা ১৪.৪ ১ ঘণ্টার burn ৫ মিনিটের burn 0306090 burst শুরুর পরে মিনিট সমস্যা চলছে দুই জানালার alert শুধু ১ ঘণ্টার alert
ছবি ৬৬.১ — দুই জানালাই ৪৪ মিনিটে একসাথে বাজে। সমস্যা ৬০ মিনিটে থামলে ছোট জানালা alert বন্ধ করে ৬২ মিনিটে; শুধু লম্বা জানালা হলে বন্ধ হতো ৭৭ মিনিটে।

ছবির ঘটনাটি মিনিট ধরে দেখুন। ধরে নিন স্বাভাবিক সময়ে error প্রায় শূন্য। হিসাবগুলো script-এ করা।

SLO ৯৯.৯৫% · error ১% · burn ২০ · সীমা ১৪.৪ · সময়কাল ৪৩,২০০ মিনিট
Burst শুরুর পরে
১ ঘণ্টার burn
৫ মিনিটের burn
দুই জানালার alert
শুধু ১ ঘণ্টা হলে
Budget খরচ
  1. শুরু। ১% error শুরু হলো। burn = ০.০১ ÷ ০.০০০৫ = ২০. দুই জানালাই এখনো ফাঁকা।
  2. ৪ মিনিট। ৫ মিনিটের জানালায় ৪ মিনিট খারাপ, burn ১৬, সীমার ওপরে। ১ ঘণ্টার জানালায় burn মাত্র ১.৩৩, তাই alert চুপ। এটি যদি ক্ষণিকের ঝাঁকুনি হতো, এখানেই শেষ হতো।
  3. ২০ মিনিট। ছোট জানালা ২০-তে স্থির। লম্বা জানালা ধীরে উঠছে: ২০ × ২০ ÷ ৬০ = ৬.৬৭. Budget গেছে ০.৯৩%.
  4. ৪৪ মিনিট, alert বাজল। ৪৩ মিনিটে লম্বা জানালা ছিল ১৪.৩৩, ৪৪ মিনিটে ১৪.৬৭. দুটোই সীমার ওপরে, তাই page. Budget গেছে ২.০৪%, অর্থাৎ নকশার ২% সীমার ঠিক পরে।
  5. ৬০ মিনিট, সমস্যা থামল। Rollback কাজ করেছে। মোট খরচ ২০ × ৬০ ÷ ৪৩,২০০ = ২.৭৮%.
  6. ৬২ মিনিট, alert থামল। ৫ মিনিটের জানালায় এখন ৩ মিনিট খারাপ, burn ১২, সীমার নিচে। Reset time মাত্র ২ মিনিট। লম্বা জানালা তখনো ১৯.৩৩, ছোট জানালা না থাকলে alert বাজতেই থাকত।
  7. ৭৭ মিনিট। শুধু লম্বা জানালার নিয়ম এতক্ষণে থামল: burn ১৪.৩৩. Reset time ১৭ মিনিট। এই সময়ে on-call ভাবতেন rollback কাজ করেনি, হয়তো আরও একটি ঝুঁকিপূর্ণ বদল চালাতেন।

এবার উল্টো ঘটনা: খুব ছোট একটি ফুটো, যা কোনো page ছোঁয় না, অথচ ফেলে রাখলে পুরো budget খায়।

SLO ৯৯.৯% · error ০.২% · burn ২ · ticket সীমা ১ · সময়কাল ৭২০ ঘণ্টা
ফুটো শুরুর পরে
৩ দিনের burn
৬ ঘণ্টার burn
Page নিয়ম (১৪.৪, ৬)
Ticket নিয়ম
Budget খরচ
  1. শুরু। একটি release-এর পর ০.২% অনুরোধ ব্যর্থ হচ্ছে। শুনতে কিছুই নয়। burn = ০.০০২ ÷ ০.০০১ = ২. এই গতিতে budget ৭২০ ÷ ২ = ৩৬০ ঘণ্টায়, অর্থাৎ ১৫ দিনে শেষ।
  2. ৪ ঘণ্টা। ৬ ঘণ্টার জানালা ১.৩৩, সীমার ওপরে। কিন্তু ৩ দিনের জানালা মাত্র ০.১১. মাত্র ৪ ঘণ্টার ফুটো এখনো অর্থবহ ক্ষতি নয়।
  3. ১২ ঘণ্টা। রাত পার হলো, কেউ জাগেনি, আর সেটিই ঠিক। Budget গেছে ৩.৩৩%.
  4. ৩৭ ঘণ্টা, ticket খুলল। ৩৬ ঘণ্টায় ৩ দিনের burn ঠিক ১.০০, সীমার সমান, ওপরে নয়। ৩৭ ঘণ্টায় ১.০৩. Budget গেছে ১০.২৮%, নকশার ১০% সীমার ঠিক পরে। কোনো ফোন বাজল না, কাজের সারিতে একটি ticket এলো।
  5. ৪৮ ঘণ্টা, ঠিক করা হলো। সকালে দল ticket দেখে release ফিরিয়ে নিল। মোট খরচ ২ × ৪৮ ÷ ৭২০ = ১৩.৩৩%, যেখানে ফেলে রাখলে ১৫ দিনে ১০০% যেত।
  6. ৫১ ঘণ্টা, শর্ত থামল। ৬ ঘণ্টার জানালায় এখন ৩ ঘণ্টা খারাপ, burn ঠিক ১.০০, সীমার ওপরে নয়। Reset time ৩ ঘণ্টা। ৩ দিনের জানালা তখনো ১.৩৩; ছোট জানালা না থাকলে শর্ত ৮৪ ঘণ্টা পর্যন্ত, অর্থাৎ আরও ৩৩ ঘণ্টা চালু থাকত।

Production-এ নিয়মগুলো Prometheus-এ দেখতে কেমন, নিচে আছে। এই ফাইলটি promtool check rules-এ পাস করেছে (SUCCESS: 3 rules found). লক্ষ্য করুন, এখানে for নেই: জানালাই সেই অপেক্ষার কাজ করে। ৩য় অংশে for ছিল শুধু তার আচরণ দেখাতে।

groups:
  - name: shop-slo-recording
    rules:
      - record: route:error_ratio:rate5m
        expr: |
          sum by (service, route) (rate(http_requests_total{code=~"5.."}[5m]))
          / sum by (service, route) (rate(http_requests_total[5m]))
      # একইভাবে rate30m, rate1h, rate6h, rate3d
  - name: shop-slo-alerts
    rules:
      - alert: ErrorBudgetFastBurn
        expr: |
          (route:error_ratio:rate1h > (14.4 * 0.001)
           and route:error_ratio:rate5m > (14.4 * 0.001))
          or
          (route:error_ratio:rate6h > (6 * 0.001)
           and route:error_ratio:rate30m > (6 * 0.001))
        labels:
          severity: page
        annotations:
          summary: "{{ $labels.route }}: error budget দ্রুত পুড়ছে"
          runbook_url: "https://runbooks.example.com/shop/fast-burn"
      - alert: ErrorBudgetSlowBurn
        expr: |
          route:error_ratio:rate3d > (1 * 0.001)
          and route:error_ratio:rate6h > (1 * 0.001)
        labels:
          severity: ticket
        annotations:
          summary: "{{ $labels.route }}: error budget ধীরে পুড়ছে"
          runbook_url: "https://runbooks.example.com/shop/slow-burn"

এবার নিজে পরীক্ষা করুন। নিচের evaluator ২১ দিনের প্রতি মিনিটের একটি seeded error stream বানায়, তাতে ক্ষণিকের ঝাঁকুনি আর তিনটি ঘটনা থাকে, তারপর চারটি নিয়ম চালায়। EVENTS বা seed বদলে দেখুন কোন নিয়ম কখন বাজে।

// Burn-rate alert evaluator on a seeded per-minute error stream. Edit EVENTS.
let seed = 66; function rand() {                     // mulberry32
  seed = (seed + 0x6D2B79F5) | 0; let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
  t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 2 ** 32;
}
const DAY = 1440, DAYS = 21, ALLOWED = 0.001, REQ = 6000;   // SLO 99.9%, 100 req/s
const EVENTS = [{ name: "outage", start: 6 * DAY + 600, min: 45, err: 0.05 },
                { name: "bad deploy", start: 10 * DAY + 180, min: 480, err: 0.012 },
                { name: "slow leak", start: 15 * DAY, min: 2880, err: 0.002 }];
const pre = [0];                                     // prefix sum of failed requests
for (let m = 0; m < DAYS * DAY; m++) {
  let r = 0.0001;                                    // healthy background
  if (rand() < 0.002) r = 0.04;                      // one-minute blip, heals itself
  for (const e of EVENTS) if (m >= e.start && m < e.start + e.min) r = Math.max(r, e.err);
  pre.push(pre[m] + REQ * r * (0.7 + 0.6 * rand())); // noisy count around the rate
}
const burn = (m, w) => { const from = Math.max(0, m + 1 - w);
  return (pre[m + 1] - pre[from]) / ((m + 1 - from) * REQ) / ALLOWED; };
const rules = [["1h only    > 14.4", 60, 60, 14.4], ["1h and 5m  > 14.4", 60, 5, 14.4],
               ["6h and 30m > 6", 360, 30, 6], ["3d and 6h  > 1", 3 * DAY, 360, 1]];
const at = m => "d" + Math.floor(m / DAY) + " " + String(Math.floor(m % DAY / 60)).padStart(2, "0") +
  ":" + String(m % 60).padStart(2, "0");
for (const [name, long, short, limit] of rules) {
  let on = -1; const out = [];
  for (let m = 0; m < DAYS * DAY; m++) {
    const firing = m + 1 >= short && burn(m, long) > limit && burn(m, short) > limit;
    if (firing && on < 0) on = m;
    if (!firing && on >= 0) { out.push(at(on) + " to " + at(m)); on = -1; }
  }
  if (on >= 0) out.push(at(on) + " to end");
  console.log(name.padEnd(19) + out.length + " alert(s): " + (out.join(", ") || "none"));
}
for (const e of EVENTS) console.log(e.name.padEnd(11) + at(e.start) + " to " + at(e.start + e.min));
console.log("budget used: " + (100 * pre[DAYS * DAY] / (30 * DAY * REQ * ALLOWED)).toFixed(0) +
  "% of a 30-day budget");

আউটপুট:

1h only    > 14.4  1 alert(s): d6 10:16 to d6 11:28
1h and 5m  > 14.4  1 alert(s): d6 10:16 to d6 10:48
6h and 30m > 6     2 alert(s): d6 10:42 to d6 11:11, d10 05:50 to d10 11:14
3d and 6h  > 1     2 alert(s): d10 07:43 to d10 16:31, d16 07:24 to d17 03:12
outage     d6 10:00 to d6 10:45
bad deploy d10 03:00 to d10 11:00
slow leak  d15 00:00 to d17 00:00
budget used: 43% of a 30-day budget

Outage (৫%, burn ৫০): দ্রুত নিয়ম d6 10:16-এ বাজে, শুরুর ১৬ মিনিট পরে; সূত্রের ১৭.৩ মিনিটের কাছাকাছি, বাকিটা error-এর ওঠানামা। 1h only থামে ১১:২৮-এ, সমস্যা মেটার ৪৩ মিনিট পরে; দুই জানালার নিয়ম থামে ১০:৪৮-এ, ৩ মিনিট পরে।

Bad deploy (১.২%, burn ১২): ১৪.৪-এর নিচে, তাই দ্রুত নিয়ম চুপ। ৬ ঘণ্টার নিয়ম বাজে ০৫:৫০-এ, শুরুর ২ ঘণ্টা ৫০ মিনিট পরে (সূত্রে ৩৬০ × ৬ ÷ ১২ = ১৮০ মিনিট)।

Slow leak (০.২%, burn ২): শুধু ticket বাজে, শুরুর প্রায় ৩১ ঘণ্টা পরে। সূত্রের ৩৬ ঘণ্টার চেয়ে আগে, কারণ জানালায় আগে থেকেই পটভূমির error ছিল। এক মিনিটের ঝাঁকুনিগুলো একটি alert-ও চালু করেনি।

আরও গভীরে: Workbook দেখায়, খুব কম traffic-এ একটি ব্যর্থ অনুরোধই বড় error rate বানায়, তাই এই সীমাগুলো নড়বড়ে হয়। উপায় হিসেবে সেখানে আছে নকল traffic যোগ করা, ছোট সেবা জোড়া দিয়ে মাপা, বা SLO-র জানালা বদলানো। Latency SLO-তেও একই নিয়ম চলে: “ধীর অনুরোধের অনুপাত”-ই সেখানে error rate. Prometheus-এর keep_firing_for সেটিং আরেক পথে reset আচরণ বদলায়। এটি তুলনামূলক নতুন, তাই আপনার version-এর docs দেখে নিন।

৭ · Page না ticket — আর incident-এর পরে budget কত

প্রতিটি সংকেত মানুষকে ডেকে তোলার যোগ্য নয়। সিদ্ধান্তটি তিন ঘরের:

ধরনকখনকে দেখবেনউদাহরণ
Pageএখনই মানুষের বিচার দরকার, নইলে SLO ভাঙবেOn-call, কয়েক মিনিটেBurn ১৪.৪ বা ৬
Ticketদিন কয়েকের মধ্যে করলেই চলেদল, কর্মদিবসেBurn ১, ৭ দিনে certificate শেষ
Dashboard বা logকারণ খোঁজার তথ্যদরকারমতোCPU, restart গণনা

একটি alert page হওয়ার জন্য চারটি প্রশ্নের উত্তর “হ্যাঁ” হতে হবে: এটি কি জরুরি? এখনই কি কাজ করা সম্ভব? কাজটি কি মানুষের বিচার চায়? ব্যবহারকারীর কি সত্যিই ক্ষতি হচ্ছে? কাজটি প্রতিবার একই যান্ত্রিক ধাপ হলে সেটি alert নয়, automation-এর কাজ।

Incident মিটে গেলে পরের প্রশ্ন: budget কত বাকি? পর্ব ৭-এর নীতি এখানে কাজে লাগে। নিচের হিসাব একই সূত্র দিয়ে প্রতিটি incident-এর খরচ বের করে, আর চলমান ৩০ দিনের জানালায় বাকি budget দেখায়। সীমাগুলো একটি কাল্পনিক দলের নীতি। INCIDENTS বদলে দেখুন।

// Budget left after incidents. Edit INCIDENTS. Budget used = burn x time / period.
const SLO = 0.999, PERIOD = 30 * 1440, ALLOWED = 1 - SLO;
const INCIDENTS = [                     // day it started, minutes, error rate
  { day: 3,  min: 20,  err: 0.10 },     // bad config
  { day: 11, min: 90,  err: 0.08 },     // slow database after a deploy
  { day: 19, min: 15,  err: 1.00 },     // full outage
  { day: 26, min: 240, err: 0.01 },     // retry storm from a partner
  { day: 29, min: 120, err: 0.03 },     // cache node lost
  { day: 34, min: 30,  err: 0.60 },     // expired certificate
  { day: 45, min: 10,  err: 0.01 },     // small blip; old incidents start to leave
  { day: 52, min: 10,  err: 0.01 },
];
const usedBy = i => (i.err / ALLOWED) * i.min / PERIOD;
console.log("day  min  err%  burn  used%  left%  outage min left  state");
for (const now of INCIDENTS) {
  const inWindow = INCIDENTS.filter(i => i.day <= now.day && i.day > now.day - 30);
  const left = 1 - inWindow.reduce((s, i) => s + usedBy(i), 0);
  const state = left <= 0 ? "EMPTY: stop risky changes"
    : left < 0.25 ? "RED: reliability work first"
    : left < 0.5 ? "AMBER: canary only" : "GREEN";
  console.log(String(now.day).padStart(3) + String(now.min).padStart(5) +
    (now.err * 100).toFixed(1).padStart(6) + (now.err / ALLOWED).toFixed(0).padStart(6) +
    (usedBy(now) * 100).toFixed(1).padStart(7) + (left * 100).toFixed(1).padStart(7) +
    Math.max(0, left * ALLOWED * PERIOD).toFixed(1).padStart(17) + "  " + state);
}

আউটপুট:

day  min  err%  burn  used%  left%  outage min left  state
  3   20  10.0   100    4.6   95.4             41.2  GREEN
 11   90   8.0    80   16.7   78.7             34.0  GREEN
 19   15 100.0  1000   34.7   44.0             19.0  AMBER: canary only
 26  240   1.0    10    5.6   38.4             16.6  AMBER: canary only
 29  120   3.0    30    8.3   30.1             13.0  AMBER: canary only
 34   30  60.0   600   41.7   -6.9              0.0  EMPTY: stop risky changes
 45   10   1.0    10    0.2    9.5              4.1  RED: reliability work first
 52   10   1.0    10    0.2   44.0             19.0  AMBER: canary only

দিন ১৯-এর ১৫ মিনিটের পূর্ণ বিভ্রাট একাই ৩৪.৭% খায়: ১,০০০ × ১৫ ÷ ৪৩,২০০. দিন ৩৪-এর expired certificate (৬০% error, ৩০ মিনিট) budget শূন্যের নিচে নামায়, −৬.৯%. outage min left হলো বাকি budget, পূর্ণ বিভ্রাটের মিনিটে।

দিন ৪৫-এ নতুন ঘটনা প্রায় নেই, তবু বাকি ৯.৫%: দিন ৩ আর ১১-এর ঘটনা জানালা থেকে বেরিয়ে গেছে। দিন ৫২-তে দিন ১৯-এর বড় ঘটনাও বেরিয়েছে, তাই বাকি ৪৪.০%. চলমান জানালায় budget একবারে ভরে না, পুরোনো ঘটনা সরলে ফেরে।

৮ · Alert fatigue, মালিকানা আর runbook

Alert fatigue মানে অতিরিক্ত alert-এ মানুষের সাড়া ভোঁতা হয়ে যাওয়া। পাড়ার যে গাড়ির alarm রোজ বাজে, তাতে কেউ আর জানালায় তাকান না। Alert-কে তাই একটি পণ্যের মতো চালান, যার মান মাপা হয়, যার মালিক আছেন।

  • মাসিক হিসাব: প্রতিটি alert কতবার বেজেছে, কতবার কাজ লেগেছে, কতবার রাতে।
  • মুছে ফেলার অভ্যাস: যে alert-এ কেউ কিছু করেন না, সেটি মুছুন। Postmortem-এ নতুন alert যোগ করা সহজ, পুরোনো সরানোই আসল শৃঙ্খলা।
  • এক কারণে এক বার্তা: grouping আর inhibition ব্যবহার করুন।
  • মালিকানা: প্রতিটি alert-এর team label থাকবে। যে দল সেবা বানায়, noise তার কাছেই যাক; তখনই সেটি ঠিক হয়।
  • Code হিসেবে রাখা: Rule ফাইল Git-এ, review সহ, যেমন পর্ব ৫১-এর Infrastructure as Code.

প্রতিটি alert-এ runbook-এর লিংক

Runbook হলো রাত ৩টায় আধা-ঘুমে পড়ার মতো ছোট নির্দেশিকা। ৩য় অংশের প্রতিটি alert-এ runbook_url ছিল, আর বার্তার সাথেই লিংকটি পৌঁছেছিল। ভালো runbook ছয়টি প্রশ্নের উত্তর দেয়:

  1. এই alert-এর মানে কী, ব্যবহারকারীর ওপর প্রভাব কী?
  2. কোন dashboard আগে দেখবেন?
  3. সবচেয়ে সাধারণ কারণগুলো কী, আর সম্প্রতি কি deploy হয়েছে?
  4. নিরাপদ প্রথম পদক্ষেপ কী: rollback, traffic সরানো, নাকি feature flag বন্ধ?
  5. কখন, কাকে ডাকবেন?
  6. শেষ কবে এই পাতা যাচাই করা হয়েছে, আর মালিক কে?

এবার একটি কাল্পনিক দলের এক মাসের page মাপি। স্কোরটি এই কোর্সের শেখার সূচক, শিল্পের কোনো মান নয়: precision-এ ৫০%, recall-এ ৩০%, runbook আর মালিকানায় ১০% করে ওজন। রাতের page-এর হিসাব seeded সময় থেকে আসে, আর সব সংখ্যা কাল্পনিক।

// Alert quality from a month of pages (a classroom score, not an industry standard).
let seed = 2026; function rand() {               // mulberry32
  seed = (seed + 0x6D2B79F5) | 0; let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
  t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 2 ** 32;
}
// pages = sent, real = needed a human, rb / own = has a runbook / an owning team
const BEFORE = [["HighCPU", 64, 2, 0, 0], ["PodRestart", 41, 1, 0, 0],
                ["DiskOver80", 18, 3, 1, 0], ["CheckoutError", 7, 5, 1, 1]];
const AFTER = [["FastBurn", 5, 5, 1, 1], ["SlowBurn6h", 3, 2, 1, 1],
               ["DiskFullIn4h", 2, 2, 1, 1]];
function report(label, alerts, incidents, caught) {
  let pages = 0, real = 0, night = 0, rb = 0, own = 0;
  console.log(label);
  for (const [name, sent, good, hasRb, hasOwn] of alerts) {
    for (let i = 0; i < sent; i++) if (Math.floor(rand() * 24) < 7) night++;  // 00:00-06:59
    pages += sent; real += good; rb += hasRb * sent; own += hasOwn * sent;
    const p = good / sent;
    console.log("  " + name.padEnd(14) + String(sent).padStart(3) + " pages, precision " +
      (p * 100).toFixed(0).padStart(3) + "%  " + (p < 0.5 ? "FIX OR DELETE" : "keep"));
  }
  const precision = real / pages, recall = caught / incidents;
  const score = 100 * (0.5 * precision + 0.3 * recall + 0.1 * rb / pages + 0.1 * own / pages);
  console.log(`  ${pages} pages = ${(pages / 4).toFixed(1)} a week, ${night} at night`);
  console.log(`  precision ${(precision * 100).toFixed(1)}%, recall ${caught}/${incidents} = ` +
    `${(recall * 100).toFixed(0)}%, runbook ${(100 * rb / pages).toFixed(0)}%, ` +
    `owner ${(100 * own / pages).toFixed(0)}%`);
  console.log(`  score ${score.toFixed(0)} / 100`);
}
report("before (month 1)", BEFORE, 9, 6);   // 9 real incidents, 6 reached a human by page
report("after (month 3)", AFTER, 9, 8);

আউটপুট:

before (month 1)
  HighCPU        64 pages, precision   3%  FIX OR DELETE
  PodRestart     41 pages, precision   2%  FIX OR DELETE
  DiskOver80     18 pages, precision  17%  FIX OR DELETE
  CheckoutError   7 pages, precision  71%  keep
  130 pages = 32.5 a week, 40 at night
  precision 8.5%, recall 6/9 = 67%, runbook 19%, owner 5%
  score 27 / 100
after (month 3)
  FastBurn        5 pages, precision 100%  keep
  SlowBurn6h      3 pages, precision  67%  keep
  DiskFullIn4h    2 pages, precision 100%  keep
  10 pages = 2.5 a week, 6 at night
  precision 90.0%, recall 8/9 = 89%, runbook 100%, owner 100%
  score 92 / 100

প্রথম মাসে ১৩০টি page-এর মাত্র ১১টি আসল, তাই precision ৮.৫%, আর সপ্তাহে ৩২.৫টি ডাক। তবু ৯টি বড় ঘটনার ৩টি page ছাড়াই গেছে। বেশি alert মানে বেশি সুরক্ষা নয়: noise বাড়লেও recall মাত্র ৬৭%. নতুন সেট-এ ১০টি page, ৯টি আসল, recall ৮৯%. নিচের stepper দেখায় কোন ধাপে কী বদলেছে।

এক মাসের page · কাল্পনিক দল · ৯টি আসল বড় ঘটনা
বদল
Page প্রতি মাসে
Page প্রতি সপ্তাহে
Precision
Recall
স্কোর
  1. মাপ। চারটি alert, ১৩০টি page, ১১টি আসল। আগে সংখ্যা, তারপর মতামত। সবচেয়ে বেশি শব্দ করে HighCPU: ৬৪টির ২টি আসল।
  2. HighCPU সরানো। এটি কারণ, লক্ষণ নয়, তাই dashboard-এ গেল। Page অর্ধেকের মতো কমে ৬৬. যে ২টি ঘটনা এটি ধরত, সেগুলো অন্য alert-ও ধরে, এই দলের হিসাবে recall একই থাকে।
  3. PodRestart সরানো। Kubernetes নিজেই restart করে; একটি restart ব্যবহারকারীর সমস্যা নয়। Page ২৫-এ নামল, precision ৩২%.
  4. Disk নিয়ম বদল। “৮০% ভরেছে” বদলে হলো “এই গতিতে ৪ ঘণ্টায় ভরবে”। ১৮টি থেকে ২টি page, দুটিই আসল। এর সাথে runbook আর মালিকও যোগ হলো।
  5. Burn rate চালু। CheckoutError-এর সরল সীমা বদলে হলো দ্রুত আর ধীর burn নিয়ম। Page ১টি বাড়ল, কিন্তু recall ৮৯%-এ উঠল। ভালো alert শুধু কমায় না, ফাঁকও ভরে। দলের সপ্তাহে এখন ২.৫টি page.

৯ · On-call-এর নকশা — ন্যায্য সূচি আর paging tool

On-call মানে একজন নির্দিষ্ট সময়ে ডাক পেলে সাড়া দেওয়ার দায়িত্বে থাকেন। Rotation বা rota হলো সেই পালার সূচি। এর নকশায় তিনটি হিসাব লাগে: কতজন, কতবার, আর কত ভার।

কতজন. Google-এর Site Reliability Engineering (২০১৬) বইয়ে on-call-এ সময়ের সর্বোচ্চ ২৫% রাখার নিয়ম আছে। সব সময় primary আর secondary, দুজন থাকলে n জনের দলে একজন ২/n ভাগ সময় on-call:

দলের আকারসাপ্তাহিক পালায় একজনের ভাগ (২ ÷ n)মন্তব্য
৪ জন৫০%টেকসই নয়; শুধু primary রাখলেও ২৫%
৬ জন৩৩.৩%২৫%-এর ওপরে
৮ জন২৫%বইয়ের একক-সাইট দলের ন্যূনতম
১২ জন১৬.৭%আরামদায়ক

কত ভার. একই বই বলে, একটি ঘটনার পুরো কাজে (ধরা, সমাধান, postmortem) গড়ে প্রায় ৬ ঘণ্টা লাগে, তাই একটি ১২ ঘণ্টার পালায় দুটি ঘটনাই বাস্তব সীমা। এগুলো Google-এর অভিজ্ঞতার সংখ্যা। আপনার দল নিজের সীমা নিজে মাপুন, তবে সীমা একটি রাখুন।

ন্যায্যতা. শুধু সপ্তাহ গুনলে হয় না। ঈদের ছুটি, রাতের page আর শুক্রবার সমান ভারী নয়।

  • ছুটির দিনের পালা গুনে পালা করে দিন, আর মাসে কে কতটি রাতের page পেলেন, সেটি মাপুন।
  • পালা বদলের সময় রাখুন কর্মদিনের মাঝামাঝি, আর হাতবদলে খোলা সমস্যা জানিয়ে দিন।
  • রাত জাগলে পরদিন বিশ্রাম, আর on-call-এর ক্ষতিপূরণ (টাকা বা ছুটি) আগে থেকে লেখা থাকুক।
  • নতুন সদস্য প্রথমে অভিজ্ঞ কারও ছায়া হয়ে থাকুন। মিথ্যা বীরত্ব নয়, ডাকতে পারাই নিয়ম।
  • দুটি সময়-অঞ্চলে দল থাকলে follow-the-sun সূচি রাতের পালা প্রায় মুছে দেয়। একই বইয়ে দুই সাইটের দলের জন্য প্রতি সাইটে ন্যূনতম ৬ জনের কথা আছে।

৮ জনের কম দল হলে কী করবেন? সাড়া দেওয়ার প্রতিশ্রুতি ঢিলে করুন, page শুধু দিনের নির্দিষ্ট সময়ে রাখুন, অথবা কয়েকটি দল মিলে একটি rota বানান। ছোট দলের জন্য কঠিন সত্য হলো, ৯৯.৯৯% SLO-র দাম মানুষের ঘুম দিয়েও দিতে হয়। SLO ঠিক করার সময় এই দামও হিসাবে আনুন।

Paging tool যা করে

Alertmanager জানে কোন alert কোথায় পাঠাতে হবে, কিন্তু ফোন করে না। সেই কাজ করে paging tool: যেমন PagerDuty, Grafana-র on-call পণ্য, বা cloud-এর নিজের পথ (AWS CloudWatch alarm → SNS, Azure Monitor → action group, Google Cloud Monitoring → notification channel). পণ্য আর দাম বদলায়, তাই নাম নয়, ধারণা মনে রাখুন:

  • Schedule: এই মুহূর্তে কে on-call, তার সূচি ও সাময়িক বদল।
  • Acknowledge: মানুষ সাড়া দিলে ডাক বন্ধ হয়। সাড়া দিতে গড়ে যে সময় লাগে, তা MTTA.
  • Escalation policy: ৫ মিনিটে সাড়া না পেলে secondary, তারপর দলনেতা।
  • একাধিক পথ: App, SMS, ফোন কল। একটি পথ কাজ না করলেও ডাক পৌঁছানো চাই।

Monitoring নিজেও থামতে পারে। তাই একটি সবসময় firing থাকা “Watchdog” alert বাইরের একটি সেবায় পাঠানো হয়। সেটি থেমে গেলে বাইরের সেবা আপনাকে ডাকে। একে বলে dead man's switch.

পরীক্ষা ও ইন্টারভিউতে:

  • SLI, SLO, SLA-র পার্থক্য? — মাপ, অভ্যন্তরীণ লক্ষ্য, ফল-সহ চুক্তি। SLO সাধারণত SLA-র চেয়ে কড়া।
  • SLO ৯৯.৯%, error ০.৩% হলে burn rate? — ০.০০৩ ÷ ০.০০১ = ৩; budget ১০ দিনে শেষ।
  • Burn ১৪.৪ এক ঘণ্টায় কত budget খায়? — ১৪.৪ × ১ ÷ ৭২০ = ২%.
  • ছোট জানালা কেন? — সমস্যা মিটলে alert দ্রুত থামাতে, অর্থাৎ reset time কমাতে।
  • Silence আর inhibition-এর পার্থক্য? — Silence মানুষ সময় ধরে বসান; inhibition নিয়ম মেনে বড় alert ছোটটিকে চাপে।

১০ · AI-এর যুগে — alert আর SLO-র নকশা যাচাই

AI কয়েক সেকেন্ডে PromQL আর rule ফাইল লিখে দেয়। সমস্যা হলো, সে আপনার traffic, SLO বা রাতের page-এর সংখ্যা জানে না। Syntax ঠিক থাকলেও alert ভুল হতে পারে, আর সেই ভুল ধরা পড়ে রাত ৩টায় বা বিভ্রাটের নীরবতায়।

AI-এর সাধারণ ভুলকেন বিপজ্জনকযাচাই
CPU বা memory-তে pageকারণে alert, noise বাড়েজিজ্ঞেস করুন: ব্যবহারকারী কি কষ্ট পাচ্ছেন?
Route-গুলোর ratio-র গড়কম traffic-এর route ওজন পায়আগে sum, পরে ভাগ
Burn সীমাকে (১ − SLO) দিয়ে গুণ করতে ভুলAlert কখনো বাজে না, বা সবসময় বাজেহাতে এক লাইন হিসাব করুন
নেই এমন flag বা সেটিংConfig চলে নাpromtool, amtool check-config
latest image tagVersion বদলে আচরণ বদলায়নির্দিষ্ট version লিখুন
Port 0.0.0.0-তে খোলাPrometheus আর Alertmanager-এর UI-তে সাধারণত login থাকে নাভেতরের network, প্রমাণীকরণ
Webhook URL সরাসরি ফাইলেএটি একটি গোপন চাবিSecret manager (পর্ব ৩৩)
সব মেলানো লম্বা silenceআসল বিভ্রাটও চাপা পড়েসরু matcher, ছোট সময়, মন্তব্য

AI-কে rule লিখতে বলার আগে আপনার সংখ্যাগুলো দিন, আর তাকে হিসাব দেখাতে বলুন:

আমার একটি কাল্পনিক অনলাইন বাজারের checkout সেবা আছে। Metric: http_requests_total, label route আর code. SLO ৯৯.৯%, সময়কাল ৩০ দিন, traffic গড়ে ২০ req/s. ১. Workbook-এর multi-window, multi-burn-rate নিয়মে Prometheus rule লেখো: recording rule, page আর ticket. ২. প্রতিটি সীমার জন্য error rate আর budget খরচ হিসাব করে দেখাও। ৩. প্রতিটি alert-এ severity, team আর runbook_url রাখো। ৪. কোন অনুমান করলে সেটি আলাদা করে বলো। কম traffic-এ এই নিয়ম কোথায় ভুল করতে পারে, তাও বলো। ৫. কোনো secret, webhook URL বা আসল ঠিকানা লিখবে না।

AI-এর alert ব্যবহারের আগে

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।

প্র ০১বেশি alert রাখলে তো নিরাপদ থাকার কথা। তবু বেশি alert কেন বিপদ বাড়ায়?

কারণ alert যন্ত্রকে নয়, মানুষকে বার্তা পাঠায়, আর মানুষের মনোযোগ একটি সীমিত সম্পদ। প্রতিবার মিথ্যা ডাকে মস্তিষ্ক শেখে, “এটি সাধারণত কিছু নয়।” সেই অভ্যাস আসল দিনেও কাজ করে।

এই শিক্ষা software-এর চেয়ে পুরোনো। ১৯৭৯ সালে আমেরিকার Three Mile Island পারমাণবিক কেন্দ্রের দুর্ঘটনার তদন্তে একটি বড় বিষয় ছিল alarm-এর বন্যা: শুরুর কয়েক মিনিটে শত শত alarm বাজে, আর অপারেটররা আসল সংকেত আলাদা করতে হিমশিম খান। হাসপাতালেও একই সমস্যা দেখা যায়। আমেরিকার The Joint Commission ২০১৩ সালে চিকিৎসা-যন্ত্রের alarm নিয়ে একটি সতর্কবার্তা প্রকাশ করে। সেখানে alarm fatigue-কে রোগীর নিরাপত্তার ঝুঁকি হিসেবে দেখানো হয়, কারণ অসংখ্য অপ্রয়োজনীয় শব্দে কর্মীরা সাড়া দেওয়া কমিয়ে দেন।

Software দলে এর হিসাবটি সরল। ধরুন precision ৮.৫%. তাহলে প্রতি ১২টি page-এ প্রায় ১টি আসল। রাত ৩টায় এমন একটি ডাক পেলে একজন মানুষ স্বাভাবিকভাবেই ধরে নেন এটিও মিথ্যা, আর ঘুমিয়ে পড়ার ঝুঁকি নেন। ফলে noise শুধু ঘুম নষ্ট করে না, recall-ও কমায়। অথচ alert যোগ করার খরচ কেউ দেখেন না, কারণ সেই খরচ দেন পরের on-call মানুষটি।

আরেকটি ফাঁদ হলো ভয় থেকে জন্মানো alert. প্রতিটি postmortem-এর পর একটি নতুন alert যোগ হয়, কিন্তু কেউ পুরোনোটি মোছেন না। দুই বছরে সেই তালিকা কেউ আর বোঝেন না। এজন্য ভালো দল alert মুছলেও উদযাপন করে, যেমন ভালো সম্পাদক লেখা কাটেন। Alert যোগ করার সময় একটি প্রশ্ন জিজ্ঞেস করুন: “এটি বাজলে আপনি ঠিক কী করবেন?” উত্তর না থাকলে সেটি page নয়।

মূল উপলব্ধি: সুরক্ষা আসে মানুষের সাড়া থেকে, alert-এর সংখ্যা থেকে নয়। Precision কমলে শেষ পর্যন্ত recall-ও কমে।

প্র ০২১৪.৪ সংখ্যাটি কোথা থেকে এলো? সব দল কি একই সংখ্যা ব্যবহার করবে?

১৪.৪ কোনো প্রাকৃতিক ধ্রুবক নয়। এটি একটি সিদ্ধান্তের গাণিতিক রূপ। Google-এর Workbook প্রশ্ন করে: এক ঘণ্টায় মাসিক budget-এর কত অংশ গেলে মানুষকে ডাকা উচিত? উত্তর হিসেবে ২% ধরা হয়েছে। তাহলে burn = ০.০২ × ৭২০ ÷ ১ = ১৪.৪. একই পথে ৬ ঘণ্টায় ৫% থেকে ৬, আর ৩ দিনে ১০% থেকে ১ আসে।

২% কেন? কারণ ধরা পড়ার পর মানুষের সাড়া দিতে আর সমস্যা মেটাতে সময় লাগে। এই গতিতে ২.০৮ দিনে budget শেষ হবে, তাই on-call-এর হাতে সময় থাকে। ৫০% ধরলে alert এত দেরিতে বাজত যে budget প্রায় শেষ হয়ে যেত। ০.১% ধরলে ছোট ঝাঁকুনিতেও ফোন বাজত।

তিনটি পরিস্থিতিতে এই সংখ্যা বদলাতে হয়। প্রথমত, ৩০ দিনের সময়কাল না হলে: ২৮ দিনের সময়কালে ১ ঘণ্টায় ২%-এর burn হয় ০.০২ × ৬৭২ = ১৩.৪৪. দ্বিতীয়ত, কড়া SLO-তে: ৯৯.৯৯% SLO-তে budget এত ছোট যে পূর্ণ বিভ্রাটে ৪.৩২ মিনিটেই শেষ; একটি ৫ মিনিটের page পৌঁছানোর আগেই budget নেই। Workbook ৯৯.৯৯৯%-এর উদাহরণে (budget ২৬ সেকেন্ডে শেষ) বলে, এমন লক্ষ্য alert দিয়ে রক্ষা করা যায় না; নকশাতেই পূর্ণ বিভ্রাটের সম্ভাবনা খুব কমাতে হয়, যেমন canary দিয়ে। তৃতীয়ত, কম traffic-এ: মিনিটে ২০টি অনুরোধ হলে একটি ব্যর্থতাই ৫% error, ৯৯.৯% SLO-তে burn ৫০. সেখানে নকল traffic বা অনুরোধ-গণনার সীমা দরকার।

তা ছাড়া দলের ক্ষমতাও বিষয়। দিনে ১২ ঘণ্টার on-call হলে রাতের নিয়ম ভিন্ন হতে পারে। তাই সংখ্যা ধার করুন শুরুর জন্য, তারপর নিজের ইতিহাসে backtest করে precision আর detection time দেখে বদলান।

মূল উপলব্ধি: মুখস্থ করার জিনিস ১৪.৪ নয়, সূত্রটি। সংখ্যাটি একটি নীতির ফল: কত ক্ষতি হলে আমরা মানুষকে ডাকব।

প্র ০৩SLO পূরণ হওয়ার পরও সেবা ইচ্ছা করে ভাঙা হয়েছে, এমন ইতিহাস আছে। কেন কেউ এমন করবে?

Google-এর SRE বইয়ের একটি বিখ্যাত গল্প Chubby নিয়ে। Chubby হলো তাদের একটি distributed lock সেবা। বই অনুযায়ী এটি এত ভালো চলত যে এর ব্যবহারকারী দলগুলো ধরে নিতে শুরু করে Chubby কখনো ব্যর্থ হবে না। ফলে নকশায় এমন নির্ভরতা ঢুকে যায়, যা বিরল বিভ্রাটে বড় সমস্যা তৈরি করত। সমাধান হিসেবে কোনো ত্রৈমাসিকে আসল বিভ্রাটে availability লক্ষ্যের নিচে না নামলে SRE দল ইচ্ছা করে নিয়ন্ত্রিতভাবে সেবা বন্ধ রাখত, যাতে নির্ভরশীল দলগুলো ত্রুটি আগেই খুঁজে পায়।

এর পেছনের নীতিটি শুনতে অদ্ভুত, কিন্তু যুক্তিসম্মত। SLO শুধু নিচের সীমা নয়, এটি একটি প্রত্যাশা। সেবা ধারাবাহিকভাবে ৯৯.৯৯% চললে, ব্যবহারকারীর আচরণ সেই ৯৯.৯৯%-এর ওপরই দাঁড়িয়ে যায়, লিখিত ৯৯.৯% যা-ই হোক। এখানে Hyrum-এর সূত্রের ছায়া আছে: যথেষ্ট ব্যবহারকারী থাকলে সিস্টেমের প্রতিটি লক্ষণীয় আচরণের ওপরই কেউ নির্ভর করবেন।

এই গল্প SLA আর SLO-র সম্পর্কও পরিষ্কার করে। SLA ভাঙলে টাকা যায়, তাই SLA-র চেয়ে কড়া SLO রাখা হয়। আবার SLO-র চেয়ে অনেক ভালো চললে budget অব্যবহৃত থেকে যায়, মানে নতুন feature আর পরীক্ষার ঝুঁকি কম নেওয়া হচ্ছে। Error budget তাই খরচ করার জন্যই। অতিরিক্ত নির্ভরযোগ্যতার একটি দাম আছে: গতি কমে, আর অন্য দল ভুল ভরসা শেখে।

আপনার দলে Chubby-র মতো ইচ্ছাকৃত বন্ধ করার দরকার সবসময় হবে না। তার ছোট রূপ হলো নিরাপদ পরিবেশে SLI পর্যবেক্ষণ করে নির্ভরতা ভেঙে দেখা, যা পর্ব ৬৮-এর chaos engineering-এর বিষয়। অন্তত প্রতিটি নির্ভরতার জন্য জেনে রাখুন, সেটি থেমে গেলে আপনার সেবা কী করবে।

মূল উপলব্ধি: ব্যবহারকারী লেখা SLO-তে নয়, দেখা আচরণে ভরসা করেন। নির্ভরযোগ্যতার লক্ষ্য হলো “যথেষ্ট ভালো”, “যত ভালো সম্ভব” নয়।

প্র ০৪On-call কার করা উচিত: যাঁরা কোড লেখেন, নাকি আলাদা operations দল?

২০০৬ সালে ACM Queue-র একটি সাক্ষাৎকারে Amazon-এর CTO Werner Vogels বলেন, “You build it, you run it.” যুক্তিটি হলো, যিনি নিজের কোডের রাতের ডাক পান, তিনি লগ, retry আর ত্রুটি-সহনশীলতা নিয়ে ভিন্নভাবে ভাবেন। Feedback সরাসরি লেখকের কাছে পৌঁছায়। DevOps-এর দেয়াল ভাঙার এটি একটি বাস্তব রূপ, যা পর্ব ৭-এ দেখেছেন।

কিন্তু এর দাম আছে। সব ডেভেলপার রাতের দায়িত্ব নিতে পারেন না বা চান না। ছোট দলে পালা ঘন ঘন আসে। Feature-এর চাপ আর on-call একসাথে এলে ক্লান্তি বাড়ে, আর ক্লান্ত মানুষ বেশি ভুল করেন। অন্য দিকে আলাদা ops দলকে on-call দিলে পুরোনো দেয়াল ফেরে: যাঁরা কষ্ট পান তাঁরা কোড বদলাতে পারেন না, আর যাঁরা বদলাতে পারেন তাঁরা কষ্ট পান না।

Google-এর SRE মডেল মাঝের একটি পথ। SRE দল on-call নেয়, কিন্তু সময়ের সীমা (ops কাজে সর্বোচ্চ ৫০%, on-call-এ ২৫%) মেনে। সেবা খুব noisy হলে দল ফেরত দিতে পারে ডেভেলপারদের কাছে। অর্থাৎ on-call একটি উপহার নয়, এর একটি মান-শর্ত আছে। Platform দল থাকলে তাদের দায়িত্ব shared platform, আর পণ্য দলের দায়িত্ব নিজের সেবা।

ন্যায্যতার দিকটিও ভাবুন। দলের সবাই সমান পরিস্থিতিতে নেই: কেউ শিশুর দেখাশোনা করেন, কেউ রোজা রাখেন, কারও বাড়ি থেকে ভালো ইন্টারনেট পাওয়া কঠিন। ঢাকার কোনো দল যদি অন্য দেশের গ্রাহক সামলায়, তাহলে তাদের রাতই গ্রাহকের দিন। তাই সূচিতে বিকল্প, অদলবদলের সহজ নিয়ম, ক্ষতিপূরণ আর বিশ্রাম লেখা থাকা দরকার। Workload মাপা না হলে অন্যায্যতা দেখা যায় না।

মূল উপলব্ধি: On-call কে নেবেন, সেটি শুধু প্রযুক্তিগত নয়, একটি সংগঠনগত সিদ্ধান্ত। লক্ষ্য একটাই: যাঁরা ব্যথা পান, তাঁরা যেন সেটি সারানোর ক্ষমতা ও সময়ও পান।

প্র ০৫লক্ষণে alert ঠিক আছে, কিন্তু monitoring নিজেই থেমে গেলে কে জানাবে? নীরবতা কি ভালো খবর?

না। Alert না থাকা দুই কারণে হতে পারে: সব ঠিক আছে, অথবা দেখার ব্যবস্থাটিই বন্ধ। এই পর্বের প্রথম Docker চালনায় ঠিক সেটিই হয়েছিল। App-এ error চলছিল, কিন্তু target down থাকায় Prometheus-এ কোনো মাপ ছিল না, আর alert-এর শর্তের ফল ছিল ফাঁকা। ফাঁকা ফল মানে “শর্ত সত্য নয়”, তাই পুরো নীরবতা। PromQL-এ একটি তুলনা কোনো data না পেলে কিছুই ফেরত দেয় না, আর সেটি শূন্য নয়।

এজন্য তিন স্তরের সুরক্ষা লাগে। প্রথম স্তর: up == 0 এবং absent() দিয়ে “মাপ হারিয়ে গেছে” alert. দ্বিতীয় স্তর: বাইরে থেকে black-box synthetic probe, যা সেবাকে ব্যবহারকারীর মতো দেখে, আর আপনার cluster-এর ভেতরের কিছুর ওপর নির্ভর করে না। তৃতীয় স্তর: dead man's switch. একটি সবসময় firing থাকা alert বাইরের একটি সেবায় নিয়মিত পৌঁছায়; সেটি থামলে বাইরের সেবা ডাকে। অর্থাৎ যুক্তিটি উল্টে দেওয়া হলো: নীরবতাই এখানে alarm.

আরেকটি ফাঁদ হলো monitoring-এর নিজের নির্ভরতা। একই region-এ Prometheus, একই network-এ Alertmanager, একই cloud-এ paging: region বন্ধ হলে সতর্কের ব্যবস্থাও বন্ধ। ২০১৭ সালের ফেব্রুয়ারিতে Amazon S3-র বিভ্রাটের পর AWS জানিয়েছিল, তাদের status dashboard-ই S3-র ওপর নির্ভরশীল ছিল বলে ঠিকমতো হালনাগাদ করা যায়নি। সেবার হাল জানানোর ব্যবস্থা যে সেবার ওপরই দাঁড়িয়ে, সেটি ব্যর্থ হলে দুটোই পড়ে।

Alertmanager-কে অনেক সময় কয়েকটি copy-তে cluster করে চালানো হয়, যাতে একটি থামলেও বার্তা যায়। Paging tool-ও আলাদা জায়গায় থাকা ভালো। মাঝে মাঝে পরীক্ষা করে দেখুন, একটি নকল alert সত্যিই ফোন পর্যন্ত পৌঁছায় কি না।

মূল উপলব্ধি: Monitoring-ও একটি production সেবা, যা ব্যর্থ হতে পারে। তাই প্রশ্ন শুধু “alert বেজেছে কি?” নয়, “বাজার মতো অবস্থায় আছে কি?”

অনুশীলন

খাতায় হিসাব করুন, তারপর উত্তর মেলান।

  1. হিসাব: SLO ৯৯.৯৫%, সময়কাল ৩০ দিন। ৪০ মিনিটের একটি ঘটনায় error rate ছিল ২%. (ক) Burn rate কত? (খ) কত budget খরচ হলো? (গ) ১ ঘণ্টার ১৪.৪ নিয়ম বাজবে কি? বাজলে ফাঁকা জানালা থেকে কত মিনিটে? (ঘ) পূর্ণ বিভ্রাটের কত মিনিট বাকি রইল?

    (ক) ০.০২ ÷ ০.০০০৫ = ৪০. (খ) ৪০ × ৪০ ÷ ৪৩,২০০ = ০.০৩৭০৪, মানে ৩.৭০%. (গ) ৪০ > ১৪.৪, আর সীমার সময় ৬০ × ১৪.৪ ÷ ৪০ = ২১.৬ মিনিট, যা ঘটনার ৪০ মিনিটের মধ্যে, তাই বাজবে। (ঘ) পুরো budget ০.০০০৫ × ৪৩,২০০ = ২১.৬ মিনিট; বাকি ৯৬.৩০% মানে প্রায় ২০.৮ মিনিট.

  2. ফল অনুমান করুন: Alert rule-এ for: 2m, evaluation interval ৩০ সেকেন্ড, Alertmanager-এ group_wait: 30s. শর্তটি ১০:০০:০০ থেকে ১০:০১:৩০ পর্যন্ত সত্য, ১০:০২:০০-এ মিথ্যা, ১০:০৩:০০ থেকে টানা সত্য। প্রতি ধাপে alert-এর অবস্থা কী, আর প্রথম বার্তা মোটামুটি কখন যাবে? ধরুন evaluation ঠিক এই সময়গুলোতে হয়, আর এই একটি alert-ই আছে।

    ১০:০০:০০ pending. ১০:০১:৩০ পর্যন্ত এখনো pending, কারণ ২ মিনিট পূর্ণ হয়নি। ১০:০২:০০-এ শর্ত মিথ্যা, তাই alert inactive, আর টাইমার মুছে যায়। ১০:০৩:০০-এ আবার pending, ঘড়ি নতুন করে শুরু। ১০:০৫:০০-এ firing, Alertmanager পায়। নতুন group, তাই group_wait-এর পরে প্রথম বার্তা, মোটামুটি ১০:০৫:৩০. প্রথম ১ মিনিট ৩০ সেকেন্ডের সমস্যায় কোনো বার্তাই যায়নি।

  3. সমালোচনা করুন: একটি দলের alert: expr: node_cpu_usage > 80, for: 1m, severity: critical, সব বার্তা ১২ জনের একটি ফোন-তালিকায়, runbook নেই, মালিক “সবাই”। অন্তত পাঁচটি সমস্যা বলুন, আর একটি ভালো বিকল্প লিখুন।
    • CPU একটি কারণ, লক্ষণ নয়। ৮০% CPU-তে ব্যবহারকারী হয়তো ভালোই আছেন।
    • ১ মিনিট খুব ছোট; একটি batch job-এই বাজবে, precision কমবে।
    • “সবাই” মালিক মানে কেউ মালিক নয়। ১২ জনে বার্তা গেলে সবাই ভাবেন অন্য কেউ দেখছেন।
    • Runbook নেই, তাই রাতে কী করতে হবে কেউ জানেন না।
    • Instance-প্রতি alert: ৫০টি node-এ ৫০টি বার্তা, grouping নেই।

    বিকল্প: CPU dashboard-এ বা autoscaling-এর সংকেতে যাক। Page হোক সেবার SLO-র burn rate-এ, দুই জানালায়, team label আর runbook_url সহ, on-call-এর একজনের কাছে, escalation সহ।

  4. নকশা করুন: ঢাকায় ৬ জনের একটি দল ২৪ ঘণ্টা সেবা চালায়, SLO ৯৯.৯%. একটি ন্যায্য on-call সূচি লিখুন: পালার দৈর্ঘ্য, primary আর secondary, ঈদের সপ্তাহ, রাতের page-এর সীমা আর পরিমাপ। তারপর একটি পরিকল্পিত ২ ঘণ্টার database কাজের জন্য payments সেবার alert চাপা দেওয়ার amtool কমান্ডটি লিখুন।

    একটি যুক্তিসঙ্গত উত্তর, একমাত্র নয়: সাপ্তাহিক পালা, বদল বুধবার দুপুরে। Primary আর secondary মিলে একজনের ভাগ ২ ÷ ৬ = ৩৩.৩%, যা ২৫%-এর ওপরে, তাই দল বড় করার পরিকল্পনা বা পাশের দলের সাথে যৌথ secondary রাখুন। ঈদের সপ্তাহ আগে থেকে লটারি বা পালা করে ঠিক করুন, আর মাসে কে কত ছুটির পালা পেলেন লিখে রাখুন। ১২ ঘণ্টার পালায় ২টি ঘটনার বেশি হলে দলনেতা noise-এর কাজকে অগ্রাধিকার দেবেন। রাত জাগলে পরদিন দেরিতে শুরু। মাসিক হিসাবে দেখুন: page-এর সংখ্যা, রাতের page, precision, MTTA.

    amtool silence add service=payments \
      --duration=2h --author=rafi \
      --comment="planned database upgrade" \
      --alertmanager.url=http://localhost:9093

    Matcher সরু রাখুন, সময় কাজের সমান রাখুন, আর কারণ লিখুন। কাজ শেষ হলে silence নিজে থেকে শেষ হবে, অথবা amtool silence expire দিয়ে আগেই বন্ধ করুন।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রমএকটি alert-এর জীবনের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. Prometheus metric scrape করে আর rule-এর শর্ত যাচাই করে
  2. শর্ত সত্য হয়, alert pending হয়
  3. for-এর সময় পার হয়, alert firing হয়
  4. Alertmanager group_wait পর্যন্ত অপেক্ষা করে group বানায়
  5. On-call runbook-এর লিংকসহ page পান আর acknowledge করেন
  6. সমস্যা মেটে, resolved বার্তা যায়

একটি সেবার SLO ৯৯.৯%. এখন error rate ০.৩%. Burn rate কত?

  • ০.৩
  • ১
  • ৩
  • ৩০

SLO-র সময়কাল ৩০ দিন। Burn rate ৬ টানা ৬ ঘণ্টা চললে budget-এর কত অংশ খরচ হয়?

  • ২%
  • ৫%
  • ১০%
  • ৩৬%

SLI, SLO আর SLA-র মধ্যে কোনটি ভাঙলে সাধারণত টাকা ফেরত বা চুক্তিগত ফল হয়?

  • SLI
  • SLO
  • Error budget
  • SLA

Multi-window burn-rate alert-এ ৫ মিনিটের ছোট জানালাটির প্রধান কাজ কী?

  • সমস্যা মিটলে alert দ্রুত থামানো, অর্থাৎ reset time কমানো
  • Alert-কে লম্বা জানালার আগেই বাজানো
  • বিভ্রাটটি যথেষ্ট বড় কি না প্রমাণ করা
  • Metric জমার খরচ কমানো

এক মাসে একটি alert ৪০ বার বেজেছে, তার ১০ বার সত্যিই ঘটনা ছিল। একই মাসে ১২টি গুরুত্বপূর্ণ ঘটনার ১০টি এটি ধরেছে। Precision আর recall কত?

  • Precision ৮৩%, recall ২৫%
  • দুটিই ২৫%
  • Precision ২৫%, recall ৮৩%
  • Precision ২৫%, recall ১০০%

রাত ১১টা থেকে ২ ঘণ্টার পরিকল্পিত কাজে একটি সেবার alert চাপা রাখতে হবে। Alertmanager-এ কোনটি সবচেয়ে উপযুক্ত?

  • Alert rule মুছে দেওয়া
  • একটি সরু matcher দিয়ে ২ ঘণ্টার silence
  • স্থায়ী inhibition নিয়ম
  • repeat_interval বাড়িয়ে দেওয়া

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. SLI মাপ, SLO লক্ষ্য, SLA চুক্তি. SLI বাছুন ব্যবহারকারীর কাজ ধরে: ভালো ঘটনা ÷ বৈধ ঘটনা।
  2. Page হবে লক্ষণে। কারণের সংকেত dashboard-এ, আর প্রতিটি alert-এ মালিক ও runbook.
  3. burn rate = error rate ÷ (১ − SLO); খরচ = burn rate × জানালা ÷ সময়কাল।
  4. ১৪.৪, ৬, ১ আসে ২%, ৫%, ১০% থেকে। লম্বা জানালা ক্ষতি নিশ্চিত করে, ছোট জানালা alert থামায়।
  5. Alert-এর মান মাপুন: precision, recall, detection আর reset time; on-call-এ ২৫% আর ১২ ঘণ্টায় ২টি ঘটনা একটি ভালো শুরুর সীমা।

পরের পর্বে: Page এসেছে। এখন কী? কে নেতৃত্ব দেবেন, কে কথা বলবেন, severity কীভাবে ঠিক হয়, আর postmortem কীভাবে দোষ না খুঁজে শেখায়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান