Part 03 · High Level Design

Observability: Logs, Metrics and Traces

LogsMetricsTracesSLO alertsHealth checks

User বলার আগেই জেনে যাওয়া যে কিছু ভেঙেছে: structured log, কাজের metric, distributed trace, CPU না দেখে SLO দেখে alert, আর এমন health check যেটার উপর load balancer ভরসা করতে পারে।

⏱ 2-3 ঘণ্টা · Station 31 / 80

Customer রা আগে জানল

একটা online pharmacy র on-call phone সারারাত বাজে: "CPU 80% এর উপরে", "CPU 80% এর উপরে", "disk 75% ভরা"। Engineer প্রতিবার দেখে, user দের কোনো সমস্যা পায় না, আবার ঘুমিয়ে পড়ে। কয়েক সপ্তাহ পর ওই alert গুলো আর কেউ মন দিয়ে পড়ে না।

তারপর এক বৃহস্পতিবার বিকেলে 1.5% checkout fail করতে শুরু করল, কারণ নতুন একটা fraud-check rule timeout হচ্ছে। CPU কম, কারণ fail করা request সস্তা। Disk ঠিক আছে। একটাও alert বাজল না। Team জানল দুই ঘণ্টা পর, রাগী Facebook post থেকে। Dashboard এর গড় latency স্বাভাবিক দেখাচ্ছে, কারণ 98.5% request দ্রুত। আর যখন শেষ পর্যন্ত খুঁজতে বসল, log হলো বারোটা service এর free-text line, কোন line গুলো একই customer এর checkout এর সেটা বোঝার কোনো উপায় নেই।

Data এর অভাব ছিল না, তবু গুরুত্বপূর্ণ দুইটা প্রশ্নের উত্তর দিতে পারল না: এই মুহূর্তে কি user দের ক্ষতি হচ্ছে, আর ঠিক কোথায় ভাঙছে? এটাই observability: বাইরে থেকে তোমার system কী করছে সেটা এত দ্রুত বুঝতে পারা যাতে ব্যবস্থা নেওয়া যায়। এই chapter এ আছে তিনটা signal (log, metric, trace), গড় কেন মিথ্যা বলে, CPU না দেখে SLO দেখে alert, আর এমন health check যেটার উপর load balancer ভরসা করতে পারে।

সমস্যা: অনেক data, কোনো উত্তর নেই

কী হয়কেন
Team এর আগে user রা সমস্যা টের পায়Alert machine এর resource দেখে, user এর অভিজ্ঞতা না
On-call alert উপেক্ষা করেএত alert যেগুলোয় কিছু করার নেই (alert fatigue)
"Latency ঠিক আছে" অথচ কিছু user কয়েক সেকেন্ড অপেক্ষা করেগড় slow tail লুকিয়ে রাখে; কেউ p99 দেখে না
Service জুড়ে একটা request কেউ অনুসরণ করতে পারে নাকোনো trace ID নেই, distributed tracing নেই
Log খোঁজা slow আর আন্দাজে চলেকাঠামো বা একই রকম field ছাড়া free-text log
Monitoring এর bill ফুলে ওঠেMetric এ high-cardinality label (user ID), প্রতিটা debug log চিরকাল রাখা

হাসপাতালের একটা ward এর কথা ভাবো

Ward এর nurse রোগীর আজকের প্রতিটা কথা পড়ে রোগীকে বোঝেন না। তিনটা হাতিয়ার আছে, প্রত্যেকটা আলাদা প্রশ্নের জন্য।

বিছানার পাশের chart সময়ের সাথে সংখ্যা দেখায়: প্রতি ঘণ্টায় তাপমাত্রা, pulse, রক্তচাপ। এক নজরেই বোঝা যায় সব স্বাভাবিক নাকি ভুল দিকে যাচ্ছে। এগুলো metric: সস্তা, সংক্ষেপ করা, কিছু একটা ভুল সেটা ধরতে আর alarm এর জন্য ভালো।

Note এ লেখা থাকে কী ঘটল, খুঁটিনাটি সহ: "১৪:২০, রোগী বুকে ব্যথার কথা বললেন, aspirin দেওয়া হলো"। এগুলো log: আলাদা আলাদা ঘটনার বিস্তারিত, কোথায় দেখতে হবে জানার পর অপরিহার্য।

রোগীকে X-ray, lab আর surgery ঘুরিয়ে নেওয়ার সময় case file প্রতিটা বিভাগে সময় লিখে রোগীর সাথে চলে, তাই দেখা যায় ছয় ঘণ্টার চার ঘণ্টাই গেছে একটা lab এর ফলের জন্য অপেক্ষায়। এটা trace: অনেক service এর মধ্য দিয়ে একটা request এর যাত্রা, সময় কোথায় গেল দেখায়।

আর যে alarm ডাক্তারকে ঘুম থেকে তোলে সেটা রোগীর অবস্থার সাথে বাঁধা ("oxygen 90% এর নিচে"), monitor এর processor কতটা ব্যস্ত তার সাথে না। এটাই SLO দিয়ে লক্ষণ দেখে alert।

RequestGET /checkoutServicetrace 7f3aLogswhat happened, in detailMetricshow often, how slowTraceswhere the time wentreq{level, msg, trace_id}count+1, 420 ms5 spanslogs, metrics and traces answer different questions; the trace ID ties them together
Play চাপো। একটা request service এ পৌঁছায়। Service একটা structured log line লেখে, একটা request counter আর একটা latency histogram বাড়ায়, আর পাঁচটা span রেকর্ড করে। তিনটাতেই একই trace ID থাকে, পরে এটাই তাদের জুড়ে দেয়।

তবে একটা জায়গায় মেলে না। Nurse রোগীকে দেখতে পারেন। চলমান একটা system এর ভেতরে তুমি দেখতে পারো না; শুধু সেটুকুই দেখো যেটা জানানোর জন্য সেটা বানানো। Observability incident এর আগেই design এ রাখতে হয়, incident এর সময় যোগ করা যায় না।

আগে অনুমান করো

1,000টা request: 980টায় 50 থেকে 100 ms লাগে আর 20টায় 2 সেকেন্ড। Dashboard এর কোন সংখ্যা সমস্যাটা দেখায়?

Observability র পেছনের নিয়মগুলো

  1. Metric হলো সময়ের সাথে সংখ্যা, একত্র করা আর রাখতে সস্তা: request এর হার, error এর হার, latency র বিন্যাস (service এর জন্য RED method), আর resource এর জন্য utilisation, saturation আর error (USE method)। Dashboard আর alert এগুলোর উপর চলে।
  2. গড় না, percentile দেখো। Latency কে histogram হিসেবে রেকর্ড করো আর p50, p95 আর p99 দেখো। User রা বিরক্ত হয় tail এ, আর অনেক call করে এমন একটা page এ একটা slow call পুরো page কে slow করে দেয়।
  3. Log হলো খুঁটিনাটি সহ ঘটনা। Structured ভাবে লেখো (একই রকম field সহ JSON: timestamp, level, service, trace ID, user বা order ID, message), যাতে grep না করে filter আর group করতে পারো। Incident এ যা লাগবে সেটা log করো; production এ হইচই করা debug log sample করো বা বাদ দাও।
  4. Trace service জুড়ে একটা request অনুসরণ করে। প্রতিটা request একটা trace ID পায়, header এ পাঠানো হয় (W3C traceparent); প্রতিটা কাজের একক একটা span, শুরু, সময়কাল আর একটা parent সহ। Trace ঠিক দেখায় কোন call slow বা fail ছিল। খরচ নিয়ন্ত্রণে trace sample করো (ধরো 1 থেকে 10%, আর সব error আর slow গুলো রেখে দাও)।
  5. তিনটাকে জুড়ে দাও। প্রতিটা log line এ trace ID রাখো আর exemplar সহ metric ব্যবহার করো, যাতে "p99 লাফিয়েছে" থেকে একটা উদাহরণ trace এ, সেখান থেকে ঠিক ওই request এর log এ যেতে পারো।
  6. কারণ না, user যে লক্ষণ টের পায় তার উপর alert দাও। SLO ভাঙলে page করো: আসল request এর error rate আর latency। বেশি CPU, ভরা queue বা একটা মরা instance dashboard আর ticket এ দেখার জিনিস, মানুষকে জাগানোর না, যদি না সেগুলো user এর ক্ষতি করতে যাচ্ছে।
  7. Error-budget এর burn rate ব্যবহার করো। SLO যদি মাসে 0.1% error দেয়, burn rate 1 মানে budget ঠিক মাস জুড়ে খরচ হবে। Page করো যখন ছোট window এ burn বেশি (যেমন এক ঘণ্টা ধরে 14.4x, যেটা মাসের budget এর 2% পুড়িয়ে ফেলে), আর ticket দাও যখন long window এ মাঝারি (যেমন তিন দিন ধরে 1x)। বড় আগুনে দ্রুত, ছোটখাটোতে চুপ।
  8. প্রতিটা alert এ কিছু করার থাকতে হবে। একজন owner, একটা runbook এর link আর স্পষ্ট "কী করতে হবে" লাগে। কোনো alert নিয়মিত বাজলে আর কেউ কিছু না করলে, ঠিক করো বা মুছে ফেলো।
  9. Health check: liveness বনাম readiness। Liveness উত্তর দেয় "process কি আটকে গেছে? restart দাও"। Readiness উত্তর দেয় "এখন কি traffic নিতে পারবে?" (dependency তে পৌঁছানো যায়, warm up হয়েছে)। Load balancer readiness ব্যবহার করে। দুইটাই হালকা রাখো, আর liveness কে অন্য service এর উপর নির্ভরশীল কোরো না, নাহলে database এর একটা ঝাঁকুনিতে প্রতিটা pod restart হবে।
errors > 14.4x budgetCPU > 80%hour 10.05%85%hour 20.08%88%hour 31.50%40%hour 41.60%35%hour 50.20%60%hour 60.06%82%CPU alerts: hours 1, 2, 6, when every user was fineburn-rate pages: hours 3 and 4, when 1 in 65 requests failedalert on what users feel, not on what machines feel
Play চাপো। ছয় ঘণ্টা পাশাপাশি। CPU alert বাজে ঘণ্টা 1, 2 আর 6 এ, যখন প্রতিটা user ঠিক ছিল, আর চুপ থাকে ঘণ্টা 3 আর 4 এ, যখন 1.5% request fail করছিল। Error-budget burn alert page করে ঠিক ঘণ্টা 3 আর 4 এ।

Page থেকে কারণ পর্যন্ত একটা incident

ধাপে ধাপে দেখো

Team কীভাবে দশ মিনিটে fail করা fraud check খুঁজে পায়

SLO alertDashboardTraceLogFix

ধাপ 1/5 Burn-rate alert page করে

গত এক ঘণ্টায় checkout এর error rate 1.5%, 99.9% SLO এর বিপরীতে burn rate 15x। Alert service এর নাম বলে আর runbook এর link দেয়।

SLO
99.9% checkout সফল
burn
15x
page
14:07

ধাপে ধাপে একটা service কে observable বানানো

  1. User যা করে তার জন্য SLI আর SLO ঠিক করো: "30 দিনে 99.9% request এ checkout 1 s এর মধ্যে সফল হয়"।
  2. প্রতি endpoint এ RED metric দাও (হার, error, histogram হিসেবে সময়) আর গুরুত্বপূর্ণ resource এর জন্য USE metric।
  3. Structured log লেখো, trace ID আর যে business ID দিয়ে খুঁজবে সেগুলো সহ।
  4. OpenTelemetry দিয়ে tracing যোগ করো: HTTP, gRPC আর message header দিয়ে context পাঠাও।
  5. প্রতি service এ একটা dashboard বানাও, যেটা শুরু হয় SLO দিয়ে, তারপর RED, তারপর dependency।
  6. Burn rate এ alert দাও (দ্রুত আর ধীর window); বাকি signal ticket বা dashboard এ পাঠাও।
  7. প্রতিটা page এর জন্য একটা runbook লেখো, আর প্রতিটা incident এর পর alert গুলো পর্যালোচনা করো।

নিজে বলো: কাজের signal নাকি হইচই?

প্রতিটা case চালিয়ে দেখো

Incident এর সময় এটা কি কাজে আসবে?

1.5% checkout fail করলে 14:07 এ বাজে; বাকি সময় চুপ
কাজ করে: কাজের। User যা টের পায় তার সাথে বাঁধা, গুরুতর সমস্যায় দ্রুত, হইচইতে চুপ।

চালিয়ে দেখার মতো percentile, trace আর burn rate

তিনটা অংশ। এক হাজার request এর latency, যার 2% একটা slow পথে পড়ে, গড় আর percentile দিয়ে সংক্ষেপ করা। একটা slow checkout span এর tree হিসেবে, indentation সহ print করা, আর সবচেয়ে বেশি সময় নেওয়া span খুঁজে বের করা। আর ছয় ঘণ্টার error rate আর CPU, 99.9% SLO এর জন্য একটা CPU alert আর একটা error-budget burn-rate alert মিলিয়ে দেখা। প্রতিটা language integer ব্যবহার করে আর একই output দেয়।

package main

import (
	"fmt"
	"sort"
	"strings"
)

// 1. Latency: 1,000 requests. Most take 50-100 ms; 2% hit a slow path and take 2 s.
func latency() {
	lat := make([]int, 1000)
	sum := 0
	for i := range lat {
		lat[i] = 50 + i*37%51
		if i%50 == 7 {
			lat[i] = 2000
		}
		sum += lat[i]
	}
	sort.Ints(lat)
	fmt.Println("1,000 requests, 2% of them hit a slow path:")
	fmt.Printf("  average %d ms, p50 %d ms, p95 %d ms, p99 %d ms, max %d ms\n", sum/1000, lat[499], lat[949], lat[989], lat[999])
}

// 2. A trace: one request as a tree of timed spans.
type span struct {
	name     string
	ms       int
	children []span
}

func printSpan(s span, depth int, slowest *span) {
	fmt.Printf("  %s%-*s %4d ms\n", strings.Repeat("  ", depth), 22-2*depth, s.name, s.ms)
	if len(s.children) == 0 && s.ms > slowest.ms {
		*slowest = s
	}
	for _, c := range s.children {
		printSpan(c, depth+1, slowest)
	}
}

func trace() {
	root := span{"GET /checkout", 420, []span{
		{"auth", 12, nil},
		{"load cart (db)", 40, nil},
		{"payment", 330, []span{
			{"fraud check", 280, nil},
			{"charge card", 45, nil},
		}},
		{"render", 30, nil},
	}}
	fmt.Println("trace of one slow checkout:")
	slowest := span{}
	printSpan(root, 0, &slowest)
	fmt.Printf("  most of the time: %s, %d ms of %d (%d%%)\n", slowest.name, slowest.ms, root.ms, slowest.ms*100/root.ms)
}

// 3. Alerts. SLO: 99.9% of requests succeed over 30 days, so the error budget is 0.1%.
// Error rates are in hundredths of a percent (150 = 1.50%).
func alerts() {
	errs := []int{5, 8, 150, 160, 20, 6}
	cpu := []int{85, 88, 40, 35, 60, 82}
	const budget = 10 // 0.10% in hundredths of a percent
	fmt.Println("six hours of errors and CPU; SLO 99.9% (budget 0.1%):")
	used := 0
	for h := range errs {
		burn := errs[h] * 10 / budget // tenths: 150 -> 150 (15.0x the allowed rate)
		page := "-"
		if burn >= 144 { // 14.4x for an hour = 2% of the month's budget gone
			page = "PAGE"
		}
		cpuAlert := "-"
		if cpu[h] > 80 {
			cpuAlert = "alert"
		}
		fmt.Printf("  hour %d: errors %d.%02d%%, burn %2d.%dx -> %-4s | CPU %d%% -> %s\n",
			h+1, errs[h]/100, errs[h]%100, burn/10, burn%10, page, cpu[h], cpuAlert)
		used += errs[h]
	}
	month := budget * 30 * 24 // the whole month's budget, in the same units
	fmt.Printf("  error budget used in these 6 hours: %d.%d%% of the month's\n", used*1000/month/10, used*1000/month%10)
}

func main() {
	latency()
	trace()
	alerts()
}

ছয়টাই হুবহু এটা print করে:

1,000 requests, 2% of them hit a slow path:
  average 113 ms, p50 76 ms, p95 99 ms, p99 2000 ms, max 2000 ms
trace of one slow checkout:
  GET /checkout           420 ms
    auth                   12 ms
    load cart (db)         40 ms
    payment               330 ms
      fraud check         280 ms
      charge card          45 ms
    render                 30 ms
  most of the time: fraud check, 280 ms of 420 (66%)
six hours of errors and CPU; SLO 99.9% (budget 0.1%):
  hour 1: errors 0.05%, burn  0.5x -> -    | CPU 85% -> alert
  hour 2: errors 0.08%, burn  0.8x -> -    | CPU 88% -> alert
  hour 3: errors 1.50%, burn 15.0x -> PAGE | CPU 40% -> -
  hour 4: errors 1.60%, burn 16.0x -> PAGE | CPU 35% -> -
  hour 5: errors 0.20%, burn  2.0x -> -    | CPU 60% -> -
  hour 6: errors 0.06%, burn  0.6x -> -    | CPU 82% -> alert
  error budget used in these 6 hours: 4.8% of the month's

Output টা পড়ো:

  • latency: গড় 113 ms আর p95 99 ms, দুইটাই "ঠিক আছে"। p99 2,000 ms: প্রতি পঞ্চাশ জনে একজন user দুই সেকেন্ড অপেক্ষা করে। শুধু tail এর percentile এটা দেখায়।
  • trace: request এ লেগেছে 420 ms, যার 280 ms গেছে payment এর ভেতরের fraud check এ। Tree ছাড়া তুমি শুধু জানতে "checkout slow"।
  • ঘণ্টা 1, 2 আর 6: CPU alert বাজে, অথচ error 0.05 থেকে 0.08%, budget এর অনেক ভেতরে। কাউকে জাগানোর দরকার ছিল না।
  • ঘণ্টা 3 আর 4: error 1.5 আর 1.6%, burn rate 15x আর 16x। Burn-rate alert page করে; CPU কম (40%, 35%), কারণ fail করা request সস্তা, তাই আসল incident এর সময় CPU alert চুপ থাকে।
  • খরচ হওয়া budget: এই ছয় ঘণ্টায় মাসের error budget এর 4.8% খরচ হয়েছে, বেশিরভাগটাই দুই ঘণ্টায়।
  • কোন language এ কী বদলালো: indent বাড়ার সাথে width কমে এমনভাবে tree print করা। Go আর C++ width টা argument হিসেবে পাঠায় (%-*s), Rust একটা নাম দেওয়া width ব্যবহার করে ({:<w$}), Python format spec এর ভেতরে বসায় ({name:<{w}}), TypeScript padEnd(w) call করে, আর Java format string টা বানিয়ে নেয়। Java র record span তৈরির পর বদলানো যায় না, তাই printSpan একটা update না করে সবচেয়ে slow span টা ফেরত দেয়।

আসল project এ observability

  • OpenTelemetry হলো code থেকে trace, metric আর log বানানোর standard উপায়, এই course এর প্রতিটা language এর SDK সহ। এগুলো পাঠাও Prometheus আর Grafana তে, log এর জন্য Loki বা Elasticsearch এ, trace এর জন্য Tempo বা Jaeger এ, বা একটা hosted service এ (Datadog, Honeycomb, New Relic, Grafana Cloud)।
  • সব জায়গায় context পাঠাও: HTTP আর gRPC header, আর queue র জন্য message header, যাতে async সীমানায় trace ভেঙে না যায়।
  • খরচ নিয়ন্ত্রণ: trace sample করো (error আর slow গুলো রাখো), debug log বাদ দাও বা sample করো, প্রতিটা signal এর retention আলাদা ঠিক করো, আর metric এর cardinality তে চোখ রাখো।
  • Dashboard: প্রতিটা service এর dashboard শুরু করো তার SLO আর error budget দিয়ে, তারপর RED metric, তারপর dependency। Deploy marker যোগ করো, কারণ বেশিরভাগ incident এর প্রথম প্রশ্ন হলো "কী বদলেছে?"।
  • On-call এর স্বাস্থ্য: প্রতিটা page এর runbook থাকবে; হইচই করা alert প্রতি সপ্তাহে পর্যালোচনা করো; প্রতি shift এ কয়টা page হলো গোনো; incident এর পরে জিজ্ঞেস করো "কোন signal আগে জানাতে পারত?"।
  • Synthetic check: তোমার network এর বাইরে থেকে প্রতি মিনিটে login আর checkout করা একটা robot এমন সমস্যা ধরে যেগুলো ভেতরের metric মিস করে, যেমন DNS বা certificate এর failure।

যে design গুলো পরে problem create করে

প্রতিটা case চালিয়ে দেখো

Observability র ভুলটা ধরো

database 20 s এর জন্য ঝাঁকুনি খেল; Kubernetes প্রতিটা pod restart করল
ভাঙে: Liveness শুধু আটকে যাওয়া process ধরবে। Dependency check readiness এ রাখো, নাহলে restart এর ঝড় outage আরো খারাপ করে।

একটু থামো, ভাবো

তোমার SLO হলো 30 দিনে 99.9% request সফল। একটা bug এর কারণে আজ থেকে স্থিরভাবে 0.2% request fail করছে। এক ঘণ্টায় 14.4x burn এ page আর তিন দিনে 1x burn এ ticket থাকলে কোন alert বাজবে, আর কখন? এটা কি ঠিক আচরণ?

উত্তর দেখো

0.1% budget এর বিপরীতে 0.2% error মানে burn rate 2x। এটা 14.4x এর অনেক নিচে, তাই page কখনো বাজে না। এটা 1x এর উপরে, তাই তিন দিনের window তে এটা দেখা গেলেই ticket alert বাজে, স্থিরভাবে পুড়তে থাকলে মোটামুটি এক দিনের মধ্যে। এটাই উদ্দেশ্য: 2x এ মাসের budget প্রায় 15 দিনে শেষ হবে, যেটা গুরুতর, কিন্তু "রাত ৩টায় কাউকে জাগাও" এর মতো গুরুতর না। এই সপ্তাহেই, কাজের সময়ে ঠিক করতে হবে। দ্রুত-burn এর page রাখা থাকে সেই সমস্যার জন্য যেগুলো কয়েক ঘণ্টা বা কয়েক দিনে budget শেষ করে দেবে।

ছোট্ট quiz

1. Log, metric আর trace এর পার্থক্য কী?

উত্তর

Metric হলো সময়ের সাথে একত্র করা সংখ্যা (হার, error, latency)। Log হলো আলাদা আলাদা ঘটনার বিস্তারিত রেকর্ড। Trace সময় দেওয়া span এর একটা tree হিসেবে service জুড়ে একটা request অনুসরণ করে।

2. গড়ের বদলে p99 কেন দেখবে?

উত্তর

গড় slow tail লুকিয়ে রাখে: কয়েকটা খুব slow request তাকে প্রায় নাড়ায়ই না। p99 বলে সবচেয়ে slow 1% কতটা slow, আর বিরক্ত user রা সেটাই অনুভব করে।

3. CPU না দেখে SLO এর burn rate দেখে কেন alert দেবে?

উত্তর

Burn rate কথা দেওয়া reliability র বিপরীতে user এর মুখোমুখি failure মাপে। User ঠিক থাকলেও CPU বেশি হতে পারে, আর তারা কষ্ট পেলেও কম হতে পারে (fail করা request সস্তা)। লক্ষণ দেখে page করা মানে কম মিথ্যা alarm আর কোনো incident মিস না হওয়া।

4. Liveness বনাম readiness: কোনটা কী কাজে?

উত্তর

Liveness আটকে যাওয়া বা নষ্ট process ধরে যাতে restart দেওয়া যায়। Readiness বলে একটা instance এখন traffic পাবে কিনা। Load balancer readiness ব্যবহার করে; liveness অন্য service এর উপর নির্ভর করা উচিত না।

তোমার challenge: tail যখন মোটা হয়

Slow পথটা বদলে 10% request এ করো, 2% এর বদলে (i % 50 == 7 এর জায়গায় i % 10 == 7), আর latency অংশটা আবার চালাও। চালানোর আগে আন্দাজ করো: গড়, p50, p95 আর p99 এর কোনগুলো অনেক বদলাবে?

  • শুধু ওই শর্তটা বদলাও।
  • পুরনো আর নতুন latency line মেলাও।

তুমি পেরেছো যখন latency line টা হবে average 267 ms, p50 78 ms, p95 2000 ms, p99 2000 ms, max 2000 ms। এখন p95 ও সমস্যা দেখাচ্ছে, আর গড় দ্বিগুণের বেশি, অথচ মধ্যমা প্রায় নড়েই না। তোমার SLO যদি হতো "p95 300 ms এর নিচে", 2% এর version পাস করত আর 10% এর version fail করত: কোন percentile এর কথা দিচ্ছো সেটা একটা product এর সিদ্ধান্ত।

এক লাইনে

System কে নিজেকে বোঝাতে দাও: হার, error আর latency histogram হিসেবে metric দাও (আর গড় না, percentile পড়ো), trace ID সহ structured log লেখো, প্রতিটা service আর queue জুড়ে request trace করো, page করো শুধু SLO burn rate এ যেটা মানে user কষ্ট পাচ্ছে, প্রতিটা alert কে একজন owner আর একটা runbook দাও, আর liveness আর readiness check হালকা আর সৎ রাখো।

Station stamp

Chapter শেষ করো

পড়া শেষ হলে Complete চাপো, progress save হবে। XP শুধু Pro তে — Pro থাকলে এই chapter এ +10 XP পেতে।

Pro নিয়ে XP পাও →