17 · 📈 Performance आणि monitoring — काउंटरवरचे स्टॉपवॉच
भाग 4 — production APIs. धडे 01–16 ने काउंटर बांधला आणि त्याभोवतीचे सगळे नकाशात मांडले. भाग 4 तो खऱ्या traffic खाली चालवतो: production जसे मोजते तसे मोजा, आणि टीम्स खरोखर वापरतात त्या साधनांनी त्यावर लक्ष ठेवा.
📦 या ब्रँचमध्ये काय आहे
धडे 01–17. काउंटर आता स्वतःलाच मोजतो:
- api/school_api.py — प्रत्येक response ची वेळ मोजली जाते आणि route नुसार नोंदवली जाते
(
/v1/students/{id}, कधीच मूळ URL नाही);GET /metricsत्या Prometheus format मध्ये देतो;METRICS_EMF=1प्रत्येक request साठी एक CloudWatch Embedded Metric Format ओळ छापतो;DOGSTATSD=127.0.0.1:8125प्रत्येक request साठी एक Datadog DogStatsD packet पाठवतो. एक नवीन read,GET /v1/reports/grades, याला नक्कल केलेला हळू मार्ग आहे — 15 पैकी 1 call "cache चुकवतो" आणि ~150 ms घेतो — म्हणजे शोधायला एक tail आहे. - api/perf.py — मोकळ्या port वर काउंटर सुरू करतो, एकाच वेळी 8
callers सह 400 requests पाठवतो, आणि एकूण व प्रत्येक route साठी p25 · p50 · p75 · p90 · p95 · p99 · max · mean छापतो,
एक histogram,
/metricsकाय सांगतो ते, Datadog agent ला मिळतील ते DogStatsD packets, एक CloudWatch EMF ओळ, आणि तिन्ही साधनांसाठी लिहिलेला तोच p95 alarm. - api/perf-output.txt — आमच्या laptop वरचा एक run (तुमचे आकडे वेगळे असतील; आकार तोच राहील)
- 🗺️ चित्रात: https://school-edh.pages.dev/api/lesson-diagrams.html#l17 — प्रत्येक percentile खूण केलेली 104 requests ची क्रमाने लावलेली रांग, आणि requests स्वतः हळू करून पाहण्याचा एक lab
🧒 5 वर्षांच्या मुलाला समजावल्यासारखे
मुख्याध्यापिका काउंटरवर एक स्टॉपवॉच ठेवतात आणि प्रत्येक पाहुण्याने किती वेळ वाट पाहिली ते लिहून ठेवतात. दिवसाच्या शेवटी त्या वेळा सर्वात कमी ते सर्वात जास्त अशा रांगेत लावतात.
- रांगेच्या अगदी मध्यभागी असलेल्या पाहुण्याने p50 (median) इतकी वाट पाहिली — नेहमीची भेट.
- दर 100 पैकी कमी बाजूकडून 95 व्या पाहुण्यापाशी उभे राहा: ती वेळ म्हणजे p95. 100 पैकी फक्त 5 जणांनी यापेक्षा जास्त वाट पाहिली.
- p99: 100 पैकी फक्त 1 जणाने जास्त वाट पाहिली — तक्रार लिहिणारा दुर्दैवी पाहुणा.
- p25 आणि p75 या पाव भागाच्या खुणा आहेत; p90 म्हणजे 10 पैकी 1.
सरासरी सगळे बेरीज करून भागाकार करते — आणि ती दुर्दैवी पाहुण्यांना लपवते. आमच्या run मध्ये report route ची सरासरी 18.9 ms होती, तर p95 होता 135.8 ms: बहुतेक पाहुण्यांनी ~10 ms वाट पाहिली, पण सुमारे 15 पैकी 1 जणाने ~150 ms. सरासरी म्हणाली "ठीक आहे". पाहुणे तसे म्हणाले नाहीत.
🗺️ आकृती
flowchart LR
c["🧑💻 callers"] --> api["🏢 counter<br/>times every request<br/>per route"]
api -->|"GET /metrics (pull)"| prom["📊 Prometheus → Grafana"]
api -->|"DogStatsD over UDP (push)"| dd["🐶 Datadog agent → Datadog"]
api -->|"EMF log line (push)"| cw["☁️ CloudWatch Logs → metric"]
prom --> al["🔔 one alarm: p95 > 100 ms for 15 min"]
dd --> al
cw --> al
❓ काय
- Latency — request पोहोचल्यापासून response बाहेर पडेपर्यंतचा वेळ (server बाजू), किंवा पाठवल्यापासून मिळेपर्यंतचा (client बाजू, ज्यात network आणि caller ची स्वतःची रांग जोडली जाते).
- Percentiles — वेळा क्रमाने लावा; pN म्हणजे N% requests ज्या किमतीवर किंवा त्याखाली होत्या ती किंमत.
perf.pyजवळच्या दोन ranks मध्ये linear interpolation वापरतो (numpy चा default, ExcelPERCENTILE.INC). - प्रत्येक route साठी — प्रत्येक method + path template साठी एक metric. सगळे routes एकत्र केल्यावर आमच्या run ने p95 = 10.8 ms सांगितले; फक्त report route 135.8 ms होता. जलद routes हळू route ला बुडवतात.
- RED — प्रत्येक route साठी: Rate (requests/s), Errors (5xx %), Duration (p50/p95/p99).
- Histograms, सरासरी नव्हे — अनेक servers मधल्या percentiles ची सरासरी काढता येत नाही. Prometheus
bucket counts ठेवतो आणि अंदाज काढतो (
histogram_quantile); Datadog distributions आणि CloudWatch percentile statistics त्या मध्यवर्ती ठिकाणी मोजतात. - SLO — ज्यावर alert लावता ते वचन, उदा. "15 मिनिटांत report route चा p95 100 ms च्या खाली".
🤔 का
कारण लोकांना tail जाणवते, सरासरी नव्हे. 93 callers साठी जलद आणि 7 साठी हळू असलेला route त्या 7 जणांना बिघडलेला वाटतो — आणि तेच सोडून जातात. प्रत्येक route साठी percentiles मोजणे हाच त्यांनी तक्रार लिहिण्याआधी त्यांना शोधण्याचा मार्ग आहे.
🔧 कसे (या repo मध्ये) — आकडे प्रवास करण्याचे तीन मार्ग
| साधन | आकडा कसा मिळवते | perf.py काय दाखवतो |
|---|---|---|
| 📊 Prometheus + Grafana | pull: दर ~15 s ने GET /metrics scrape करते |
school_api_request_duration_seconds_bucket{route="/v1/reports/grades",le="0.25"} 104 |
| 🐶 Datadog | push: app UDP वरून local agent ला DogStatsD packets पाठवते | school_api.request.duration:10.16|d|#method:GET,route:/v1/reports/grades,status:200 |
| ☁️ CloudWatch | push: प्रत्येक request साठी एक Embedded Metric Format JSON log ओळ; CloudWatch तिचे metric बनवते | {"_aws": {… "Metrics": [{"Name": "Latency", "Unit": "Milliseconds"}]}, "Route": "GET /v1/reports/grades", "Latency": 10.4} |
तोच alarm — report route चा p95 15 मिनिटे 100 ms च्या वर — प्रत्येक साधनात:
CloudWatch aws cloudwatch put-metric-alarm --alarm-name school-api-report-p95 --namespace SchoolAPI \
--metric-name Latency --dimensions Name=Route,Value='GET /v1/reports/grades' --extended-statistic p95 \
--period 300 --evaluation-periods 3 --threshold 100 --comparison-operator GreaterThanThreshold
Datadog percentile(last_15m):p95:school_api.request.duration{route:/v1/reports/grades} > 100
Prometheus histogram_quantile(0.95, sum by (le) (rate(school_api_request_duration_seconds_bucket{route="/v1/reports/grades"}[5m]))) > 0.1
🧪 करून पाहा
python3 api/perf.py # 400 requests, 8 callers
python3 api/perf.py 2000 32 # more traffic, more callers — watch p99 move
python3 api/school_api.py & # then, in another terminal:
curl -s localhost:8080/v1/reports/grades; curl -s localhost:8080/metrics | grep reports
METRICS_EMF=1 python3 api/school_api.py 8081 # every request prints a CloudWatch EMF line on stdout
✅ तपासा — तुम्हाला काय दिसायला हवे
प्रत्येक route चा तक्ता GET /v1/reports/grades ला सर्वात वर ठेवतो, p90 सुमारे 11 ms आणि p95/p99
सुमारे 136–156 ms सह, तर student routes सुमारे 1 ms जवळ राहतात. सगळ्या routes चा p95 ~11 ms असतो आणि
फक्त सगळ्या routes चा p99 ~150 ms पर्यंत उडी मारतो. histogram_quantile caller च्या p95 जवळ येतो पण
नेमका त्यावर नाही — buckets ढोबळ असतात. सुमारे 400 DogStatsD packets पकडले जातात, प्रत्येक request साठी एक.
🏁 तुम्ही आत्ताच काय सिद्ध केले
तुम्ही production जसे मोजते तसे API मोजू शकता — प्रत्येक route साठी percentiles — सरासरीने लपवलेला हळू route शोधू शकता, आणि CloudWatch, Datadog आणि Prometheus मध्ये तोच SLO alarm लिहू शकता.
⚠️ नेहमीच्या चुका
- Mean वर alert लावणे — tail जळत असताना ते शांत राहते.
- संपूर्ण API साठी एकच latency metric — हळू route जलद routes मध्ये लपतो.
- User ids किंवा मूळ URLs (
/v1/students/7) असलेली labels — cardinality फुगते आणि bill सुद्धा; route template वापरा. - अनेक servers मधल्या percentiles ची सरासरी ("प्रत्येक server च्या p95 चा mean") — गणितदृष्ट्या चूक; histograms किंवा distributions एकत्र करा.
- तुमच्या laptop वरून localhost वर load-testing करून त्या आकड्याला "क्षमता" म्हणणे (धडा 16).
- मिनिटाला 20 requests वर p99 — एकच request तो हलवते; जास्त लांब कालखंड किंवा p95 पाहा.
🏭 प्रत्यक्ष वापरात हे का महत्त्वाचे: प्रत्येक on-call टीमकडे प्रत्येक route च्या RED metrics चा dashboard असतो आणि percentiles मध्ये लिहिलेल्या SLOs वर alerts असतात — Prometheus/Grafana, Datadog किंवा CloudWatch मध्ये (AWS शाळेचा धडा 18 आणि Kubernetes शाळेचा धडा 26 पाहा).
⏭️ पुढे
काउंटर बांधला, नकाशात मांडला आणि मोजला. अभ्यास आराखड्यात या धड्यासाठी आठवडा 6 आहे; quiz मध्ये भाग 4 आहे.